Cw 473 exchange refactoring (#1126)

* CW-473 Remove deprecated Exchanges

* CW-473 Clean up Exchange Code

* CW-473 Add Decimals to Crypto Enums

* CW-473 Fix minor merge error

* CW-473 Fix minor merge error

* CW-473 Fix FAQ Locals

* CW-473 Apply requested changes

* CW-473 Show Error if Exchange Provider is not supported anymore

* CW-473 Implement Requested Changes
This commit is contained in:
Konstantin Ullrich 2023-10-25 22:58:25 +02:00 committed by GitHub
parent db7f025b71
commit cef3029f6f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
74 changed files with 941 additions and 1783 deletions

View file

@ -1,7 +1,7 @@
[ [
{ {
"question" : "Was ist der Unterschied zwischen verfügbarem Guthaben und vollständigem Guthaben?", "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?", "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" "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\"?", "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 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" "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?", "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" "answer" : "Es gibt keine Grenzen! Sie können so viele Brieftaschen erstellen, wie Sie möchten.\n"
}, },
{ {
"question" : "Wie kann ich meine Brieftasche wiederherstellen?", "question" : "Wie kann ich mein Wallet 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" "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?", "question" : "Was kann ich tun, wenn ich meinen Seed 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" "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?", "question" : "Sammeln Sie Informationen zu meinem Wallet?",
"answer" : "Cake Wallet sammelt oder zeichnet keine Informationen über Ihre Brieftasche auf. Ihre Privatsphäre ist uns wichtig.\n" "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?", "question" : "Kann ich eine Transaktion stornieren?",
@ -37,7 +37,7 @@
}, },
{ {
"question" : "Was sind Subadressen und wie verwende ich sie?", "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?", "question" : "Was ist eine Transaktions-ID?",
@ -48,8 +48,8 @@
"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" "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?", "question" : "Ich habe in der App keine Coins 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" "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?", "question" : "Wie kontaktiere ich den Cake Wallet-Support?",

View file

@ -49,7 +49,7 @@
}, },
{ {
"question" : "I didn't receive my coins from the exchange in the app. What can I do?", "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?", "question" : "How do I contact Cake Wallet support?",

View file

@ -49,7 +49,7 @@
}, },
{ {
"question" : "No recibí mis monedas del intercambio en la aplicación. ¿Que puedo hacer?", "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?", "question" : "¿Cómo contacto al soporte de Cake Wallet?",

View file

@ -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 ?", "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 ?", "question" : "Comment puis-je contacter le support de Cake Wallet ?",

View file

@ -49,7 +49,7 @@
}, },
{ {
"question" : "मुझे ऐप में एक्सचेंज से मेरे सिक्के नहीं मिले। मैं क्या कर सकता हूँ?", "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" : "मैं केक वॉलेट से कैसे संपर्क करूं?", "question" : "मैं केक वॉलेट से कैसे संपर्क करूं?",

View file

@ -49,7 +49,7 @@
}, },
{ {
"question" : "アプリの取引所からコインを受け取りませんでした。 私に何ができる?", "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サポートに連絡するにはどうすればよいですか", "question" : "Cake Walletサポートに連絡するにはどうすればよいですか",

View file

@ -49,7 +49,7 @@
}, },
{ {
"question" : "앱의 거래소에서 동전을받지 못했습니다. 내가 무엇을 할 수 있을지?", "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 지원팀에 연락하려면 어떻게해야합니까?", "question" : "Cake Wallet 지원팀에 연락하려면 어떻게해야합니까?",

View file

@ -49,7 +49,7 @@
}, },
{ {
"question" : "Ik heb mijn munten niet ontvangen van de beurs in de app. Wat kan ik doen?", "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?", "question" : "Hoe neem ik contact op met Cake Wallet-ondersteuning?",

View file

@ -49,7 +49,7 @@
}, },
{ {
"question" : "Nie otrzymałem moich monet z wymiany w aplikacji. Co mogę zrobić?", "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?", "question" : "Jak skontaktować się z obsługą Cake Wallet?",

View file

@ -49,7 +49,7 @@
}, },
{ {
"question" : "Não recebi minhas moedas da troca no aplicativo. O que eu posso fazer?", "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?", "question" : "Como entro em contato com o suporte da Cake Wallet?",

View file

@ -49,7 +49,7 @@
}, },
{ {
"question" : "Я не получил свои монеты после обмена в приложении. Что я могу сделать?", "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?", "question" : "Как мне связаться со службой поддержки Cake Wallet?",

View file

@ -49,7 +49,7 @@
}, },
{ {
"question" : "Я не отримав свої монети після обміну в додатку. Що я можу зробити?", "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?", "question" : "Як мені зв'язатися зі службою підтримки Cake Wallet?",

View file

@ -49,7 +49,7 @@
}, },
{ {
"question" : "我没有从应用程序中的交易所收到硬币。 我能做什么?", "question" : "我没有从应用程序中的交易所收到硬币。 我能做什么?",
"answer" : "如果您对交易所有疑问,最好的选择是与交易所本身联系。 我们与XMR.TOMorph和ChangeNow合作因此最好的选择是访问http//xmr.to、http//changenow.io或http://morphtoken.com并与他们的支持部门联系。\n" "answer" : "如果您对交易所有问题最好的选择是与交易所本身联系。我们与ChangeNowSimplesWapSideShift和Trocador合作。因此最好的选择是访问https://changenow.iohttps://simpleswap.io/https://sideshift.ai/https//trocador.app/并联系他们的支持。\n"
}, },
{ {
"question" : "如何联系蛋糕钱包支持?", "question" : "如何联系蛋糕钱包支持?",

View file

@ -6,6 +6,7 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
String title = '', String title = '',
int raw = -1, int raw = -1,
required this.name, required this.name,
required this.decimals,
this.fullName, this.fullName,
this.iconPath, this.iconPath,
this.tag}) this.tag})
@ -15,6 +16,7 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
final String? tag; final String? tag;
final String? fullName; final String? fullName;
final String? iconPath; final String? iconPath;
final int decimals;
static const all = [ static const all = [
CryptoCurrency.xmr, 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 // 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 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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', raw: 10, fullName: 'Nano', name: 'xno', iconPath: 'assets/images/nano_icon.png'); 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'); 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'); 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'); 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'); 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'); 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'); 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 xag = CryptoCurrency(title: 'XAG', tag: 'XHV', raw: 17, name: 'xag', decimals: 12);
static const xau = CryptoCurrency(title: 'XAU', tag: 'XHV', raw: 18, name: 'xau'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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 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', raw: 31, name: 'avaxc', iconPath: 'assets/images/avaxc_icon.png'); 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'); 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'); 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'); 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'); 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'); 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', ); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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'); 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', raw: 86, name: 'banano', iconPath: 'assets/images/nano_icon.png'); 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 = 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}) { static CryptoCurrency deserialize({required int raw}) {
if (CryptoCurrency._rawCurrencyMap[raw] == null) { if (CryptoCurrency._rawCurrencyMap[raw] == null) {
final s = 'Unexpected token: $raw for CryptoCurrency deserialize'; final s = 'Unexpected token: $raw for CryptoCurrency deserialize';
throw ArgumentError.value(raw, 'raw', s); throw ArgumentError.value(raw, 'raw', s);
@ -232,7 +233,6 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
} }
static CryptoCurrency fromString(String name) { static CryptoCurrency fromString(String name) {
if (CryptoCurrency._nameCurrencyMap[name.toLowerCase()] == null) { if (CryptoCurrency._nameCurrencyMap[name.toLowerCase()] == null) {
final s = 'Unexpected token: $name for CryptoCurrency fromString'; final s = 'Unexpected token: $name for CryptoCurrency fromString';
throw ArgumentError.value(name, 'name', s); throw ArgumentError.value(name, 'name', s);
@ -241,7 +241,6 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
} }
static CryptoCurrency fromFullName(String name) { static CryptoCurrency fromFullName(String name) {
if (CryptoCurrency._fullNameCurrencyMap[name.toLowerCase()] == null) { if (CryptoCurrency._fullNameCurrencyMap[name.toLowerCase()] == null) {
final s = 'Unexpected token: $name for CryptoCurrency fromFullName'; final s = 'Unexpected token: $name for CryptoCurrency fromFullName';
throw ArgumentError.value(name, 'Fullname', s); throw ArgumentError.value(name, 'Fullname', s);
@ -249,7 +248,6 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
return CryptoCurrency._fullNameCurrencyMap[name.toLowerCase()]!; return CryptoCurrency._fullNameCurrencyMap[name.toLowerCase()]!;
} }
@override @override
String toString() => title; String toString() => title;
} }

View file

@ -37,6 +37,7 @@ class Erc20Token extends CryptoCurrency with HiveObjectMixin {
fullName: name, fullName: name,
tag: "ETH", tag: "ETH",
iconPath: iconPath, iconPath: iconPath,
decimals: decimal
); );
Erc20Token.copyWith(Erc20Token other, String? icon) Erc20Token.copyWith(Erc20Token other, String? icon)
@ -52,6 +53,7 @@ class Erc20Token extends CryptoCurrency with HiveObjectMixin {
fullName: other.name, fullName: other.name,
tag: "ETH", tag: "ETH",
iconPath: icon, iconPath: icon,
decimals: other.decimal
); );
static const typeId = ERC20_TOKEN_TYPE_ID; static const typeId = ERC20_TOKEN_TYPE_ID;

View file

@ -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;
}

View file

@ -1,10 +1,7 @@
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
class ExchangePair { class ExchangePair {
ExchangePair({ ExchangePair({required this.from, required this.to, this.reverse = true});
required this.from,
required this.to,
this.reverse = true});
final CryptoCurrency from; final CryptoCurrency from;
final CryptoCurrency to; final CryptoCurrency to;

View file

@ -14,16 +14,12 @@ class ExchangeProviderDescription extends EnumerableItem<int> with Serializable<
ExchangeProviderDescription(title: 'ChangeNOW', raw: 1, image: 'assets/images/changenow.png'); ExchangeProviderDescription(title: 'ChangeNOW', raw: 1, image: 'assets/images/changenow.png');
static const morphToken = static const morphToken =
ExchangeProviderDescription(title: 'MorphToken', raw: 2, image: 'assets/images/morph.png'); ExchangeProviderDescription(title: 'MorphToken', raw: 2, image: 'assets/images/morph.png');
static const sideShift = static const sideShift =
ExchangeProviderDescription(title: 'SideShift', raw: 3, image: 'assets/images/sideshift.png'); ExchangeProviderDescription(title: 'SideShift', raw: 3, image: 'assets/images/sideshift.png');
static const simpleSwap = ExchangeProviderDescription( static const simpleSwap = ExchangeProviderDescription(
title: 'SimpleSwap', raw: 4, image: 'assets/images/simpleSwap.png'); title: 'SimpleSwap', raw: 4, image: 'assets/images/simpleSwap.png');
static const trocador = static const trocador =
ExchangeProviderDescription(title: 'Trocador', raw: 5, image: 'assets/images/trocador.png'); ExchangeProviderDescription(title: 'Trocador', raw: 5, image: 'assets/images/trocador.png');
static const exolix = static const exolix =
ExchangeProviderDescription(title: 'Exolix', raw: 6, image: 'assets/images/exolix.png'); ExchangeProviderDescription(title: 'Exolix', raw: 6, image: 'assets/images/exolix.png');

View file

@ -1,4 +1,3 @@
import 'package:flutter/foundation.dart';
import 'package:cake_wallet/exchange/trade.dart'; import 'package:cake_wallet/exchange/trade.dart';
abstract class ExchangeTradeState {} abstract class ExchangeTradeState {}

View file

@ -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;
}

View file

@ -1,4 +1,3 @@
import 'package:flutter/foundation.dart';
import 'package:cake_wallet/exchange/limits.dart'; import 'package:cake_wallet/exchange/limits.dart';
abstract class LimitsState {} abstract class LimitsState {}

View file

@ -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;
}
}
}

View file

@ -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;
}

View file

@ -1,33 +1,32 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; 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/store/settings_store.dart';
import 'package:cake_wallet/utils/device_info.dart'; import 'package:cake_wallet/utils/device_info.dart';
import 'package:cake_wallet/utils/distribution_info.dart'; import 'package:cake_wallet/utils/distribution_info.dart';
import 'package:cake_wallet/wallet_type_utils.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:cw_core/crypto_currency.dart';
import 'package:cake_wallet/exchange/exchange_pair.dart'; import 'package:http/http.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';
class ChangeNowExchangeProvider extends ExchangeProvider { class ChangeNowExchangeProvider extends ExchangeProvider {
ChangeNowExchangeProvider({required this.settingsStore}) ChangeNowExchangeProvider({required SettingsStore settingsStore})
: _lastUsedRateId = '', : _settingsStore = settingsStore,
super( _lastUsedRateId = '',
pairList: CryptoCurrency.all super(pairList: supportedPairs(_notSupported));
.where((i) => i != CryptoCurrency.xhv)
.map((i) => CryptoCurrency.all static const List<CryptoCurrency> _notSupported = [
.where((i) => i != CryptoCurrency.xhv) CryptoCurrency.zaddr,
.map((k) => ExchangePair(from: i, to: k, reverse: true))) CryptoCurrency.xhv,
.expand((i) => i) ];
.toList());
static final apiKey = static final apiKey =
DeviceInfo.instance.isMobile ? secrets.changeNowApiKey : secrets.changeNowApiKeyDesktop; DeviceInfo.instance.isMobile ? secrets.changeNowApiKey : secrets.changeNowApiKeyDesktop;
@ -38,6 +37,9 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
static const rangePath = '/v2/exchange/range'; static const rangePath = '/v2/exchange/range';
static const apiHeaderKey = 'x-changenow-api-key'; static const apiHeaderKey = 'x-changenow-api-key';
final SettingsStore _settingsStore;
String _lastUsedRateId;
@override @override
String get title => 'ChangeNOW'; String get title => 'ChangeNOW';
@ -56,25 +58,18 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
@override @override
Future<bool> checkIsAvailable() async => true; Future<bool> checkIsAvailable() async => true;
final SettingsStore settingsStore;
String _lastUsedRateId;
static String getFlow(bool isFixedRate) => isFixedRate ? 'fixed-rate' : 'standard';
@override @override
Future<Limits> fetchLimits( Future<Limits> fetchLimits(
{required CryptoCurrency from, {required CryptoCurrency from,
required CryptoCurrency to, required CryptoCurrency to,
required bool isFixedRateMode}) async { required bool isFixedRateMode}) async {
final headers = {apiHeaderKey: apiKey}; final headers = {apiHeaderKey: apiKey};
final flow = getFlow(isFixedRateMode);
final params = <String, String>{ final params = <String, String>{
'fromCurrency': _normalizeCurrency(from), 'fromCurrency': _normalizeCurrency(from),
'toCurrency': _normalizeCurrency(to), 'toCurrency': _normalizeCurrency(to),
'fromNetwork': _networkFor(from), 'fromNetwork': _networkFor(from),
'toNetwork': _networkFor(to), 'toNetwork': _networkFor(to),
'flow': flow 'flow': _getFlow(isFixedRateMode)
}; };
final uri = Uri.https(apiAuthority, rangePath, params); final uri = Uri.https(apiAuthority, rangePath, params);
final response = await get(uri, headers: headers); final response = await get(uri, headers: headers);
@ -86,20 +81,61 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
throw Exception('${error}\n$message'); throw Exception('${error}\n$message');
} }
if (response.statusCode != 200) { if (response.statusCode != 200)
throw Exception('Unexpected http status: ${response.statusCode}'); throw Exception('Unexpected http status: ${response.statusCode}');
}
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
return Limits( return Limits(
min: responseJSON['minAmount'] as double?, max: responseJSON['maxAmount'] as double?); 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 @override
Future<Trade> createTrade({required TradeRequest request, required bool isFixedRateMode}) async { Future<Trade> createTrade({required TradeRequest request, required bool isFixedRateMode}) async {
final _request = request as ChangeNowRequest;
final distributionPath = await DistributionInfo.instance.getDistributionPath(); final distributionPath = await DistributionInfo.instance.getDistributionPath();
final formattedAppVersion = int.tryParse(settingsStore.appVersion.replaceAll('.', '')) ?? 0; final formattedAppVersion = int.tryParse(_settingsStore.appVersion.replaceAll('.', '')) ?? 0;
final payload = { final payload = {
'app': isMoneroOnly ? 'monerocom' : 'cakewallet', 'app': isMoneroOnly ? 'monerocom' : 'cakewallet',
'device': Platform.operatingSystem, 'device': Platform.operatingSystem,
@ -107,19 +143,18 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
'version': formattedAppVersion 'version': formattedAppVersion
}; };
final headers = {apiHeaderKey: apiKey, 'Content-Type': 'application/json'}; final headers = {apiHeaderKey: apiKey, 'Content-Type': 'application/json'};
final flow = getFlow(isFixedRateMode);
final type = isFixedRateMode ? 'reverse' : 'direct'; final type = isFixedRateMode ? 'reverse' : 'direct';
final body = <String, dynamic>{ final body = <String, dynamic>{
'fromCurrency': _normalizeCurrency(_request.from), 'fromCurrency': _normalizeCurrency(request.fromCurrency),
'toCurrency': _normalizeCurrency(_request.to), 'toCurrency': _normalizeCurrency(request.toCurrency),
'fromNetwork': _networkFor(_request.from), 'fromNetwork': _networkFor(request.fromCurrency),
'toNetwork': _networkFor(_request.to), 'toNetwork': _networkFor(request.toCurrency),
if (!isFixedRateMode) 'fromAmount': _request.fromAmount, if (!isFixedRateMode) 'fromAmount': request.fromAmount,
if (isFixedRateMode) 'toAmount': _request.toAmount, if (isFixedRateMode) 'toAmount': request.toAmount,
'address': _request.address, 'address': request.toAddress,
'flow': flow, 'flow': _getFlow(isFixedRateMode),
'type': type, 'type': type,
'refundAddress': _request.refundAddress, 'refundAddress': request.refundAddress,
'payload': payload, '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 // 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 // we have the latest rate id with the given inputs before creating the trade
await fetchRate( await fetchRate(
from: _request.from, from: request.fromCurrency,
to: _request.to, to: request.toCurrency,
amount: double.tryParse(_request.toAmount) ?? 0, amount: double.tryParse(request.toAmount) ?? 0,
isFixedRateMode: true, isFixedRateMode: true,
isReceiveAmount: true, isReceiveAmount: true,
); );
@ -146,9 +181,8 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
throw Exception('${error}\n$message'); throw Exception('${error}\n$message');
} }
if (response.statusCode != 200) { if (response.statusCode != 200)
throw Exception('Unexpected http status: ${response.statusCode}'); throw Exception('Unexpected http status: ${response.statusCode}');
}
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final id = responseJSON['id'] as String; final id = responseJSON['id'] as String;
@ -159,14 +193,14 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
return Trade( return Trade(
id: id, id: id,
from: _request.from, from: request.fromCurrency,
to: _request.to, to: request.toCurrency,
provider: description, provider: description,
inputAddress: inputAddress, inputAddress: inputAddress,
refundAddress: refundAddress, refundAddress: refundAddress,
extraId: extraId, extraId: extraId,
createdAt: DateTime.now(), createdAt: DateTime.now(),
amount: responseJSON['fromAmount']?.toString() ?? _request.fromAmount, amount: responseJSON['fromAmount']?.toString() ?? request.fromAmount,
state: TradeState.created, state: TradeState.created,
payoutAddress: payoutAddress); payoutAddress: payoutAddress);
} }
@ -178,9 +212,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
final uri = Uri.https(apiAuthority, findTradeByIdPath, params); final uri = Uri.https(apiAuthority, findTradeByIdPath, params);
final response = await get(uri, headers: headers); final response = await get(uri, headers: headers);
if (response.statusCode == 404) { if (response.statusCode == 404) throw TradeNotFoundException(id, provider: description);
throw TradeNotFoundException(id, provider: description);
}
if (response.statusCode == 400) { if (response.statusCode == 400) {
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
@ -189,9 +221,8 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
throw TradeNotFoundException(id, provider: description, description: error); throw TradeNotFoundException(id, provider: description, description: error);
} }
if (response.statusCode != 200) { if (response.statusCode != 200)
throw Exception('Unexpected http status: ${response.statusCode}'); throw Exception('Unexpected http status: ${response.statusCode}');
}
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final fromCurrency = responseJSON['fromCurrency'] as String; final fromCurrency = responseJSON['fromCurrency'] as String;
@ -222,54 +253,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
payoutAddress: payoutAddress); payoutAddress: payoutAddress);
} }
@override String _getFlow(bool isFixedRate) => isFixedRate ? 'fixed-rate' : 'standard';
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 _networkFor(CryptoCurrency currency) { String _networkFor(CryptoCurrency currency) {
switch (currency) { switch (currency) {

View file

@ -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_pair.dart';
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
import 'package:cake_wallet/exchange/limits.dart'; import 'package:cake_wallet/exchange/limits.dart';
import 'package:cake_wallet/exchange/trade.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 { abstract class ExchangeProvider {
ExchangeProvider({required this.pairList}); ExchangeProvider({required this.pairList});
String get title; String get title;
List<ExchangePair> pairList; List<ExchangePair> pairList;
ExchangeProviderDescription get description; ExchangeProviderDescription get description;
bool get isAvailable; bool get isAvailable;
bool get isEnabled; bool get isEnabled;
bool get supportsFixedRate; bool get supportsFixedRate;
bool get supportsOnionAddress => false; bool get supportsOnionAddress => false;
@override @override
String toString() => title; String toString() => title;
Future<Limits> fetchLimits( Future<Limits> fetchLimits(
{required CryptoCurrency from, {required CryptoCurrency from, required CryptoCurrency to, required bool isFixedRateMode});
required CryptoCurrency to,
required bool isFixedRateMode}); Future<Trade> createTrade({required TradeRequest request, required bool isFixedRateMode});
Future<Trade> createTrade({
required TradeRequest request,
required bool isFixedRateMode});
Future<Trade> findTradeById({required String id}); Future<Trade> findTradeById({required String id});
Future<double> fetchRate({
required CryptoCurrency from, Future<double> fetchRate(
{required CryptoCurrency from,
required CryptoCurrency to, required CryptoCurrency to,
required double amount, required double amount,
required bool isFixedRateMode, required bool isFixedRateMode,
required bool isReceiveAmount}); required bool isReceiveAmount});
Future<bool> checkIsAvailable(); Future<bool> checkIsAvailable();
} }

View file

@ -1,19 +1,19 @@
import 'dart:convert'; 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:cake_wallet/.secrets.g.dart' as secrets;
import 'package:cw_core/crypto_currency.dart'; import 'package:cake_wallet/exchange/exchange_provider_description.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/limits.dart';
import 'package:cake_wallet/exchange/provider/exchange_provider.dart';
import 'package:cake_wallet/exchange/trade.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_request.dart';
import 'package:cake_wallet/exchange/trade_state.dart'; import 'package:cake_wallet/exchange/trade_state.dart';
import 'package:cake_wallet/exchange/exolix/exolix_request.dart'; import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
import 'package:cake_wallet/exchange/exchange_provider_description.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:http/http.dart';
class ExolixExchangeProvider extends ExchangeProvider { class ExolixExchangeProvider extends ExchangeProvider {
ExolixExchangeProvider() : super(pairList: _supportedPairs()); ExolixExchangeProvider() : super(pairList: supportedPairs(_notSupported));
static final apiKey = secrets.exolixApiKey; static final apiKey = secrets.exolixApiKey;
static const apiBaseUrl = 'exolix.com'; static const apiBaseUrl = 'exolix.com';
@ -40,16 +40,6 @@ class ExolixExchangeProvider extends ExchangeProvider {
CryptoCurrency.weth, 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 @override
String get title => 'Exolix'; String get title => 'Exolix';
@ -68,15 +58,13 @@ class ExolixExchangeProvider extends ExchangeProvider {
@override @override
Future<bool> checkIsAvailable() async => true; Future<bool> checkIsAvailable() async => true;
static String getRateType(bool isFixedRate) => isFixedRate ? 'fixed' : 'float';
@override @override
Future<Limits> fetchLimits( Future<Limits> fetchLimits(
{required CryptoCurrency from, {required CryptoCurrency from,
required CryptoCurrency to, required CryptoCurrency to,
required bool isFixedRateMode}) async { required bool isFixedRateMode}) async {
final params = <String, String>{ final params = <String, String>{
'rateType': getRateType(isFixedRateMode), 'rateType': _getRateType(isFixedRateMode),
'amount': '1', 'amount': '1',
}; };
if (isFixedRateMode) { if (isFixedRateMode) {
@ -93,36 +81,72 @@ class ExolixExchangeProvider extends ExchangeProvider {
final uri = Uri.https(apiBaseUrl, ratePath, params); final uri = Uri.https(apiBaseUrl, ratePath, params);
final response = await get(uri); final response = await get(uri);
if (response.statusCode != 200) { if (response.statusCode != 200)
throw Exception('Unexpected http status: ${response.statusCode}'); throw Exception('Unexpected http status: ${response.statusCode}');
}
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
return Limits(min: responseJSON['minAmount'] as double?); return Limits(min: responseJSON['minAmount'] as double?);
} }
@override @override
Future<Trade> createTrade({required TradeRequest request, required bool isFixedRateMode}) async { Future<double> fetchRate(
final _request = request as ExolixRequest; {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 = {'Content-Type': 'application/json'}; final params = {
final body = <String, dynamic>{ 'coinFrom': _normalizeCurrency(from),
'coinFrom': _normalizeCurrency(_request.from), 'coinTo': _normalizeCurrency(to),
'coinTo': _normalizeCurrency(_request.to), 'networkFrom': _networkFor(from),
'networkFrom': _networkFor(_request.from), 'networkTo': _networkFor(to),
'networkTo': _networkFor(_request.to), 'rateType': _getRateType(isFixedRateMode),
'withdrawalAddress': _request.address,
'refundAddress': _request.refundAddress,
'rateType': getRateType(isFixedRateMode),
'apiToken': apiKey, 'apiToken': apiKey,
}; };
if (isFixedRateMode) { if (isReceiveAmount)
body['withdrawalAmount'] = _request.toAmount; params['withdrawalAmount'] = amount.toString();
} else { else
body['amount'] = _request.fromAmount; 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 = {
'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;
final uri = Uri.https(apiBaseUrl, transactionsPath); final uri = Uri.https(apiBaseUrl, transactionsPath);
final response = await post(uri, headers: headers, body: json.encode(body)); final response = await post(uri, headers: headers, body: json.encode(body));
@ -133,9 +157,8 @@ class ExolixExchangeProvider extends ExchangeProvider {
throw Exception(errorMessage); throw Exception(errorMessage);
} }
if (response.statusCode != 200 && response.statusCode != 201) { if (response.statusCode != 200 && response.statusCode != 201)
throw Exception('Unexpected http status: ${response.statusCode}'); throw Exception('Unexpected http status: ${response.statusCode}');
}
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final id = responseJSON['id'] as String; final id = responseJSON['id'] as String;
@ -147,8 +170,8 @@ class ExolixExchangeProvider extends ExchangeProvider {
return Trade( return Trade(
id: id, id: id,
from: _request.from, from: request.fromCurrency,
to: _request.to, to: request.toCurrency,
provider: description, provider: description,
inputAddress: inputAddress, inputAddress: inputAddress,
refundAddress: refundAddress, refundAddress: refundAddress,
@ -161,13 +184,11 @@ class ExolixExchangeProvider extends ExchangeProvider {
@override @override
Future<Trade> findTradeById({required String id}) async { Future<Trade> findTradeById({required String id}) async {
final findTradeByIdPath = transactionsPath + '/$id'; final findTradeByIdPath = '$transactionsPath/$id';
final uri = Uri.https(apiBaseUrl, findTradeByIdPath); final uri = Uri.https(apiBaseUrl, findTradeByIdPath);
final response = await get(uri); final response = await get(uri);
if (response.statusCode == 404) { if (response.statusCode == 404) throw TradeNotFoundException(id, provider: description);
throw TradeNotFoundException(id, provider: description);
}
if (response.statusCode == 400) { if (response.statusCode == 400) {
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
@ -177,80 +198,33 @@ class ExolixExchangeProvider extends ExchangeProvider {
throw TradeNotFoundException(id, provider: description, description: errorMessage); throw TradeNotFoundException(id, provider: description, description: errorMessage);
} }
if (response.statusCode != 200) { if (response.statusCode != 200)
throw Exception('Unexpected http status: ${response.statusCode}'); throw Exception('Unexpected http status: ${response.statusCode}');
}
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final coinFrom = responseJSON['coinFrom']['coinCode'] as String; final coinFrom = responseJSON['coinFrom']['coinCode'] as String;
final from = CryptoCurrency.fromString(coinFrom);
final coinTo = responseJSON['coinTo']['coinCode'] as String; final coinTo = responseJSON['coinTo']['coinCode'] as String;
final to = CryptoCurrency.fromString(coinTo);
final inputAddress = responseJSON['depositAddress'] as String; final inputAddress = responseJSON['depositAddress'] as String;
final amount = responseJSON['amount'].toString(); final amount = responseJSON['amount'].toString();
final status = responseJSON['status'] as String; final status = responseJSON['status'] as String;
final state = TradeState.deserialize(raw: _prepareStatus(status));
final extraId = responseJSON['depositExtraId'] as String?; final extraId = responseJSON['depositExtraId'] as String?;
final outputTransaction = responseJSON['hashOut']['hash'] as String?; final outputTransaction = responseJSON['hashOut']['hash'] as String?;
final payoutAddress = responseJSON['withdrawalAddress'] as String; final payoutAddress = responseJSON['withdrawalAddress'] as String;
return Trade( return Trade(
id: id, id: id,
from: from, from: CryptoCurrency.fromString(coinFrom),
to: to, to: CryptoCurrency.fromString(coinTo),
provider: description, provider: description,
inputAddress: inputAddress, inputAddress: inputAddress,
amount: amount, amount: amount,
state: state, state: TradeState.deserialize(raw: _prepareStatus(status)),
extraId: extraId, extraId: extraId,
outputTransaction: outputTransaction, outputTransaction: outputTransaction,
payoutAddress: payoutAddress); payoutAddress: payoutAddress);
} }
@override String _getRateType(bool isFixedRate) => isFixedRate ? 'fixed' : 'float';
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 _prepareStatus(String status) { String _prepareStatus(String status) {
switch (status) { switch (status) {

View file

@ -1,28 +1,20 @@
import 'dart:convert'; 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:cake_wallet/.secrets.g.dart' as secrets;
import 'package:cw_core/crypto_currency.dart'; import 'package:cake_wallet/exchange/provider/exchange_provider.dart';
import 'package:cake_wallet/exchange/trade_request.dart'; import 'package:cake_wallet/exchange/exchange_provider_description.dart';
import 'package:cake_wallet/exchange/trade.dart';
import 'package:cake_wallet/exchange/limits.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'; import 'package:http/http.dart';
class SideShiftExchangeProvider extends ExchangeProvider { class SideShiftExchangeProvider extends ExchangeProvider {
SideShiftExchangeProvider() : super(pairList: _supportedPairs()); SideShiftExchangeProvider() : super(pairList: supportedPairs(_notSupported));
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';
static const List<CryptoCurrency> _notSupported = [ static const List<CryptoCurrency> _notSupported = [
CryptoCurrency.xhv, CryptoCurrency.xhv,
@ -39,49 +31,28 @@ class SideShiftExchangeProvider extends ExchangeProvider {
CryptoCurrency.eos, CryptoCurrency.eos,
]; ];
static List<ExchangePair> _supportedPairs() { static const affiliateId = secrets.sideShiftAffiliateId;
final supportedCurrencies = static const apiBaseUrl = 'https://sideshift.ai/api';
CryptoCurrency.all.where((element) => !_notSupported.contains(element)).toList(); static const rangePath = '/v2/pair';
static const orderPath = '/v2/shifts';
static const quotePath = '/v2/quotes';
static const permissionPath = '/v2/permissions';
return supportedCurrencies @override
.map((i) => supportedCurrencies.map((k) => ExchangePair(from: i, to: k, reverse: true))) String get title => 'SideShift';
.expand((i) => i)
.toList(); @override
} bool get isAvailable => true;
@override
bool get isEnabled => true;
@override
bool get supportsFixedRate => true;
@override @override
ExchangeProviderDescription get description => ExchangeProviderDescription.sideShift; 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 @override
Future<bool> checkIsAvailable() async { Future<bool> checkIsAvailable() async {
const url = apiBaseUrl + permissionPath; const url = apiBaseUrl + permissionPath;
@ -95,110 +66,10 @@ class SideShiftExchangeProvider extends ExchangeProvider {
throw Exception('$error'); throw Exception('$error');
} }
if (response.statusCode != 200) { if (response.statusCode != 200) return false;
return false;
}
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final cancreateShift = responseJSON['createShift'] as bool; return 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;
} }
@override @override
@ -244,6 +115,91 @@ class SideShiftExchangeProvider extends ExchangeProvider {
return Limits(min: min, max: max); 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 @override
Future<Trade> findTradeById({required String id}) async { Future<Trade> findTradeById({required String id}) async {
final url = apiBaseUrl + orderPath + '/' + id; final url = apiBaseUrl + orderPath + '/' + id;
@ -267,44 +223,56 @@ class SideShiftExchangeProvider extends ExchangeProvider {
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final fromCurrency = responseJSON['depositCoin'] as String; final fromCurrency = responseJSON['depositCoin'] as String;
final from = CryptoCurrency.fromString(fromCurrency);
final toCurrency = responseJSON['settleCoin'] as String; final toCurrency = responseJSON['settleCoin'] as String;
final to = CryptoCurrency.fromString(toCurrency);
final inputAddress = responseJSON['depositAddress'] as String; final inputAddress = responseJSON['depositAddress'] as String;
final expectedSendAmount = responseJSON['depositAmount'] as String?; final expectedSendAmount = responseJSON['depositAmount'] as String?;
final status = responseJSON['status'] as String?; final status = responseJSON['status'] as String?;
final settleAddress = responseJSON['settleAddress'] as String; final settleAddress = responseJSON['settleAddress'] as String;
TradeState? state;
state = TradeState.deserialize(raw: status ?? 'created');
final isVariable = (responseJSON['type'] as String) == 'variable'; final isVariable = (responseJSON['type'] as String) == 'variable';
final expiredAtRaw = responseJSON['expiresAt'] as String; final expiredAtRaw = responseJSON['expiresAt'] as String;
final expiredAt = isVariable ? null : DateTime.tryParse(expiredAtRaw)?.toLocal(); final expiredAt = isVariable ? null : DateTime.tryParse(expiredAtRaw)?.toLocal();
return Trade( return Trade(
id: id, id: id,
from: from, from: CryptoCurrency.fromString(fromCurrency),
to: to, to: CryptoCurrency.fromString(toCurrency),
provider: description, provider: description,
inputAddress: inputAddress, inputAddress: inputAddress,
amount: expectedSendAmount ?? '', amount: expectedSendAmount ?? '',
state: state, state: TradeState.deserialize(raw: status ?? 'created'),
expiredAt: expiredAt, expiredAt: expiredAt,
payoutAddress: settleAddress); payoutAddress: settleAddress);
} }
@override Future<String> _createQuote(TradeRequest request) async {
bool get isAvailable => true; 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 if (response.statusCode != 201) {
bool get isEnabled => true; if (response.statusCode == 400) {
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final error = responseJSON['error']['message'] as String;
@override throw TradeNotCreatedException(description, description: error);
bool get supportsFixedRate => true; }
@override throw TradeNotCreatedException(description);
String get title => 'SideShift'; }
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
return responseJSON['id'] as String;
}
String _networkFor(CryptoCurrency currency) => String _networkFor(CryptoCurrency currency) =>
currency.tag != null ? _normalizeTag(currency.tag!) : 'mainnet'; currency.tag != null ? _normalizeTag(currency.tag!) : 'mainnet';

View file

@ -1,71 +1,49 @@
import 'dart:convert'; 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/exchange_provider_description.dart';
import 'package:cake_wallet/exchange/simpleswap/simpleswap_request.dart'; import 'package:cake_wallet/exchange/limits.dart';
import 'package:cake_wallet/exchange/trade_not_created_exeption.dart'; import 'package:cake_wallet/exchange/trade.dart';
import 'package:cake_wallet/exchange/trade_not_found_exeption.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/trade_state.dart';
import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
import 'package:cake_wallet/utils/device_info.dart'; import 'package:cake_wallet/utils/device_info.dart';
import 'package:cw_core/crypto_currency.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'; import 'package:http/http.dart';
class SimpleSwapExchangeProvider extends ExchangeProvider { class SimpleSwapExchangeProvider extends ExchangeProvider {
SimpleSwapExchangeProvider() SimpleSwapExchangeProvider() : super(pairList: supportedPairs(_notSupported));
: 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());
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 apiAuthority = 'api.simpleswap.io';
static const getEstimatePath = '/v1/get_estimated'; static const getEstimatePath = '/v1/get_estimated';
static const rangePath = '/v1/get_ranges'; static const rangePath = '/v1/get_ranges';
static const getExchangePath = '/v1/get_exchange'; static const getExchangePath = '/v1/get_exchange';
static const createExchangePath = '/v1/create_exchange'; static const createExchangePath = '/v1/create_exchange';
static final apiKey = DeviceInfo.instance.isMobile ? secrets.simpleSwapApiKey : secrets.simpleSwapApiKeyDesktop;
@override @override
ExchangeProviderDescription get description => String get title => 'SimpleSwap';
ExchangeProviderDescription.simpleSwap;
@override @override
Future<double> fetchRate( bool get isAvailable => true;
{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);
if (response.body == "null") return 0.00; @override
final data = json.decode(response.body) as String; bool get isEnabled => true;
return double.parse(data) / amount;
} catch (_) { @override
return 0.00; bool get supportsFixedRate => false;
}
} @override
ExchangeProviderDescription get description => ExchangeProviderDescription.simpleSwap;
@override @override
Future<bool> checkIsAvailable() async { Future<bool> checkIsAvailable() async {
@ -76,20 +54,79 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
} }
@override @override
Future<Trade> createTrade({required TradeRequest request, required bool isFixedRateMode}) async { Future<Limits> fetchLimits(
final _request = request as SimpleSwapRequest; {required CryptoCurrency from,
final headers = { required CryptoCurrency to,
'Content-Type': 'application/json'}; required bool isFixedRateMode}) async {
final params = <String, String>{ final params = <String, dynamic>{
'api_key': apiKey, '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>{ final body = <String, dynamic>{
"currency_from": _normalizeCryptoCurrency(_request.from), "currency_from": _normalizeCurrency(request.fromCurrency),
"currency_to": _normalizeCryptoCurrency(_request.to), "currency_to": _normalizeCurrency(request.toCurrency),
"amount": _request.amount, "amount": request.fromAmount,
"fixed": isFixedRateMode, "fixed": isFixedRateMode,
"user_refund_address": _request.refundAddress, "user_refund_address": request.refundAddress,
"address_to": _request.address "address_to": request.toAddress
}; };
final uri = Uri.https(apiAuthority, createExchangePath, params); final uri = Uri.https(apiAuthority, createExchangePath, params);
@ -112,56 +149,22 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
final payoutAddress = responseJSON['address_to'] as String; final payoutAddress = responseJSON['address_to'] as String;
final settleAddress = responseJSON['user_refund_address'] as String; final settleAddress = responseJSON['user_refund_address'] as String;
final extraId = responseJSON['extra_id_from'] as String?; final extraId = responseJSON['extra_id_from'] as String?;
return Trade( return Trade(
id: id, id: id,
provider: description, provider: description,
from: _request.from, from: request.fromCurrency,
to: _request.to, to: request.toCurrency,
inputAddress: inputAddress, inputAddress: inputAddress,
refundAddress: settleAddress, refundAddress: settleAddress,
extraId: extraId, extraId: extraId,
state: TradeState.created, state: TradeState.created,
amount: _request.amount, amount: request.fromAmount,
payoutAddress: payoutAddress, payoutAddress: payoutAddress,
createdAt: DateTime.now(), 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 @override
Future<Trade> findTradeById({required String id}) async { Future<Trade> findTradeById({required String id}) async {
final params = {'api_key': apiKey, 'id': id}; final params = {'api_key': apiKey, 'id': id};
@ -185,42 +188,27 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final fromCurrency = responseJSON['currency_from'] as String; final fromCurrency = responseJSON['currency_from'] as String;
final from = CryptoCurrency.fromString(fromCurrency);
final toCurrency = responseJSON['currency_to'] as String; final toCurrency = responseJSON['currency_to'] as String;
final to = CryptoCurrency.fromString(toCurrency);
final inputAddress = responseJSON['address_from'] as String; final inputAddress = responseJSON['address_from'] as String;
final expectedSendAmount = responseJSON['expected_amount'].toString(); final expectedSendAmount = responseJSON['expected_amount'].toString();
final extraId = responseJSON['extra_id_from'] as String?; final extraId = responseJSON['extra_id_from'] as String?;
final status = responseJSON['status'] as String; final status = responseJSON['status'] as String;
final payoutAddress = responseJSON['address_to'] as String; final payoutAddress = responseJSON['address_to'] as String;
final state = TradeState.deserialize(raw: status);
return Trade( return Trade(
id: id, id: id,
from: from, from: CryptoCurrency.fromString(fromCurrency),
to: to, to: CryptoCurrency.fromString(toCurrency),
extraId: extraId, extraId: extraId,
provider: description, provider: description,
inputAddress: inputAddress, inputAddress: inputAddress,
amount: expectedSendAmount, amount: expectedSendAmount,
state: state, state: TradeState.deserialize(raw: status),
payoutAddress: payoutAddress, payoutAddress: payoutAddress,
); );
} }
@override static String _normalizeCurrency(CryptoCurrency currency) {
bool get isAvailable => true;
@override
bool get isEnabled => true;
@override
bool get supportsFixedRate => false;
@override
String get title => 'SimpleSwap';
static String _normalizeCryptoCurrency(CryptoCurrency currency) {
switch (currency) { switch (currency) {
case CryptoCurrency.zaddr: case CryptoCurrency.zaddr:
return 'zec'; return 'zec';

View file

@ -1,21 +1,20 @@
import 'dart:convert'; 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/.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'; import 'package:http/http.dart';
class TrocadorExchangeProvider extends ExchangeProvider { class TrocadorExchangeProvider extends ExchangeProvider {
TrocadorExchangeProvider({this.useTorOnly = false}) TrocadorExchangeProvider({this.useTorOnly = false})
: _lastUsedRateId = '', : _lastUsedRateId = '',
super(pairList: _supportedPairs()); super(pairList: supportedPairs(_notSupported));
bool useTorOnly; bool useTorOnly;
@ -24,135 +23,58 @@ class TrocadorExchangeProvider extends ExchangeProvider {
CryptoCurrency.zaddr, CryptoCurrency.zaddr,
]; ];
static List<ExchangePair> _supportedPairs() { static const apiKey = secrets.trocadorApiKey;
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 onionApiAuthority = 'trocadorfyhlu27aefre5u7zri66gudtzdyelymftvr4yjwcxhfaqsid.onion'; static const onionApiAuthority = 'trocadorfyhlu27aefre5u7zri66gudtzdyelymftvr4yjwcxhfaqsid.onion';
static const clearNetAuthority = 'trocador.app'; static const clearNetAuthority = 'trocador.app';
static const apiKey = secrets.trocadorApiKey;
static const markup = secrets.trocadorExchangeMarkup; static const markup = secrets.trocadorExchangeMarkup;
static const newRatePath = '/api/new_rate'; static const newRatePath = '/api/new_rate';
static const createTradePath = 'api/new_trade'; static const createTradePath = 'api/new_trade';
static const tradePath = 'api/trade'; static const tradePath = 'api/trade';
static const coinPath = 'api/coin'; static const coinPath = 'api/coin';
String _lastUsedRateId; String _lastUsedRateId;
@override @override
Future<bool> checkIsAvailable() async => true; String get title => 'Trocador';
@override @override
Future<Trade> createTrade({required TradeRequest request, required bool isFixedRateMode}) { bool get isAvailable => true;
final _request = request as TrocadorRequest;
return _createTrade(request: _request, isFixedRateMode: isFixedRateMode);
}
Future<Trade> _createTrade({ @override
required TrocadorRequest request, bool get isEnabled => true;
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
};
if (isFixedRateMode) { @override
await fetchRate( bool get supportsFixedRate => true;
from: request.from,
to: request.to,
amount: double.tryParse(request.toAmount) ?? 0,
isFixedRateMode: true,
isReceiveAmount: true,
);
params['id'] = _lastUsedRateId;
}
final uri = await _getUri(createTradePath, params); @override
final response = await get(uri); bool get supportsOnionAddress => true;
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 @override
ExchangeProviderDescription get description => ExchangeProviderDescription.trocador; ExchangeProviderDescription get description => ExchangeProviderDescription.trocador;
@override
Future<bool> checkIsAvailable() async => true;
@override @override
Future<Limits> fetchLimits( Future<Limits> fetchLimits(
{required CryptoCurrency from, {required CryptoCurrency from,
required CryptoCurrency to, required CryptoCurrency to,
required bool isFixedRateMode}) async { required bool isFixedRateMode}) async {
final params = <String, String>{ final params = {
'api_key': apiKey, 'api_key': apiKey,
'ticker': _normalizeCurrency(from), 'ticker': _normalizeCurrency(from),
'name': from.name, 'name': from.name,
}; };
final uri = await _getUri(coinPath, params); final uri = await _getUri(coinPath, params);
final response = await get(uri); final response = await get(uri);
if (response.statusCode != 200) { if (response.statusCode != 200)
throw Exception('Unexpected http status: ${response.statusCode}'); throw Exception('Unexpected http status: ${response.statusCode}');
}
final responseJSON = json.decode(response.body) as List<dynamic>; final responseJSON = json.decode(response.body) as List<dynamic>;
if (responseJSON.isEmpty) { if (responseJSON.isEmpty) throw Exception('No data');
throw Exception('No data');
}
final coinJson = responseJSON.first as Map<String, dynamic>; final coinJson = responseJSON.first as Map<String, dynamic>;
@ -170,9 +92,7 @@ class TrocadorExchangeProvider extends ExchangeProvider {
required bool isFixedRateMode, required bool isFixedRateMode,
required bool isReceiveAmount}) async { required bool isReceiveAmount}) async {
try { try {
if (amount == 0) { if (amount == 0) return 0.0;
return 0.0;
}
final params = <String, String>{ final params = <String, String>{
'api_key': apiKey, 'api_key': apiKey,
@ -195,9 +115,7 @@ class TrocadorExchangeProvider extends ExchangeProvider {
final toAmount = double.parse(responseJSON['amount_to'].toString()); final toAmount = double.parse(responseJSON['amount_to'].toString());
final rateId = responseJSON['trade_id'] as String? ?? ''; final rateId = responseJSON['trade_id'] as String? ?? '';
if (rateId.isNotEmpty) { if (rateId.isNotEmpty) _lastUsedRateId = rateId;
_lastUsedRateId = rateId;
}
return isReceiveAmount ? (amount / fromAmount) : (toAmount / amount); return isReceiveAmount ? (amount / fromAmount) : (toAmount / amount);
} catch (e) { } catch (e) {
@ -207,39 +125,102 @@ class TrocadorExchangeProvider extends ExchangeProvider {
} }
@override @override
Future<Trade> findTradeById({required String id}) async { Future<Trade> createTrade({required TradeRequest request, required bool isFixedRateMode}) async {
final uri = await _getUri(tradePath, {'api_key': apiKey, 'id': id}); final params = {
return get(uri).then((response) { 'api_key': apiKey,
if (response.statusCode != 200) { 'ticker_from': _normalizeCurrency(request.fromCurrency),
throw Exception('Unexpected http status: ${response.statusCode}'); '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 responseListJson = json.decode(response.body) as List; final uri = await _getUri(createTradePath, params);
final response = await get(uri);
final responseJSON = responseListJson.first; 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 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 inputAddress = responseJSON['address_provider'] as String;
final fromAmount = responseJSON['amount_from']?.toString() ?? '0'; final refundAddress = responseJSON['refund_address'] as String;
final from = CryptoCurrency.fromString(responseJSON['ticker_from'] as String); final status = responseJSON['status'] as String;
final to = CryptoCurrency.fromString(responseJSON['ticker_to'] as String); final payoutAddress = responseJSON['address_user'] as String;
final state = TradeState.deserialize(raw: responseJSON['status'] as String); final date = responseJSON['date'] as String;
final date = DateTime.parse(responseJSON['date'] as String);
final password = responseJSON['password'] as String; final password = responseJSON['password'] as String;
final providerId = responseJSON['id_provider'] as String; final providerId = responseJSON['id_provider'] as String;
final providerName = responseJSON['provider'] as String; final providerName = responseJSON['provider'] as String;
return Trade( return Trade(
id: id, id: id,
from: from, from: request.fromCurrency,
to: to, to: request.toCurrency,
provider: description, provider: description,
inputAddress: inputAddress, inputAddress: inputAddress,
refundAddress: refundAddress, refundAddress: refundAddress,
createdAt: date, 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)
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 password = responseJSON['password'] as String;
final providerId = responseJSON['id_provider'] as String;
final providerName = responseJSON['provider'] as String;
return Trade(
id: id,
from: CryptoCurrency.fromString(responseJSON['ticker_from'] as String),
to: CryptoCurrency.fromString(responseJSON['ticker_to'] as String),
provider: description,
inputAddress: inputAddress,
refundAddress: refundAddress,
createdAt: DateTime.parse(responseJSON['date'] as String),
amount: fromAmount, amount: fromAmount,
state: state, state: TradeState.deserialize(raw: responseJSON['status'] as String),
payoutAddress: payoutAddress, payoutAddress: payoutAddress,
password: password, password: password,
providerId: providerId, 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) { String _networkFor(CryptoCurrency currency) {
switch (currency) { switch (currency) {
case CryptoCurrency.eth: case CryptoCurrency.eth:
@ -301,15 +267,9 @@ class TrocadorExchangeProvider extends ExchangeProvider {
} }
Future<Uri> _getUri(String path, Map<String, String> queryParams) async { 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); final uri = Uri.http(onionApiAuthority, path, queryParams);
if (useTorOnly) { if (useTorOnly) return uri;
return uri;
}
try { try {
await get(uri); await get(uri);

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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/exchange_provider_description.dart';
import 'package:cake_wallet/exchange/trade_state.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/format_amount.dart';
import 'package:cw_core/hive_type_ids.dart'; import 'package:cw_core/hive_type_ids.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
@ -28,18 +28,13 @@ class Trade extends HiveObject {
this.providerId, this.providerId,
this.providerName, this.providerName,
}) { }) {
if (provider != null) { if (provider != null) providerRaw = provider.raw;
providerRaw = provider.raw;
} if (from != null) fromRaw = from.raw;
if (from != null) {
fromRaw = from.raw; if (to != null) toRaw = to.raw;
}
if (to != null) { if (state != null) stateRaw = state.raw;
toRaw = to.raw;
}
if (state != null) {
stateRaw = state.raw;
}
} }
static const typeId = TRADE_TYPE_ID; static const typeId = TRADE_TYPE_ID;

View file

@ -8,12 +8,5 @@ class TradeNotCreatedException implements Exception {
String description; String description;
@override @override
String toString() { String toString() => '${S.current.trade_for_not_created(provider.title)} $description';
var text = provider != null
? S.current.trade_for_not_created(provider.title)
: S.current.trade_not_created;
text += ' $description';
return text;
}
} }

View 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';
}

View file

@ -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;
}
}

View file

@ -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;
}

View file

@ -1,9 +1,7 @@
import 'package:flutter/foundation.dart';
import 'package:cw_core/enumerable_item.dart'; import 'package:cw_core/enumerable_item.dart';
class TradeState extends EnumerableItem<String> with Serializable<String> { class TradeState extends EnumerableItem<String> with Serializable<String> {
const TradeState({required String raw, required String title}) const TradeState({required String raw, required String title}) : super(raw: raw, title: title);
: super(raw: raw, title: title);
@override @override
bool operator ==(Object other) => other is TradeState && other.raw == raw; 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 trading = TradeState(raw: 'trading', title: 'Trading');
static const traded = TradeState(raw: 'traded', title: 'Traded'); static const traded = TradeState(raw: 'traded', title: 'Traded');
static const complete = TradeState(raw: 'complete', title: 'Complete'); static const complete = TradeState(raw: 'complete', title: 'Complete');
static const toBeCreated = static const toBeCreated = TradeState(raw: 'TO_BE_CREATED', title: 'To be created');
TradeState(raw: 'TO_BE_CREATED', title: 'To be created');
static const unpaid = TradeState(raw: 'UNPAID', title: 'Unpaid'); static const unpaid = TradeState(raw: 'UNPAID', title: 'Unpaid');
static const underpaid = TradeState(raw: 'UNDERPAID', title: 'Underpaid'); static const underpaid = TradeState(raw: 'UNDERPAID', title: 'Underpaid');
static const paidUnconfirmed = static const paidUnconfirmed = TradeState(raw: 'PAID_UNCONFIRMED', title: 'Paid unconfirmed');
TradeState(raw: 'PAID_UNCONFIRMED', title: 'Paid unconfirmed');
static const paid = TradeState(raw: 'PAID', title: 'Paid'); static const paid = TradeState(raw: 'PAID', title: 'Paid');
static const btcSent = TradeState(raw: 'BTC_SENT', title: 'Btc sent'); static const btcSent = TradeState(raw: 'BTC_SENT', title: 'Btc sent');
static const timeout = TradeState(raw: 'TIMED_OUT', title: 'Timeout'); 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 finished = TradeState(raw: 'finished', title: 'Finished');
static const waiting = TradeState(raw: 'waiting', title: 'Waiting'); static const waiting = TradeState(raw: 'waiting', title: 'Waiting');
static const processing = TradeState(raw: 'processing', title: 'Processing'); static const processing = TradeState(raw: 'processing', title: 'Processing');
static const waitingPayment = static const waitingPayment = TradeState(raw: 'waitingPayment', title: 'Waiting payment');
TradeState(raw: 'waitingPayment', title: 'Waiting payment');
static const waitingAuthorization = static const waitingAuthorization =
TradeState(raw: 'waitingAuthorization', title: 'Waiting authorization'); TradeState(raw: 'waitingAuthorization', title: 'Waiting authorization');
static const failed = TradeState(raw: 'failed', title: 'Failed'); static const failed = TradeState(raw: 'failed', title: 'Failed');

View file

@ -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;
}

View 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();
}

View file

@ -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));
}

View file

@ -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 XMRTOTradeRequest extends TradeRequest {
XMRTOTradeRequest(
{required this.from,
required this.to,
required this.amount,
required this.receiveAmount,
required this.address,
required this.refundAddress,
required this.isBTCRequest});
final CryptoCurrency from;
final CryptoCurrency to;
final String amount;
final String receiveAmount;
final String address;
final String refundAddress;
final bool isBTCRequest;
}

View file

@ -1,6 +1,6 @@
import 'package:cake_wallet/themes/extensions/exchange_page_theme.dart'; import 'package:cake_wallet/themes/extensions/exchange_page_theme.dart';
import 'package:cake_wallet/themes/extensions/keyboard_theme.dart'; import 'package:cake_wallet/themes/extensions/keyboard_theme.dart';
import 'package:cake_wallet/exchange/exchange_provider.dart'; import 'package:cake_wallet/exchange/provider/exchange_provider.dart';
import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart'; import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -9,9 +9,6 @@ import 'package:keyboard_actions/keyboard_actions.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cake_wallet/exchange/xmrto/xmrto_exchange_provider.dart';
// import 'package:cake_wallet/exchange/exchange_trade_state.dart';
// import 'package:cake_wallet/exchange/limits_state.dart';
import 'package:cake_wallet/src/screens/exchange/widgets/exchange_card.dart'; import 'package:cake_wallet/src/screens/exchange/widgets/exchange_card.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart'; import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
@ -176,9 +173,7 @@ class ExchangeTemplatePage extends BasePage {
exchangeViewModel.wallet.currency exchangeViewModel.wallet.currency
? exchangeViewModel.wallet.walletAddresses.address ? exchangeViewModel.wallet.walletAddresses.address
: exchangeViewModel.receiveAddress, : exchangeViewModel.receiveAddress,
initialIsAmountEditable: initialIsAmountEditable: false,
exchangeViewModel.provider is
XMRTOExchangeProvider ? true : false,
initialIsAddressEditable: initialIsAddressEditable:
exchangeViewModel.isReceiveAddressEnabled, exchangeViewModel.isReceiveAddressEnabled,
isAmountEstimated: true, isAmountEstimated: true,
@ -207,22 +202,21 @@ class ExchangeTemplatePage extends BasePage {
bottomSection: Column(children: <Widget>[ bottomSection: Column(children: <Widget>[
Padding( Padding(
padding: EdgeInsets.only(bottom: 15), padding: EdgeInsets.only(bottom: 15),
child: Observer(builder: (_) { child: Observer(
final description = builder: (_) => Center(
exchangeViewModel.provider is XMRTOExchangeProvider
? S.of(context).amount_is_guaranteed
: S.of(context).amount_is_estimate;
return Center(
child: Text( child: Text(
description, S.of(context).amount_is_estimate,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
color: Theme.of(context).extension<ExchangePageTheme>()!.receiveAmountColor, color: Theme.of(context)
.extension<ExchangePageTheme>()!
.receiveAmountColor,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
fontSize: 12), fontSize: 12,
),
),
),
), ),
);
}),
), ),
PrimaryButton( PrimaryButton(
onPressed: () { onPressed: () {
@ -340,9 +334,7 @@ class ExchangeTemplatePage extends BasePage {
}); });
reaction((_) => exchangeViewModel.provider, (ExchangeProvider? provider) { reaction((_) => exchangeViewModel.provider, (ExchangeProvider? provider) {
provider is XMRTOExchangeProvider receiveKey.currentState!.isAmountEditable(isEditable: false);
? receiveKey.currentState!.isAmountEditable(isEditable: true)
: receiveKey.currentState!.isAmountEditable(isEditable: false);
}); });
/*reaction((_) => exchangeViewModel.limitsState, (LimitsState state) { /*reaction((_) => exchangeViewModel.limitsState, (LimitsState state) {

View file

@ -1,18 +1,19 @@
import 'package:auto_size_text/auto_size_text.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/screens/trade_details/track_trade_list_item.dart';
import 'package:cake_wallet/src/screens/trade_details/trade_details_list_card.dart';
import 'package:cake_wallet/src/screens/trade_details/trade_details_status_item.dart';
import 'package:cake_wallet/src/screens/trade_details/trade_provider_unsupported_item.dart';
import 'package:cake_wallet/src/widgets/list_row.dart';
import 'package:cake_wallet/src/widgets/standard_list.dart'; import 'package:cake_wallet/src/widgets/standard_list.dart';
import 'package:cake_wallet/src/widgets/standard_list_card.dart'; import 'package:cake_wallet/src/widgets/standard_list_card.dart';
import 'package:cake_wallet/src/widgets/standard_list_status_row.dart'; import 'package:cake_wallet/src/widgets/standard_list_status_row.dart';
import 'package:cake_wallet/utils/show_bar.dart'; import 'package:cake_wallet/utils/show_bar.dart';
import 'package:cake_wallet/view_model/trade_details_view_model.dart'; import 'package:cake_wallet/view_model/trade_details_view_model.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/list_row.dart';
import 'package:cake_wallet/src/screens/trade_details/track_trade_list_item.dart';
import 'package:cake_wallet/src/screens/trade_details/trade_details_list_card.dart';
import 'package:cake_wallet/src/screens/trade_details/trade_details_status_item.dart';
class TradeDetailsPage extends BasePage { class TradeDetailsPage extends BasePage {
TradeDetailsPage(this.tradeDetailsViewModel); TradeDetailsPage(this.tradeDetailsViewModel);
@ -23,8 +24,7 @@ class TradeDetailsPage extends BasePage {
final TradeDetailsViewModel tradeDetailsViewModel; final TradeDetailsViewModel tradeDetailsViewModel;
@override @override
Widget body(BuildContext context) => Widget body(BuildContext context) => TradeDetailsPageBody(tradeDetailsViewModel);
TradeDetailsPageBody(tradeDetailsViewModel);
} }
class TradeDetailsPageBody extends StatefulWidget { class TradeDetailsPageBody extends StatefulWidget {
@ -33,8 +33,7 @@ class TradeDetailsPageBody extends StatefulWidget {
final TradeDetailsViewModel tradeDetailsViewModel; final TradeDetailsViewModel tradeDetailsViewModel;
@override @override
TradeDetailsPageBodyState createState() => TradeDetailsPageBodyState createState() => TradeDetailsPageBodyState(tradeDetailsViewModel);
TradeDetailsPageBodyState(tradeDetailsViewModel);
} }
class TradeDetailsPageBodyState extends State<TradeDetailsPageBody> { class TradeDetailsPageBodyState extends State<TradeDetailsPageBody> {
@ -51,7 +50,7 @@ class TradeDetailsPageBodyState extends State<TradeDetailsPageBody> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Observer(builder: (_) { return Observer(builder: (_) {
int itemsCount = tradeDetailsViewModel.items.length; final itemsCount = tradeDetailsViewModel.items.length;
return SectionStandardList( return SectionStandardList(
sectionCount: 1, sectionCount: 1,
@ -59,37 +58,39 @@ class TradeDetailsPageBodyState extends State<TradeDetailsPageBody> {
itemBuilder: (__, index) { itemBuilder: (__, index) {
final item = tradeDetailsViewModel.items[index]; final item = tradeDetailsViewModel.items[index];
if (item is TrackTradeListItem) { if (item is TrackTradeListItem)
return GestureDetector( return GestureDetector(
onTap: item.onTap, onTap: item.onTap,
child: ListRow( child: ListRow(title: '${item.title}', value: '${item.value}'));
title: '${item.title}', value: '${item.value}'));
}
if (item is DetailsListStatusItem) { if (item is DetailsListStatusItem)
return StandardListStatusRow( return StandardListStatusRow(title: item.title, value: item.value);
title: item.title,
value: item.value);
}
if (item is TradeDetailsListCardItem) { if (item is TradeDetailsListCardItem)
return TradeDetailsStandardListCard( return TradeDetailsStandardListCard(
id: item.id, id: item.id,
create: item.createdAt, create: item.createdAt,
pair: item.pair, pair: item.pair,
currentTheme: tradeDetailsViewModel.settingsStore.currentTheme.type, currentTheme: tradeDetailsViewModel.settingsStore.currentTheme.type,
onTap: item.onTap,); onTap: item.onTap,
} );
if (item is TradeProviderUnsupportedItem)
return AutoSizeText(item.value,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Colors.red,
));
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
Clipboard.setData(ClipboardData(text: '${item.value}')); Clipboard.setData(ClipboardData(text: '${item.value}'));
showBar<void>(context, S.of(context).copied_to_clipboard); showBar<void>(context, S.of(context).copied_to_clipboard);
}, },
child: ListRow( child: ListRow(title: '${item.title}', value: '${item.value}'));
title: '${item.title}', value: '${item.value}'));
}); });
}); });
} }
} }

View file

@ -0,0 +1,5 @@
import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart';
class TradeProviderUnsupportedItem extends StandartListItem {
TradeProviderUnsupportedItem({required String error}) : super(title: '', value: error);
}

View file

@ -1,22 +1,21 @@
import 'dart:async'; import 'dart:async';
import 'package:cake_wallet/exchange/exolix/exolix_exchange_provider.dart';
import 'package:cake_wallet/exchange/sideshift/sideshift_exchange_provider.dart';
import 'package:cake_wallet/exchange/simpleswap/simpleswap_exchange_provider.dart';
import 'package:cake_wallet/exchange/trocador/trocador_exchange_provider.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cake_wallet/exchange/changenow/changenow_exchange_provider.dart';
import 'package:cake_wallet/exchange/exchange_provider.dart';
import 'package:cake_wallet/exchange/exchange_provider_description.dart'; import 'package:cake_wallet/exchange/exchange_provider_description.dart';
import 'package:cake_wallet/exchange/morphtoken/morphtoken_exchange_provider.dart'; import 'package:cake_wallet/exchange/provider/changenow_exchange_provider.dart';
import 'package:cake_wallet/exchange/provider/exchange_provider.dart';
import 'package:cake_wallet/exchange/provider/exolix_exchange_provider.dart';
import 'package:cake_wallet/exchange/provider/sideshift_exchange_provider.dart';
import 'package:cake_wallet/exchange/provider/simpleswap_exchange_provider.dart';
import 'package:cake_wallet/exchange/provider/trocador_exchange_provider.dart';
import 'package:cake_wallet/exchange/trade.dart'; import 'package:cake_wallet/exchange/trade.dart';
import 'package:cake_wallet/exchange/xmrto/xmrto_exchange_provider.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/exchange_trade/exchange_trade_item.dart';
import 'package:cake_wallet/store/dashboard/trades_store.dart'; import 'package:cake_wallet/store/dashboard/trades_store.dart';
import 'package:cake_wallet/view_model/send/send_view_model.dart'; import 'package:cake_wallet/view_model/send/send_view_model.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:cake_wallet/src/screens/exchange_trade/exchange_trade_item.dart';
import 'package:cake_wallet/generated/i18n.dart';
part 'exchange_trade_view_model.g.dart'; part 'exchange_trade_view_model.g.dart';
@ -35,16 +34,10 @@ abstract class ExchangeTradeViewModelBase with Store {
tradesStore.trade!.from.tag == CryptoCurrency.eth.title), tradesStore.trade!.from.tag == CryptoCurrency.eth.title),
items = ObservableList<ExchangeTradeItem>() { items = ObservableList<ExchangeTradeItem>() {
switch (trade.provider) { switch (trade.provider) {
case ExchangeProviderDescription.xmrto:
_provider = XMRTOExchangeProvider();
break;
case ExchangeProviderDescription.changeNow: case ExchangeProviderDescription.changeNow:
_provider = _provider =
ChangeNowExchangeProvider(settingsStore: sendViewModel.balanceViewModel.settingsStore); ChangeNowExchangeProvider(settingsStore: sendViewModel.balanceViewModel.settingsStore);
break; break;
case ExchangeProviderDescription.morphToken:
_provider = MorphTokenExchangeProvider(trades: trades);
break;
case ExchangeProviderDescription.sideShift: case ExchangeProviderDescription.sideShift:
_provider = SideShiftExchangeProvider(); _provider = SideShiftExchangeProvider();
break; break;
@ -60,9 +53,12 @@ abstract class ExchangeTradeViewModelBase with Store {
} }
_updateItems(); _updateItems();
if (_provider != null) {
_updateTrade(); _updateTrade();
timer = Timer.periodic(Duration(seconds: 20), (_) async => _updateTrade()); timer = Timer.periodic(Duration(seconds: 20), (_) async => _updateTrade());
} }
}
final WalletBase wallet; final WalletBase wallet;
final Box<Trade> trades; final Box<Trade> trades;
@ -100,10 +96,8 @@ abstract class ExchangeTradeViewModelBase with Store {
Timer? timer; Timer? timer;
@action @action
Future confirmSending() async { Future<void> confirmSending() async {
if (!isSendable) { if (!isSendable) return;
return;
}
sendViewModel.clearOutputs(); sendViewModel.clearOutputs();
final output = sendViewModel.outputs.first; final output = sendViewModel.outputs.first;
@ -118,13 +112,10 @@ abstract class ExchangeTradeViewModelBase with Store {
try { try {
final updatedTrade = await _provider!.findTradeById(id: trade.id); final updatedTrade = await _provider!.findTradeById(id: trade.id);
if (updatedTrade.createdAt == null && trade.createdAt != null) { if (updatedTrade.createdAt == null && trade.createdAt != null)
updatedTrade.createdAt = trade.createdAt; updatedTrade.createdAt = trade.createdAt;
}
if (updatedTrade.amount.isEmpty) { if (updatedTrade.amount.isEmpty) updatedTrade.amount = trade.amount;
updatedTrade.amount = trade.amount;
}
trade = updatedTrade; trade = updatedTrade;

View file

@ -3,48 +3,39 @@ import 'dart:collection';
import 'dart:convert'; import 'dart:convert';
import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart'; import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/core/wallet_change_listener_view_model.dart'; import 'package:cake_wallet/core/wallet_change_listener_view_model.dart';
import 'package:cake_wallet/entities/exchange_api_mode.dart'; import 'package:cake_wallet/entities/exchange_api_mode.dart';
import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/entities/wallet_contact.dart'; import 'package:cake_wallet/entities/wallet_contact.dart';
import 'package:cake_wallet/ethereum/ethereum.dart'; import 'package:cake_wallet/ethereum/ethereum.dart';
import 'package:cake_wallet/exchange/exolix/exolix_exchange_provider.dart'; import 'package:cake_wallet/exchange/exchange_template.dart';
import 'package:cake_wallet/exchange/exolix/exolix_request.dart'; import 'package:cake_wallet/exchange/exchange_trade_state.dart';
import 'package:cake_wallet/exchange/sideshift/sideshift_exchange_provider.dart';
import 'package:cake_wallet/exchange/sideshift/sideshift_request.dart';
import 'package:cake_wallet/exchange/simpleswap/simpleswap_exchange_provider.dart';
import 'package:cake_wallet/exchange/simpleswap/simpleswap_request.dart';
import 'package:cake_wallet/exchange/trocador/trocador_exchange_provider.dart';
import 'package:cake_wallet/exchange/trocador/trocador_request.dart';
import 'package:cake_wallet/utils/feature_flag.dart';
import 'package:cake_wallet/view_model/contact_list/contact_list_view_model.dart';
import 'package:cw_core/transaction_priority.dart';
import 'package:cake_wallet/store/app_store.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/sync_status.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/monero/monero.dart';
import 'package:cake_wallet/exchange/exchange_provider.dart';
import 'package:cake_wallet/exchange/limits.dart'; import 'package:cake_wallet/exchange/limits.dart';
import 'package:cake_wallet/exchange/trade.dart';
import 'package:cake_wallet/exchange/limits_state.dart'; import 'package:cake_wallet/exchange/limits_state.dart';
import 'package:cake_wallet/exchange/provider/changenow_exchange_provider.dart';
import 'package:cake_wallet/exchange/provider/exchange_provider.dart';
import 'package:cake_wallet/exchange/provider/exolix_exchange_provider.dart';
import 'package:cake_wallet/exchange/provider/sideshift_exchange_provider.dart';
import 'package:cake_wallet/exchange/provider/simpleswap_exchange_provider.dart';
import 'package:cake_wallet/exchange/provider/trocador_exchange_provider.dart';
import 'package:cake_wallet/exchange/trade.dart';
import 'package:cake_wallet/exchange/trade_request.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/monero/monero.dart';
import 'package:cake_wallet/store/app_store.dart';
import 'package:cake_wallet/store/dashboard/trades_store.dart'; import 'package:cake_wallet/store/dashboard/trades_store.dart';
import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/store/templates/exchange_template_store.dart';
import 'package:cake_wallet/utils/feature_flag.dart';
import 'package:cake_wallet/view_model/contact_list/contact_list_view_model.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/sync_status.dart';
import 'package:cw_core/transaction_priority.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:hive/hive.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:hive/hive.dart';
import 'package:cake_wallet/exchange/exchange_trade_state.dart';
import 'package:cake_wallet/exchange/changenow/changenow_exchange_provider.dart';
import 'package:cake_wallet/exchange/changenow/changenow_request.dart';
import 'package:cake_wallet/exchange/trade_request.dart';
import 'package:cake_wallet/exchange/xmrto/xmrto_exchange_provider.dart';
import 'package:cake_wallet/exchange/xmrto/xmrto_trade_request.dart';
import 'package:cake_wallet/exchange/morphtoken/morphtoken_exchange_provider.dart';
import 'package:cake_wallet/exchange/morphtoken/morphtoken_request.dart';
import 'package:cake_wallet/store/templates/exchange_template_store.dart';
import 'package:cake_wallet/exchange/exchange_template.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
part 'exchange_view_model.g.dart'; part 'exchange_view_model.g.dart';
@ -144,6 +135,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
_calculateBestRate(); _calculateBestRate();
}); });
} }
bool _useTorOnly; bool _useTorOnly;
final Box<Trade> trades; final Box<Trade> trades;
final ExchangeTemplateStore _exchangeTemplateStore; final ExchangeTemplateStore _exchangeTemplateStore;
@ -384,13 +376,9 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
double minLimit = limits.min ?? 0; double minLimit = limits.min ?? 0;
double? maxLimit = limits.max; double? maxLimit = limits.max;
if (_enteredAmount < minLimit) { if (_enteredAmount < minLimit) return false;
return false;
}
if (maxLimit != null && _enteredAmount > maxLimit) { if (maxLimit != null && _enteredAmount > maxLimit) return false;
return false;
}
return true; return true;
} }
@ -422,16 +410,12 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
} }
} }
} }
if (_sortedAvailableProviders.isNotEmpty) { if (_sortedAvailableProviders.isNotEmpty) _bestRate = _sortedAvailableProviders.keys.first;
_bestRate = _sortedAvailableProviders.keys.first;
}
} }
@action @action
Future<void> loadLimits() async { Future<void> loadLimits() async {
if (selectedProviders.isEmpty) { if (selectedProviders.isEmpty) return;
return;
}
limitsState = LimitsIsLoading(); limitsState = LimitsIsLoading();
@ -444,20 +428,16 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
try { try {
for (var provider in selectedProviders) { for (var provider in selectedProviders) {
/// if this provider is not valid for the current pair, skip it /// if this provider is not valid for the current pair, skip it
if (!providersForCurrentPair().contains(provider)) { if (!providersForCurrentPair().contains(provider)) continue;
continue;
}
try { try {
final tempLimits = final tempLimits =
await provider.fetchLimits(from: from, to: to, isFixedRateMode: isFixedRateMode); await provider.fetchLimits(from: from, to: to, isFixedRateMode: isFixedRateMode);
if (lowestMin != null && (tempLimits.min ?? -1) < lowestMin) { if (lowestMin != null && (tempLimits.min ?? -1) < lowestMin) lowestMin = tempLimits.min;
lowestMin = tempLimits.min;
} if (highestMax != null && (tempLimits.max ?? double.maxFinite) > highestMax)
if (highestMax != null && (tempLimits.max ?? double.maxFinite) > highestMax) {
highestMax = tempLimits.max; highestMax = tempLimits.max;
}
} catch (e) { } catch (e) {
continue; continue;
} }
@ -482,111 +462,34 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
@action @action
Future<void> createTrade() async { Future<void> createTrade() async {
TradeRequest? request;
String amount = '';
try { try {
for (var provider in _sortedAvailableProviders.values) { for (var provider in _sortedAvailableProviders.values) {
if (!(await provider.checkIsAvailable())) { if (!(await provider.checkIsAvailable())) continue;
continue;
}
if (provider is SideShiftExchangeProvider) { final request = TradeRequest(
request = SideShiftRequest( fromCurrency: depositCurrency,
depositMethod: depositCurrency, toCurrency: receiveCurrency,
settleMethod: receiveCurrency,
depositAmount: isFixedRateMode
? receiveAmount.replaceAll(',', '.')
: depositAmount.replaceAll(',', '.'),
settleAddress: receiveAddress,
refundAddress: depositAddress,
);
amount = isFixedRateMode ? receiveAmount : depositAmount;
}
if (provider is SimpleSwapExchangeProvider) {
request = SimpleSwapRequest(
from: depositCurrency,
to: receiveCurrency,
amount: depositAmount.replaceAll(',', '.'),
address: receiveAddress,
refundAddress: depositAddress,
);
amount = isFixedRateMode ? receiveAmount : depositAmount;
}
if (provider is XMRTOExchangeProvider) {
request = XMRTOTradeRequest(
from: depositCurrency,
to: receiveCurrency,
amount: depositAmount.replaceAll(',', '.'),
receiveAmount: receiveAmount.replaceAll(',', '.'),
address: receiveAddress,
refundAddress: depositAddress,
isBTCRequest: isReceiveAmountEntered);
amount = isFixedRateMode ? receiveAmount : depositAmount;
}
if (provider is ChangeNowExchangeProvider) {
request = ChangeNowRequest(
from: depositCurrency,
to: receiveCurrency,
fromAmount: depositAmount.replaceAll(',', '.'), fromAmount: depositAmount.replaceAll(',', '.'),
toAmount: receiveAmount.replaceAll(',', '.'), toAmount: receiveAmount.replaceAll(',', '.'),
refundAddress: depositAddress, refundAddress: depositAddress,
address: receiveAddress, toAddress: receiveAddress,
isReverse: isFixedRateMode); isFixedRate: isFixedRateMode);
amount = isFixedRateMode ? receiveAmount : depositAmount;
}
if (provider is MorphTokenExchangeProvider) {
request = MorphTokenRequest(
from: depositCurrency,
to: receiveCurrency,
amount: depositAmount.replaceAll(',', '.'),
refundAddress: depositAddress,
address: receiveAddress);
amount = isFixedRateMode ? receiveAmount : depositAmount;
}
if (provider is TrocadorExchangeProvider) {
request = TrocadorRequest(
from: depositCurrency,
to: receiveCurrency,
fromAmount: depositAmount.replaceAll(',', '.'),
toAmount: receiveAmount.replaceAll(',', '.'),
refundAddress: depositAddress,
address: receiveAddress,
isReverse: isFixedRateMode);
amount = isFixedRateMode ? receiveAmount : depositAmount;
}
if (provider is ExolixExchangeProvider) {
request = ExolixRequest(
from: depositCurrency,
to: receiveCurrency,
fromAmount: depositAmount.replaceAll(',', '.'),
toAmount: receiveAmount.replaceAll(',', '.'),
refundAddress: depositAddress,
address: receiveAddress);
amount = isFixedRateMode ? receiveAmount : depositAmount;
}
var amount = isFixedRateMode ? receiveAmount : depositAmount;
amount = amount.replaceAll(',', '.'); amount = amount.replaceAll(',', '.');
if (limitsState is LimitsLoadedSuccessfully) { if (limitsState is LimitsLoadedSuccessfully) {
if (double.tryParse(amount) == null) { if (double.tryParse(amount) == null) continue;
if (limits.max != null && double.parse(amount) < limits.min!)
continue; continue;
} else if (limits.max != null && double.parse(amount) > limits.max!)
if (limits.max != null && double.parse(amount) < limits.min!) {
continue; continue;
} else if (limits.max != null && double.parse(amount) > limits.max!) { else {
continue;
} else {
try { try {
tradeState = TradeIsCreating(); tradeState = TradeIsCreating();
final trade = final trade =
await provider.createTrade(request: request!, isFixedRateMode: isFixedRateMode); await provider.createTrade(request: request, isFixedRateMode: isFixedRateMode);
trade.walletId = wallet.id; trade.walletId = wallet.id;
tradesStore.setTrade(trade); tradesStore.setTrade(trade);
await trades.add(trade); await trades.add(trade);
@ -636,9 +539,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
final priority = _settingsStore.priority[wallet.type]!; final priority = _settingsStore.priority[wallet.type]!;
final fee = wallet.calculateEstimatedFee(priority, null); final fee = wallet.calculateEstimatedFee(priority, null);
if (availableBalance < fee || availableBalance == 0) { if (availableBalance < fee || availableBalance == 0) return;
return;
}
final amount = availableBalance - fee; final amount = availableBalance - fee;
changeDepositAmount(amount: bitcoin!.formatterBitcoinAmountToString(amount: amount)); changeDepositAmount(amount: bitcoin!.formatterBitcoinAmountToString(amount: amount));
@ -669,20 +570,16 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
void removeTemplate({required ExchangeTemplate template}) => void removeTemplate({required ExchangeTemplate template}) =>
_exchangeTemplateStore.remove(template: template); _exchangeTemplateStore.remove(template: template);
List<ExchangeProvider> providersForCurrentPair() { List<ExchangeProvider> providersForCurrentPair() =>
return _providersForPair(from: depositCurrency, to: receiveCurrency); _providersForPair(from: depositCurrency, to: receiveCurrency);
}
List<ExchangeProvider> _providersForPair( List<ExchangeProvider> _providersForPair(
{required CryptoCurrency from, required CryptoCurrency to}) { {required CryptoCurrency from, required CryptoCurrency to}) =>
final providers = providerList providerList
.where((provider) => .where((provider) =>
provider.pairList.where((pair) => pair.from == from && pair.to == to).isNotEmpty) provider.pairList.where((pair) => pair.from == from && pair.to == to).isNotEmpty)
.toList(); .toList();
return providers;
}
void _onPairChange() { void _onPairChange() {
depositAmount = ''; depositAmount = '';
receiveAmount = ''; receiveAmount = '';
@ -744,9 +641,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
@action @action
void addExchangeProvider(ExchangeProvider provider) { void addExchangeProvider(ExchangeProvider provider) {
selectedProviders.add(provider); selectedProviders.add(provider);
if (providersForCurrentPair().contains(provider)) { if (providersForCurrentPair().contains(provider)) _tradeAvailableProviders.add(provider);
_tradeAvailableProviders.add(provider);
}
} }
@action @action
@ -817,14 +712,13 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
} }
void _setProviders() { void _setProviders() {
if (_settingsStore.exchangeStatus == ExchangeApiMode.torOnly) { if (_settingsStore.exchangeStatus == ExchangeApiMode.torOnly)
providerList = _allProviders.where((provider) => provider.supportsOnionAddress).toList(); providerList = _allProviders.where((provider) => provider.supportsOnionAddress).toList();
} else { else
providerList = _allProviders; providerList = _allProviders;
} }
}
int get depositMaxDigits => depositCurrency == CryptoCurrency.btc ? 8 : 12; int get depositMaxDigits => depositCurrency.decimals;
int get receiveMaxDigits => receiveCurrency == CryptoCurrency.btc ? 8 : 12; int get receiveMaxDigits => receiveCurrency.decimals;
} }

View file

@ -1,28 +1,28 @@
import 'dart:async'; import 'dart:async';
import 'package:cake_wallet/exchange/changenow/changenow_exchange_provider.dart';
import 'package:cake_wallet/exchange/exchange_provider.dart';
import 'package:cake_wallet/exchange/exchange_provider_description.dart'; import 'package:cake_wallet/exchange/exchange_provider_description.dart';
import 'package:cake_wallet/exchange/exolix/exolix_exchange_provider.dart'; import 'package:cake_wallet/exchange/provider/changenow_exchange_provider.dart';
import 'package:cake_wallet/exchange/morphtoken/morphtoken_exchange_provider.dart'; import 'package:cake_wallet/exchange/provider/exchange_provider.dart';
import 'package:cake_wallet/exchange/sideshift/sideshift_exchange_provider.dart'; import 'package:cake_wallet/exchange/provider/exolix_exchange_provider.dart';
import 'package:cake_wallet/exchange/simpleswap/simpleswap_exchange_provider.dart'; import 'package:cake_wallet/exchange/provider/sideshift_exchange_provider.dart';
import 'package:cake_wallet/exchange/provider/simpleswap_exchange_provider.dart';
import 'package:cake_wallet/exchange/provider/trocador_exchange_provider.dart';
import 'package:cake_wallet/exchange/trade.dart'; import 'package:cake_wallet/exchange/trade.dart';
import 'package:cake_wallet/exchange/trocador/trocador_exchange_provider.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/exchange/xmrto/xmrto_exchange_provider.dart'; import 'package:cake_wallet/src/screens/trade_details/track_trade_list_item.dart';
import 'package:cake_wallet/src/screens/trade_details/trade_details_list_card.dart';
import 'package:cake_wallet/src/screens/trade_details/trade_details_status_item.dart';
import 'package:cake_wallet/src/screens/trade_details/trade_provider_unsupported_item.dart';
import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart';
import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/utils/date_formatter.dart'; import 'package:cake_wallet/utils/date_formatter.dart';
import 'package:cake_wallet/utils/show_bar.dart'; import 'package:cake_wallet/utils/show_bar.dart';
import 'package:collection/collection.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart';
import 'package:cake_wallet/src/screens/trade_details/track_trade_list_item.dart';
import 'package:cake_wallet/src/screens/trade_details/trade_details_list_card.dart';
import 'package:cake_wallet/src/screens/trade_details/trade_details_status_item.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import 'package:collection/collection.dart';
part 'trade_details_view_model.g.dart'; part 'trade_details_view_model.g.dart';
@ -37,15 +37,9 @@ abstract class TradeDetailsViewModelBase with Store {
trade = trades.values.firstWhereOrNull((element) => element.id == tradeForDetails.id) ?? trade = trades.values.firstWhereOrNull((element) => element.id == tradeForDetails.id) ??
tradeForDetails { tradeForDetails {
switch (trade.provider) { switch (trade.provider) {
case ExchangeProviderDescription.xmrto:
_provider = XMRTOExchangeProvider();
break;
case ExchangeProviderDescription.changeNow: case ExchangeProviderDescription.changeNow:
_provider = ChangeNowExchangeProvider(settingsStore: settingsStore); _provider = ChangeNowExchangeProvider(settingsStore: settingsStore);
break; break;
case ExchangeProviderDescription.morphToken:
_provider = MorphTokenExchangeProvider(trades: trades);
break;
case ExchangeProviderDescription.sideShift: case ExchangeProviderDescription.sideShift:
_provider = SideShiftExchangeProvider(); _provider = SideShiftExchangeProvider();
break; break;
@ -62,10 +56,11 @@ abstract class TradeDetailsViewModelBase with Store {
_updateItems(); _updateItems();
if (_provider != null) {
_updateTrade(); _updateTrade();
timer = Timer.periodic(Duration(seconds: 20), (_) async => _updateTrade()); timer = Timer.periodic(Duration(seconds: 20), (_) async => _updateTrade());
} }
}
final Box<Trade> trades; final Box<Trade> trades;
@ -86,9 +81,9 @@ abstract class TradeDetailsViewModelBase with Store {
try { try {
final updatedTrade = await _provider!.findTradeById(id: trade.id); final updatedTrade = await _provider!.findTradeById(id: trade.id);
if (updatedTrade.createdAt == null && trade.createdAt != null) { if (updatedTrade.createdAt == null && trade.createdAt != null)
updatedTrade.createdAt = trade.createdAt; updatedTrade.createdAt = trade.createdAt;
}
Trade? foundElement = trades.values.firstWhereOrNull((element) => element.id == trade.id); Trade? foundElement = trades.values.firstWhereOrNull((element) => element.id == trade.id);
if (foundElement != null) { if (foundElement != null) {
final editedTrade = trades.get(foundElement.key); final editedTrade = trades.get(foundElement.key);
@ -109,6 +104,10 @@ abstract class TradeDetailsViewModelBase with Store {
items.clear(); items.clear();
if (_provider == null)
items.add(TradeProviderUnsupportedItem(
error: S.current.exchange_provider_unsupported(trade.provider.title)));
items.add( items.add(
DetailsListStatusItem(title: S.current.trade_details_state, value: trade.state.toString())); DetailsListStatusItem(title: S.current.trade_details_state, value: trade.state.toString()));

View file

@ -339,7 +339,6 @@
"template": "قالب", "template": "قالب",
"confirm_delete_template": "سيؤدي هذا الإجراء إلى حذف هذا القالب. هل ترغب في الاستمرار؟", "confirm_delete_template": "سيؤدي هذا الإجراء إلى حذف هذا القالب. هل ترغب في الاستمرار؟",
"confirm_delete_wallet": "سيؤدي هذا الإجراء إلى حذف هذه المحفظة. هل ترغب في الاستمرار؟", "confirm_delete_wallet": "سيؤدي هذا الإجراء إلى حذف هذه المحفظة. هل ترغب في الاستمرار؟",
"picker_description": "لاختيار ChangeNOW أو MorphToken ، يرجى تغيير زوج التداول الخاص بك أولاً",
"change_wallet_alert_title": "تغيير المحفظة الحالية", "change_wallet_alert_title": "تغيير المحفظة الحالية",
"change_wallet_alert_content": "هل تريد تغيير المحفظة الحالية إلى ${wallet_name}؟", "change_wallet_alert_content": "هل تريد تغيير المحفظة الحالية إلى ${wallet_name}؟",
"creating_new_wallet": "يتم إنشاء محفظة جديدة", "creating_new_wallet": "يتم إنشاء محفظة جديدة",
@ -722,5 +721,6 @@
"enterWalletConnectURI": "WalletConnect ـﻟ URI ﻞﺧﺩﺃ", "enterWalletConnectURI": "WalletConnect ـﻟ URI ﻞﺧﺩﺃ",
"seed_key": "مفتاح البذور", "seed_key": "مفتاح البذور",
"enter_seed_phrase": "أدخل عبارة البذور الخاصة بك", "enter_seed_phrase": "أدخل عبارة البذور الخاصة بك",
"add_contact": "ﻝﺎﺼﺗﺍ ﺔﻬﺟ ﺔﻓﺎﺿﺇ" "add_contact": "ﻝﺎﺼﺗﺍ ﺔﻬﺟ ﺔﻓﺎﺿﺇ",
"exchange_provider_unsupported": "${providerName} لم يعد مدعومًا!"
} }

View file

@ -339,7 +339,6 @@
"template": "Шаблон", "template": "Шаблон",
"confirm_delete_template": "Този шаблон ще бъде изтрит. Искате ли да продължите?", "confirm_delete_template": "Този шаблон ще бъде изтрит. Искате ли да продължите?",
"confirm_delete_wallet": "Този портфейл ще бъде изтрит. Искате ли да продължите?", "confirm_delete_wallet": "Този портфейл ще бъде изтрит. Искате ли да продължите?",
"picker_description": "За да изберете ChangeNOW или MorphToken, моля, първо променете своя trading pair",
"change_wallet_alert_title": "Смяна на сегашния портфейл", "change_wallet_alert_title": "Смяна на сегашния портфейл",
"change_wallet_alert_content": "Искате ли да смените сегашния портфейл на ${wallet_name}?", "change_wallet_alert_content": "Искате ли да смените сегашния портфейл на ${wallet_name}?",
"creating_new_wallet": "Създаване на нов портфейл", "creating_new_wallet": "Създаване на нов портфейл",
@ -718,5 +717,6 @@
"enterWalletConnectURI": "Въведете URI на WalletConnect", "enterWalletConnectURI": "Въведете URI на WalletConnect",
"seed_key": "Ключ за семена", "seed_key": "Ключ за семена",
"enter_seed_phrase": "Въведете вашата фраза за семена", "enter_seed_phrase": "Въведете вашата фраза за семена",
"add_contact": "Добави контакт" "add_contact": "Добави контакт",
"exchange_provider_unsupported": "${providerName} вече не се поддържа!"
} }

View file

@ -339,7 +339,6 @@
"template": "Šablona", "template": "Šablona",
"confirm_delete_template": "Tato akce smaže tuto šablonu. Přejete si pokračovat?", "confirm_delete_template": "Tato akce smaže tuto šablonu. Přejete si pokračovat?",
"confirm_delete_wallet": "Tato akce smaže tuto peněženku. Přejete si pokračovat?", "confirm_delete_wallet": "Tato akce smaže tuto peněženku. Přejete si pokračovat?",
"picker_description": "Pro volbu ChangeNOW, nebo MorphToken si prosím vyberte nejprve pár pro obchodování",
"change_wallet_alert_title": "Přepnout peněženku", "change_wallet_alert_title": "Přepnout peněženku",
"change_wallet_alert_content": "Opravdu chcete změnit aktivní peněženku na ${wallet_name}?", "change_wallet_alert_content": "Opravdu chcete změnit aktivní peněženku na ${wallet_name}?",
"creating_new_wallet": "Vytvářím novou peněženku", "creating_new_wallet": "Vytvářím novou peněženku",
@ -718,5 +717,6 @@
"enterWalletConnectURI": "Zadejte identifikátor URI WalletConnect", "enterWalletConnectURI": "Zadejte identifikátor URI WalletConnect",
"seed_key": "Klíč semen", "seed_key": "Klíč semen",
"enter_seed_phrase": "Zadejte svou frázi semen", "enter_seed_phrase": "Zadejte svou frázi semen",
"add_contact": "Přidat kontakt" "add_contact": "Přidat kontakt",
"exchange_provider_unsupported": "${providerName} již není podporováno!"
} }

View file

@ -339,7 +339,6 @@
"template": "Vorlage", "template": "Vorlage",
"confirm_delete_template": "Diese Aktion löscht diese Vorlage. Möchten Sie fortfahren?", "confirm_delete_template": "Diese Aktion löscht diese Vorlage. Möchten Sie fortfahren?",
"confirm_delete_wallet": "Diese Aktion löscht diese Wallet. Möchten Sie fortfahren?", "confirm_delete_wallet": "Diese Aktion löscht diese Wallet. Möchten Sie fortfahren?",
"picker_description": "Um ChangeNOW oder MorphToken zu wählen, ändern Sie bitte zuerst Ihr Handelspaar",
"change_wallet_alert_title": "Aktuelle Wallet ändern", "change_wallet_alert_title": "Aktuelle Wallet ändern",
"change_wallet_alert_content": "Möchten Sie die aktuelle Wallet zu ${wallet_name} ändern?", "change_wallet_alert_content": "Möchten Sie die aktuelle Wallet zu ${wallet_name} ändern?",
"creating_new_wallet": "Neue Wallet erstellen", "creating_new_wallet": "Neue Wallet erstellen",
@ -724,7 +723,8 @@
"awaitDAppProcessing": "Bitte warten Sie, bis die dApp die Verarbeitung abgeschlossen hat.", "awaitDAppProcessing": "Bitte warten Sie, bis die dApp die Verarbeitung abgeschlossen hat.",
"copyWalletConnectLink": "Kopieren Sie den WalletConnect-Link von dApp und fügen Sie ihn hier ein", "copyWalletConnectLink": "Kopieren Sie den WalletConnect-Link von dApp und fügen Sie ihn hier ein",
"enterWalletConnectURI": "Geben Sie den WalletConnect-URI ein", "enterWalletConnectURI": "Geben Sie den WalletConnect-URI ein",
"seed_key": "Samenschlüssel", "seed_key": "Seed-Schlüssel",
"enter_seed_phrase": "Geben Sie Ihre Samenphrase ein", "enter_seed_phrase": "Geben Sie Ihre Seed-Phrase ein",
"add_contact": "Kontakt hinzufügen" "add_contact": "Kontakt hinzufügen",
"exchange_provider_unsupported": "${providerName} wird nicht mehr unterstützt!"
} }

View file

@ -339,7 +339,6 @@
"template": "Template", "template": "Template",
"confirm_delete_template": "This action will delete this template. Do you wish to continue?", "confirm_delete_template": "This action will delete this template. Do you wish to continue?",
"confirm_delete_wallet": "This action will delete this wallet. Do you wish to continue?", "confirm_delete_wallet": "This action will delete this wallet. Do you wish to continue?",
"picker_description": "To choose ChangeNOW or MorphToken, please change your trading pair first",
"change_wallet_alert_title": "Change current wallet", "change_wallet_alert_title": "Change current wallet",
"change_wallet_alert_content": "Do you want to change current wallet to ${wallet_name}?", "change_wallet_alert_content": "Do you want to change current wallet to ${wallet_name}?",
"creating_new_wallet": "Creating new wallet", "creating_new_wallet": "Creating new wallet",
@ -727,5 +726,6 @@
"enterWalletConnectURI": "Enter WalletConnect URI", "enterWalletConnectURI": "Enter WalletConnect URI",
"seed_key": "Seed key", "seed_key": "Seed key",
"enter_seed_phrase": "Enter your seed phrase", "enter_seed_phrase": "Enter your seed phrase",
"add_contact": "Add contact" "add_contact": "Add contact",
"exchange_provider_unsupported": "${providerName} is no longer supported!"
} }

View file

@ -339,7 +339,6 @@
"template": "Plantilla", "template": "Plantilla",
"confirm_delete_template": "Esta acción eliminará esta plantilla. ¿Desea continuar?", "confirm_delete_template": "Esta acción eliminará esta plantilla. ¿Desea continuar?",
"confirm_delete_wallet": "Esta acción eliminará esta billetera. ¿Desea continuar?", "confirm_delete_wallet": "Esta acción eliminará esta billetera. ¿Desea continuar?",
"picker_description": "Para elegir ChangeNOW o MorphToken, primero cambie su par comercial",
"change_wallet_alert_title": "Cambiar billetera actual", "change_wallet_alert_title": "Cambiar billetera actual",
"change_wallet_alert_content": "¿Quieres cambiar la billetera actual a ${wallet_name}?", "change_wallet_alert_content": "¿Quieres cambiar la billetera actual a ${wallet_name}?",
"creating_new_wallet": "Creando nueva billetera", "creating_new_wallet": "Creando nueva billetera",
@ -726,5 +725,6 @@
"enterWalletConnectURI": "Ingrese el URI de WalletConnect", "enterWalletConnectURI": "Ingrese el URI de WalletConnect",
"seed_key": "Llave de semilla", "seed_key": "Llave de semilla",
"enter_seed_phrase": "Ingrese su frase de semillas", "enter_seed_phrase": "Ingrese su frase de semillas",
"add_contact": "Agregar contacto" "add_contact": "Agregar contacto",
"exchange_provider_unsupported": "¡${providerName} ya no es compatible!"
} }

View file

@ -339,7 +339,6 @@
"template": "Modèle", "template": "Modèle",
"confirm_delete_template": "Cette action va supprimer ce modèle. Souhaitez-vous continuer ?", "confirm_delete_template": "Cette action va supprimer ce modèle. Souhaitez-vous continuer ?",
"confirm_delete_wallet": "Cette action va supprimer ce portefeuille (wallet). Souhaitez-vous contnuer ?", "confirm_delete_wallet": "Cette action va supprimer ce portefeuille (wallet). Souhaitez-vous contnuer ?",
"picker_description": "Pour choisir ChangeNOW ou MorphToken, merci de modifier d'abord la paire de votre échange",
"change_wallet_alert_title": "Changer le portefeuille (wallet) actuel", "change_wallet_alert_title": "Changer le portefeuille (wallet) actuel",
"change_wallet_alert_content": "Souhaitez-vous changer le portefeuille (wallet) actuel vers ${wallet_name} ?", "change_wallet_alert_content": "Souhaitez-vous changer le portefeuille (wallet) actuel vers ${wallet_name} ?",
"creating_new_wallet": "Création d'un nouveau portefeuille (wallet)", "creating_new_wallet": "Création d'un nouveau portefeuille (wallet)",
@ -726,5 +725,6 @@
"enterWalletConnectURI": "Saisissez l'URI de WalletConnect.", "enterWalletConnectURI": "Saisissez l'URI de WalletConnect.",
"seed_key": "Clé de graines", "seed_key": "Clé de graines",
"enter_seed_phrase": "Entrez votre phrase de semence", "enter_seed_phrase": "Entrez votre phrase de semence",
"add_contact": "Ajouter le contact" "add_contact": "Ajouter le contact",
"exchange_provider_unsupported": "${providerName} n'est plus pris en charge!"
} }

View file

@ -340,7 +340,6 @@
"template": "Samfura", "template": "Samfura",
"confirm_delete_template": "Wannan aikin zai share wannan samfuri. Kuna so ku ci gaba?", "confirm_delete_template": "Wannan aikin zai share wannan samfuri. Kuna so ku ci gaba?",
"confirm_delete_wallet": "Wannan aikin zai share wannan walat. Kuna so ku ci gaba?", "confirm_delete_wallet": "Wannan aikin zai share wannan walat. Kuna so ku ci gaba?",
"picker_description": "Don zaɓar ChangeNOW ko MorphToken, da farko canja kasuwancin pair din ku",
"change_wallet_alert_title": "Canja walat yanzu", "change_wallet_alert_title": "Canja walat yanzu",
"change_wallet_alert_content": "Kana so ka canja walat yanzu zuwa ${wallet_name}?", "change_wallet_alert_content": "Kana so ka canja walat yanzu zuwa ${wallet_name}?",
"creating_new_wallet": "Haliccin walat sabuwa", "creating_new_wallet": "Haliccin walat sabuwa",
@ -704,5 +703,6 @@
"enterWalletConnectURI": "Shigar da WalletConnect URI", "enterWalletConnectURI": "Shigar da WalletConnect URI",
"seed_key": "Maɓallin iri", "seed_key": "Maɓallin iri",
"enter_seed_phrase": "Shigar da Sert Sentarku", "enter_seed_phrase": "Shigar da Sert Sentarku",
"add_contact": "Ƙara lamba" "add_contact": "Ƙara lamba",
"exchange_provider_unsupported": "${providerName}"
} }

View file

@ -339,7 +339,6 @@
"template": "खाका", "template": "खाका",
"confirm_delete_template": "यह क्रिया इस टेम्पलेट को हटा देगी। क्या आप जारी रखना चाहते हैं?", "confirm_delete_template": "यह क्रिया इस टेम्पलेट को हटा देगी। क्या आप जारी रखना चाहते हैं?",
"confirm_delete_wallet": "यह क्रिया इस वॉलेट को हटा देगी। क्या आप जारी रखना चाहते हैं?", "confirm_delete_wallet": "यह क्रिया इस वॉलेट को हटा देगी। क्या आप जारी रखना चाहते हैं?",
"picker_description": "ChangeNOW या MorphToken चुनने के लिए, कृपया अपनी ट्रेडिंग जोड़ी को पहले बदलें",
"change_wallet_alert_title": "वर्तमान बटुआ बदलें", "change_wallet_alert_title": "वर्तमान बटुआ बदलें",
"change_wallet_alert_content": "क्या आप करंट वॉलेट को बदलना चाहते हैं ${wallet_name}?", "change_wallet_alert_content": "क्या आप करंट वॉलेट को बदलना चाहते हैं ${wallet_name}?",
"creating_new_wallet": "नया बटुआ बनाना", "creating_new_wallet": "नया बटुआ बनाना",
@ -726,5 +725,6 @@
"enterWalletConnectURI": "वॉलेटकनेक्ट यूआरआई दर्ज करें", "enterWalletConnectURI": "वॉलेटकनेक्ट यूआरआई दर्ज करें",
"seed_key": "बीज कुंजी", "seed_key": "बीज कुंजी",
"enter_seed_phrase": "अपना बीज वाक्यांश दर्ज करें", "enter_seed_phrase": "अपना बीज वाक्यांश दर्ज करें",
"add_contact": "संपर्क जोड़ें" "add_contact": "संपर्क जोड़ें",
"exchange_provider_unsupported": "${providerName} अब समर्थित नहीं है!"
} }

View file

@ -339,7 +339,6 @@
"template": "Predložak", "template": "Predložak",
"confirm_delete_template": "Ovom ćete radnjom izbrisati ovaj predložak. Želite li nastaviti?", "confirm_delete_template": "Ovom ćete radnjom izbrisati ovaj predložak. Želite li nastaviti?",
"confirm_delete_wallet": "Ovom ćete radnjom izbrisati ovaj novčanik. Želite li nastaviti?", "confirm_delete_wallet": "Ovom ćete radnjom izbrisati ovaj novčanik. Želite li nastaviti?",
"picker_description": "Da biste odabrali ChangeNOW ili MorphToken, molimo da prvo odabete dvije valute za trgovanje",
"change_wallet_alert_title": "Izmijeni trenutni novčanik", "change_wallet_alert_title": "Izmijeni trenutni novčanik",
"change_wallet_alert_content": "Želite li promijeniti trenutni novčanik u ${wallet_name}?", "change_wallet_alert_content": "Želite li promijeniti trenutni novčanik u ${wallet_name}?",
"creating_new_wallet": "Stvaranje novog novčanika", "creating_new_wallet": "Stvaranje novog novčanika",
@ -724,5 +723,6 @@
"enterWalletConnectURI": "Unesite WalletConnect URI", "enterWalletConnectURI": "Unesite WalletConnect URI",
"seed_key": "Sjemenski ključ", "seed_key": "Sjemenski ključ",
"enter_seed_phrase": "Unesite svoju sjemensku frazu", "enter_seed_phrase": "Unesite svoju sjemensku frazu",
"add_contact": "Dodaj kontakt" "add_contact": "Dodaj kontakt",
"exchange_provider_unsupported": "${providerName} više nije podržan!"
} }

View file

@ -340,7 +340,6 @@
"template": "Template", "template": "Template",
"confirm_delete_template": "Tindakan ini akan menghapus template ini. Apakah Anda ingin melanjutkan?", "confirm_delete_template": "Tindakan ini akan menghapus template ini. Apakah Anda ingin melanjutkan?",
"confirm_delete_wallet": "Tindakan ini akan menghapus dompet ini. Apakah Anda ingin melanjutkan?", "confirm_delete_wallet": "Tindakan ini akan menghapus dompet ini. Apakah Anda ingin melanjutkan?",
"picker_description": "Untuk memilih ChangeNOW atau MorphToken, silakan ubah pasangan perdagangan Anda terlebih dahulu",
"change_wallet_alert_title": "Ganti dompet saat ini", "change_wallet_alert_title": "Ganti dompet saat ini",
"change_wallet_alert_content": "Apakah Anda ingin mengganti dompet saat ini ke ${wallet_name}?", "change_wallet_alert_content": "Apakah Anda ingin mengganti dompet saat ini ke ${wallet_name}?",
"creating_new_wallet": "Membuat dompet baru", "creating_new_wallet": "Membuat dompet baru",
@ -714,5 +713,6 @@
"enterWalletConnectURI": "Masukkan URI WalletConnect", "enterWalletConnectURI": "Masukkan URI WalletConnect",
"seed_key": "Kunci benih", "seed_key": "Kunci benih",
"enter_seed_phrase": "Masukkan frasa benih Anda", "enter_seed_phrase": "Masukkan frasa benih Anda",
"add_contact": "Tambah kontak" "add_contact": "Tambah kontak",
"exchange_provider_unsupported": "${providerName} tidak lagi didukung!"
} }

View file

@ -339,7 +339,6 @@
"template": "Modello", "template": "Modello",
"confirm_delete_template": "Questa azione cancellerà questo modello. Desideri continuare?", "confirm_delete_template": "Questa azione cancellerà questo modello. Desideri continuare?",
"confirm_delete_wallet": "Questa azione cancellerà questo portafoglio. Desideri continuare?", "confirm_delete_wallet": "Questa azione cancellerà questo portafoglio. Desideri continuare?",
"picker_description": "Per scegliere ChangeNOW o MorphToken, gentilmente cambia prima la tua coppia di valute",
"change_wallet_alert_title": "Cambia portafoglio attuale", "change_wallet_alert_title": "Cambia portafoglio attuale",
"change_wallet_alert_content": "Sei sicuro di voler cambiare il portafoglio attuale con ${wallet_name}?", "change_wallet_alert_content": "Sei sicuro di voler cambiare il portafoglio attuale con ${wallet_name}?",
"creating_new_wallet": "Creazione nuovo portafoglio", "creating_new_wallet": "Creazione nuovo portafoglio",
@ -726,5 +725,6 @@
"enterWalletConnectURI": "Inserisci l'URI di WalletConnect", "enterWalletConnectURI": "Inserisci l'URI di WalletConnect",
"seed_key": "Chiave di semi", "seed_key": "Chiave di semi",
"enter_seed_phrase": "Inserisci la tua frase di semi", "enter_seed_phrase": "Inserisci la tua frase di semi",
"add_contact": "Aggiungi contatto" "add_contact": "Aggiungi contatto",
"exchange_provider_unsupported": "${providerName} non è più supportato!"
} }

View file

@ -339,7 +339,6 @@
"template": "テンプレート", "template": "テンプレート",
"confirm_delete_template": "この操作により、このテンプレートが削除されます。 続行しますか?", "confirm_delete_template": "この操作により、このテンプレートが削除されます。 続行しますか?",
"confirm_delete_wallet": "このアクションにより、このウォレットが削除されます。 続行しますか?", "confirm_delete_wallet": "このアクションにより、このウォレットが削除されます。 続行しますか?",
"picker_description": "ChangeNOWまたはMorphTokenを選択するには、最初にトレーディングペアを変更してください",
"change_wallet_alert_title": "現在のウォレットを変更する", "change_wallet_alert_title": "現在のウォレットを変更する",
"change_wallet_alert_content": "現在のウォレットをに変更しますか ${wallet_name}?", "change_wallet_alert_content": "現在のウォレットをに変更しますか ${wallet_name}?",
"creating_new_wallet": "新しいウォレットの作成", "creating_new_wallet": "新しいウォレットの作成",
@ -726,5 +725,6 @@
"enterWalletConnectURI": "WalletConnect URI を入力してください", "enterWalletConnectURI": "WalletConnect URI を入力してください",
"seed_key": "シードキー", "seed_key": "シードキー",
"enter_seed_phrase": "シードフレーズを入力してください", "enter_seed_phrase": "シードフレーズを入力してください",
"add_contact": "連絡先を追加" "add_contact": "連絡先を追加",
"exchange_provider_unsupported": "${providerName}はサポートされなくなりました!"
} }

View file

@ -339,7 +339,6 @@
"template": "주형", "template": "주형",
"confirm_delete_template": "이 작업은이 템플릿을 삭제합니다. 계속 하시겠습니까?", "confirm_delete_template": "이 작업은이 템플릿을 삭제합니다. 계속 하시겠습니까?",
"confirm_delete_wallet": "이 작업은이 지갑을 삭제합니다. 계속 하시겠습니까?", "confirm_delete_wallet": "이 작업은이 지갑을 삭제합니다. 계속 하시겠습니까?",
"picker_description": "ChangeNOW 또는 MorphToken을 선택하려면 먼저 거래 쌍을 변경하십시오.",
"change_wallet_alert_title": "현재 지갑 변경", "change_wallet_alert_title": "현재 지갑 변경",
"change_wallet_alert_content": "현재 지갑을 다음으로 변경 하시겠습니까 ${wallet_name}?", "change_wallet_alert_content": "현재 지갑을 다음으로 변경 하시겠습니까 ${wallet_name}?",
"creating_new_wallet": "새 지갑 생성", "creating_new_wallet": "새 지갑 생성",
@ -724,5 +723,6 @@
"enterWalletConnectURI": "WalletConnect URI를 입력하세요.", "enterWalletConnectURI": "WalletConnect URI를 입력하세요.",
"seed_key": "시드 키", "seed_key": "시드 키",
"enter_seed_phrase": "시드 문구를 입력하십시오", "enter_seed_phrase": "시드 문구를 입력하십시오",
"add_contact": "주소록에 추가" "add_contact": "주소록에 추가",
"exchange_provider_unsupported": "${providerName}은 더 이상 지원되지 않습니다!"
} }

View file

@ -339,7 +339,6 @@
"template": "ပုံစံခွက်", "template": "ပုံစံခွက်",
"confirm_delete_template": "ဤလုပ်ဆောင်ချက်သည် ဤပုံစံပြားကို ဖျက်လိုက်ပါမည်။ ဆက်လုပ်လိုပါသလား။", "confirm_delete_template": "ဤလုပ်ဆောင်ချက်သည် ဤပုံစံပြားကို ဖျက်လိုက်ပါမည်။ ဆက်လုပ်လိုပါသလား။",
"confirm_delete_wallet": "ဤလုပ်ဆောင်ချက်သည် ဤပိုက်ဆံအိတ်ကို ဖျက်လိုက်ပါမည်။ ဆက်လုပ်လိုပါသလား။", "confirm_delete_wallet": "ဤလုပ်ဆောင်ချက်သည် ဤပိုက်ဆံအိတ်ကို ဖျက်လိုက်ပါမည်။ ဆက်လုပ်လိုပါသလား။",
"picker_description": "ChangeNOW သို့မဟုတ် MorphToken ကိုရွေးချယ်ရန်၊ ကျေးဇူးပြု၍ သင်၏ကုန်သွယ်မှုအတွဲကို ဦးစွာပြောင်းလဲပါ။",
"change_wallet_alert_title": "လက်ရှိပိုက်ဆံအိတ်ကို ပြောင်းပါ။", "change_wallet_alert_title": "လက်ရှိပိုက်ဆံအိတ်ကို ပြောင်းပါ။",
"change_wallet_alert_content": "လက်ရှိပိုက်ဆံအိတ်ကို ${wallet_name} သို့ ပြောင်းလိုပါသလား။", "change_wallet_alert_content": "လက်ရှိပိုက်ဆံအိတ်ကို ${wallet_name} သို့ ပြောင်းလိုပါသလား။",
"creating_new_wallet": "ပိုက်ဆံအိတ်အသစ်ဖန်တီးခြင်း။", "creating_new_wallet": "ပိုက်ဆံအိတ်အသစ်ဖန်တီးခြင်း။",
@ -724,5 +723,6 @@
"enterWalletConnectURI": "WalletConnect URI ကိုရိုက်ထည့်ပါ။", "enterWalletConnectURI": "WalletConnect URI ကိုရိုက်ထည့်ပါ။",
"seed_key": "မျိုးစေ့သော့", "seed_key": "မျိုးစေ့သော့",
"enter_seed_phrase": "သင့်ရဲ့မျိုးစေ့စကားစုကိုရိုက်ထည့်ပါ", "enter_seed_phrase": "သင့်ရဲ့မျိုးစေ့စကားစုကိုရိုက်ထည့်ပါ",
"add_contact": "အဆက်အသွယ်ထည့်ပါ။" "add_contact": "အဆက်အသွယ်ထည့်ပါ။",
"exchange_provider_unsupported": "${providerName} မရှိတော့ပါ!"
} }

View file

@ -339,7 +339,6 @@
"template": "Sjabloon", "template": "Sjabloon",
"confirm_delete_template": "Met deze actie wordt deze sjabloon verwijderd. Wilt u doorgaan?", "confirm_delete_template": "Met deze actie wordt deze sjabloon verwijderd. Wilt u doorgaan?",
"confirm_delete_wallet": "Met deze actie wordt deze portemonnee verwijderd. Wilt u doorgaan?", "confirm_delete_wallet": "Met deze actie wordt deze portemonnee verwijderd. Wilt u doorgaan?",
"picker_description": "Om ChangeNOW of MorphToken te kiezen, moet u eerst uw handelspaar wijzigen",
"change_wallet_alert_title": "Wijzig huidige portemonnee", "change_wallet_alert_title": "Wijzig huidige portemonnee",
"change_wallet_alert_content": "Wilt u de huidige portemonnee wijzigen in ${wallet_name}?", "change_wallet_alert_content": "Wilt u de huidige portemonnee wijzigen in ${wallet_name}?",
"creating_new_wallet": "Nieuwe portemonnee aanmaken", "creating_new_wallet": "Nieuwe portemonnee aanmaken",
@ -726,5 +725,6 @@
"enterWalletConnectURI": "Voer WalletConnect-URI in", "enterWalletConnectURI": "Voer WalletConnect-URI in",
"seed_key": "Zaadsleutel", "seed_key": "Zaadsleutel",
"enter_seed_phrase": "Voer uw zaadzin in", "enter_seed_phrase": "Voer uw zaadzin in",
"add_contact": "Contactpersoon toevoegen" "add_contact": "Contactpersoon toevoegen",
"exchange_provider_unsupported": "${providerName} wordt niet langer ondersteund!"
} }

View file

@ -339,7 +339,6 @@
"template": "Szablon", "template": "Szablon",
"confirm_delete_template": "Ta czynność usunie ten szablon. Czy chcesz kontynuować?", "confirm_delete_template": "Ta czynność usunie ten szablon. Czy chcesz kontynuować?",
"confirm_delete_wallet": "Ta czynność usunie ten portfel. Czy chcesz kontynuować?", "confirm_delete_wallet": "Ta czynność usunie ten portfel. Czy chcesz kontynuować?",
"picker_description": "Aby wybrać ChangeNOW lub MorphToken, najpierw zmień swoją parę handlową",
"change_wallet_alert_title": "Zmień obecny portfel", "change_wallet_alert_title": "Zmień obecny portfel",
"change_wallet_alert_content": "Czy chcesz zmienić obecny portfel na ${wallet_name}?", "change_wallet_alert_content": "Czy chcesz zmienić obecny portfel na ${wallet_name}?",
"creating_new_wallet": "Tworzenie nowego portfela", "creating_new_wallet": "Tworzenie nowego portfela",
@ -726,5 +725,6 @@
"enterWalletConnectURI": "Wprowadź identyfikator URI WalletConnect", "enterWalletConnectURI": "Wprowadź identyfikator URI WalletConnect",
"seed_key": "Klucz nasion", "seed_key": "Klucz nasion",
"enter_seed_phrase": "Wprowadź swoją frazę nasienną", "enter_seed_phrase": "Wprowadź swoją frazę nasienną",
"add_contact": "Dodaj kontakt" "add_contact": "Dodaj kontakt",
"exchange_provider_unsupported": "${providerName} nie jest już obsługiwany!"
} }

View file

@ -339,7 +339,6 @@
"template": "Modelo", "template": "Modelo",
"confirm_delete_template": "Esta ação excluirá este modelo. Você deseja continuar?", "confirm_delete_template": "Esta ação excluirá este modelo. Você deseja continuar?",
"confirm_delete_wallet": "Esta ação excluirá esta carteira. Você deseja continuar?", "confirm_delete_wallet": "Esta ação excluirá esta carteira. Você deseja continuar?",
"picker_description": "Para escolher ChangeNOW ou MorphToken, altere primeiro o seu par de negociação",
"change_wallet_alert_title": "Alterar carteira atual", "change_wallet_alert_title": "Alterar carteira atual",
"change_wallet_alert_content": "Quer mudar a carteira atual para ${wallet_name}?", "change_wallet_alert_content": "Quer mudar a carteira atual para ${wallet_name}?",
"creating_new_wallet": "Criando nova carteira", "creating_new_wallet": "Criando nova carteira",
@ -725,5 +724,6 @@
"enterWalletConnectURI": "Insira o URI do WalletConnect", "enterWalletConnectURI": "Insira o URI do WalletConnect",
"seed_key": "Chave de semente", "seed_key": "Chave de semente",
"enter_seed_phrase": "Digite sua frase de semente", "enter_seed_phrase": "Digite sua frase de semente",
"add_contact": "Adicionar contato" "add_contact": "Adicionar contato",
"exchange_provider_unsupported": "${providerName} não é mais suportado!"
} }

View file

@ -339,7 +339,6 @@
"template": "Шаблон", "template": "Шаблон",
"confirm_delete_template": "Это действие удалит шаблон. Вы хотите продолжить?", "confirm_delete_template": "Это действие удалит шаблон. Вы хотите продолжить?",
"confirm_delete_wallet": "Это действие удалит кошелек. Вы хотите продолжить?", "confirm_delete_wallet": "Это действие удалит кошелек. Вы хотите продолжить?",
"picker_description": "Чтобы выбрать ChangeNOW или MorphToken, сначала смените пару для обмена",
"change_wallet_alert_title": "Изменить текущий кошелек", "change_wallet_alert_title": "Изменить текущий кошелек",
"change_wallet_alert_content": "Вы хотите изменить текущий кошелек на ${wallet_name}?", "change_wallet_alert_content": "Вы хотите изменить текущий кошелек на ${wallet_name}?",
"creating_new_wallet": "Создание нового кошелька", "creating_new_wallet": "Создание нового кошелька",
@ -726,5 +725,6 @@
"enterWalletConnectURI": "Введите URI WalletConnect", "enterWalletConnectURI": "Введите URI WalletConnect",
"seed_key": "Ключ семян", "seed_key": "Ключ семян",
"enter_seed_phrase": "Введите свою семенную фразу", "enter_seed_phrase": "Введите свою семенную фразу",
"add_contact": "Добавить контакт" "add_contact": "Добавить контакт",
"exchange_provider_unsupported": "${providerName} больше не поддерживается!"
} }

View file

@ -339,7 +339,6 @@
"template": "แบบฟอร์ม", "template": "แบบฟอร์ม",
"confirm_delete_template": "การดำเนินการนี้จะลบแบบฟอร์มนี้ คุณต้องการดำเนินการต่อหรือไม่?", "confirm_delete_template": "การดำเนินการนี้จะลบแบบฟอร์มนี้ คุณต้องการดำเนินการต่อหรือไม่?",
"confirm_delete_wallet": "การดำเนินการนี้จะลบกระเป๋านี้ คุณต้องการดำเนินการต่อหรือไม่?", "confirm_delete_wallet": "การดำเนินการนี้จะลบกระเป๋านี้ คุณต้องการดำเนินการต่อหรือไม่?",
"picker_description": "ในการเลือก ChangeNOW หรือ MorphToken โปรดเปลี่ยนคู่แลกเปลี่ยนก่อน",
"change_wallet_alert_title": "เปลี่ยนกระเป๋าปัจจุบัน", "change_wallet_alert_title": "เปลี่ยนกระเป๋าปัจจุบัน",
"change_wallet_alert_content": "คุณต้องการเปลี่ยนกระเป๋าปัจจุบันเป็น ${wallet_name} หรือไม่?", "change_wallet_alert_content": "คุณต้องการเปลี่ยนกระเป๋าปัจจุบันเป็น ${wallet_name} หรือไม่?",
"creating_new_wallet": "กำลังสร้างกระเป๋าใหม่", "creating_new_wallet": "กำลังสร้างกระเป๋าใหม่",
@ -724,5 +723,6 @@
"enterWalletConnectURI": "เข้าสู่ WalletConnect URI", "enterWalletConnectURI": "เข้าสู่ WalletConnect URI",
"seed_key": "คีย์เมล็ดพันธุ์", "seed_key": "คีย์เมล็ดพันธุ์",
"enter_seed_phrase": "ป้อนวลีเมล็ดพันธุ์ของคุณ", "enter_seed_phrase": "ป้อนวลีเมล็ดพันธุ์ของคุณ",
"add_contact": "เพิ่มผู้ติดต่อ" "add_contact": "เพิ่มผู้ติดต่อ",
"exchange_provider_unsupported": "${providerName} ไม่ได้รับการสนับสนุนอีกต่อไป!"
} }

View file

@ -339,7 +339,6 @@
"template": "Template", "template": "Template",
"confirm_delete_template": "Ang pagkilos na ito ay tatanggalin ang template na ito. Nais mo bang magpatuloy?", "confirm_delete_template": "Ang pagkilos na ito ay tatanggalin ang template na ito. Nais mo bang magpatuloy?",
"confirm_delete_wallet": "Ang pagkilos na ito ay tatanggalin ang pitaka na ito. Nais mo bang magpatuloy?", "confirm_delete_wallet": "Ang pagkilos na ito ay tatanggalin ang pitaka na ito. Nais mo bang magpatuloy?",
"picker_description": "Upang pumili ng Changenow o MorphToken, mangyaring baguhin muna ang iyong pares ng kalakalan",
"change_wallet_alert_title": "Baguhin ang kasalukuyang pitaka", "change_wallet_alert_title": "Baguhin ang kasalukuyang pitaka",
"change_wallet_alert_content": "Nais mo bang baguhin ang kasalukuyang pitaka sa ${wallet_name}?", "change_wallet_alert_content": "Nais mo bang baguhin ang kasalukuyang pitaka sa ${wallet_name}?",
"creating_new_wallet": "Lumilikha ng bagong pitaka", "creating_new_wallet": "Lumilikha ng bagong pitaka",
@ -721,5 +720,6 @@
"enterWalletConnectURI": "Ilagay ang WalletConnect URI", "enterWalletConnectURI": "Ilagay ang WalletConnect URI",
"seed_key": "Seed Key", "seed_key": "Seed Key",
"enter_seed_phrase": "Ipasok ang iyong pariralang binhi", "enter_seed_phrase": "Ipasok ang iyong pariralang binhi",
"add_contact": "Magdagdag ng contact" "add_contact": "Magdagdag ng contact",
"exchange_provider_unsupported": "Ang ${providerName} ay hindi na suportado!"
} }

View file

@ -339,7 +339,6 @@
"template": "Şablon", "template": "Şablon",
"confirm_delete_template": "Bu eylem, bu şablonu silecek. Devam etmek istiyor musun?", "confirm_delete_template": "Bu eylem, bu şablonu silecek. Devam etmek istiyor musun?",
"confirm_delete_wallet": "Bu eylem, bu cüzdanı silecek. Devam etmek istiyor musun?", "confirm_delete_wallet": "Bu eylem, bu cüzdanı silecek. Devam etmek istiyor musun?",
"picker_description": "ChangeNOW veya MorphToken'ı seçmek için lütfen önce işlem paritenizi değiştirin",
"change_wallet_alert_title": "Şimdiki cüzdanı değiştir", "change_wallet_alert_title": "Şimdiki cüzdanı değiştir",
"change_wallet_alert_content": "Şimdiki cüzdanı ${wallet_name} cüzdanı ile değiştirmek istediğinden emin misin?", "change_wallet_alert_content": "Şimdiki cüzdanı ${wallet_name} cüzdanı ile değiştirmek istediğinden emin misin?",
"creating_new_wallet": "Cüzdan oluşturuluyor", "creating_new_wallet": "Cüzdan oluşturuluyor",
@ -724,5 +723,6 @@
"enterWalletConnectURI": "WalletConnect URI'sini girin", "enterWalletConnectURI": "WalletConnect URI'sini girin",
"seed_key": "Tohum", "seed_key": "Tohum",
"enter_seed_phrase": "Tohum ifadenizi girin", "enter_seed_phrase": "Tohum ifadenizi girin",
"add_contact": "Kişi ekle" "add_contact": "Kişi ekle",
"exchange_provider_unsupported": "${providerName} artık desteklenmiyor!"
} }

View file

@ -339,7 +339,6 @@
"template": "Шаблон", "template": "Шаблон",
"confirm_delete_template": "Ця дія видалить шаблон. Ви хочете продовжити?", "confirm_delete_template": "Ця дія видалить шаблон. Ви хочете продовжити?",
"confirm_delete_wallet": "Ця дія видалить гаманець. Ви хочете продовжити?", "confirm_delete_wallet": "Ця дія видалить гаманець. Ви хочете продовжити?",
"picker_description": "Щоб вибрати ChangeNOW або MorphToken, спочатку змініть пару для обміну",
"change_wallet_alert_title": "Змінити поточний гаманець", "change_wallet_alert_title": "Змінити поточний гаманець",
"change_wallet_alert_content": "Ви хочете змінити поточний гаманець на ${wallet_name}?", "change_wallet_alert_content": "Ви хочете змінити поточний гаманець на ${wallet_name}?",
"creating_new_wallet": "Створення нового гаманця", "creating_new_wallet": "Створення нового гаманця",
@ -726,5 +725,6 @@
"enterWalletConnectURI": "Введіть URI WalletConnect", "enterWalletConnectURI": "Введіть URI WalletConnect",
"seed_key": "Насіннєвий ключ", "seed_key": "Насіннєвий ключ",
"enter_seed_phrase": "Введіть свою насіннєву фразу", "enter_seed_phrase": "Введіть свою насіннєву фразу",
"add_contact": "Додати контакт" "add_contact": "Додати контакт",
"exchange_provider_unsupported": "${providerName} більше не підтримується!"
} }

View file

@ -340,7 +340,6 @@
"template": "سانچے", "template": "سانچے",
"confirm_delete_template": "یہ عمل اس ٹیمپلیٹ کو حذف کر دے گا۔ کیا آپ جاری رکھنا چاہتے ہیں؟", "confirm_delete_template": "یہ عمل اس ٹیمپلیٹ کو حذف کر دے گا۔ کیا آپ جاری رکھنا چاہتے ہیں؟",
"confirm_delete_wallet": "اس کارروائی سے یہ پرس حذف ہو جائے گا۔ کیا آپ جاری رکھنا چاہتے ہیں؟", "confirm_delete_wallet": "اس کارروائی سے یہ پرس حذف ہو جائے گا۔ کیا آپ جاری رکھنا چاہتے ہیں؟",
"picker_description": "ChangeNOW یا MorphToken کو منتخب کرنے کے لیے، براہ کرم پہلے اپنا تجارتی جوڑا تبدیل کریں۔",
"change_wallet_alert_title": "موجودہ پرس تبدیل کریں۔", "change_wallet_alert_title": "موجودہ پرس تبدیل کریں۔",
"change_wallet_alert_content": "کیا آپ موجودہ والیٹ کو ${wallet_name} میں تبدیل کرنا چاہتے ہیں؟", "change_wallet_alert_content": "کیا آپ موجودہ والیٹ کو ${wallet_name} میں تبدیل کرنا چاہتے ہیں؟",
"creating_new_wallet": "نیا پرس بنانا", "creating_new_wallet": "نیا پرس بنانا",
@ -718,5 +717,6 @@
"enterWalletConnectURI": "WalletConnect URI ۔ﮟﯾﺮﮐ ﺝﺭﺩ", "enterWalletConnectURI": "WalletConnect URI ۔ﮟﯾﺮﮐ ﺝﺭﺩ",
"seed_key": "بیج کی کلید", "seed_key": "بیج کی کلید",
"enter_seed_phrase": "اپنے بیج کا جملہ درج کریں", "enter_seed_phrase": "اپنے بیج کا جملہ درج کریں",
"add_contact": "۔ﮟﯾﺮﮐ ﻞﻣﺎﺷ ﮧﻄﺑﺍﺭ" "add_contact": "۔ﮟﯾﺮﮐ ﻞﻣﺎﺷ ﮧﻄﺑﺍﺭ",
"exchange_provider_unsupported": "${providerName} اب تعاون نہیں کیا جاتا ہے!"
} }

View file

@ -339,7 +339,6 @@
"template": "Àwòṣe", "template": "Àwòṣe",
"confirm_delete_template": "Ìṣe yìí máa yọ àwòṣe yìí kúrò. Ṣé ẹ fẹ́ tẹ̀síwájú?", "confirm_delete_template": "Ìṣe yìí máa yọ àwòṣe yìí kúrò. Ṣé ẹ fẹ́ tẹ̀síwájú?",
"confirm_delete_wallet": "Ìṣe yìí máa yọ àpamọ́wọ́ yìí kúrò. Ṣé ẹ fẹ́ tẹ̀síwájú?", "confirm_delete_wallet": "Ìṣe yìí máa yọ àpamọ́wọ́ yìí kúrò. Ṣé ẹ fẹ́ tẹ̀síwájú?",
"picker_description": "Ẹ jọ̀wọ́ pààrọ̀ owó tí ẹ pàṣípààrọ̀ jọ yín lákọ̀ọ́kọ́ kí ẹ yán ChangeNOW tàbí MorphToken",
"change_wallet_alert_title": "Ẹ pààrọ̀ àpamọ́wọ́ yìí", "change_wallet_alert_title": "Ẹ pààrọ̀ àpamọ́wọ́ yìí",
"change_wallet_alert_content": "Ṣe ẹ fẹ́ pààrọ̀ àpamọ́wọ́ yìí sí ${wallet_name}?", "change_wallet_alert_content": "Ṣe ẹ fẹ́ pààrọ̀ àpamọ́wọ́ yìí sí ${wallet_name}?",
"creating_new_wallet": "Ń dá àpamọ́wọ́ títun", "creating_new_wallet": "Ń dá àpamọ́wọ́ títun",
@ -720,5 +719,6 @@
"enterWalletConnectURI": "Tẹ WalletConnect URI sii", "enterWalletConnectURI": "Tẹ WalletConnect URI sii",
"seed_key": "Bọtini Ose", "seed_key": "Bọtini Ose",
"enter_seed_phrase": "Tẹ ọrọ-iru irugbin rẹ", "enter_seed_phrase": "Tẹ ọrọ-iru irugbin rẹ",
"add_contact": "Fi olubasọrọ kun" "add_contact": "Fi olubasọrọ kun",
"exchange_provider_unsupported": "${providerName} ko ni atilẹyin mọ!"
} }

View file

@ -338,7 +338,6 @@
"template": "模板", "template": "模板",
"confirm_delete_template": "此操作将刪除此模板。确定吗?", "confirm_delete_template": "此操作将刪除此模板。确定吗?",
"confirm_delete_wallet": "此操作将刪除此钱包。确定吗?", "confirm_delete_wallet": "此操作将刪除此钱包。确定吗?",
"picker_description": "要选择ChangeNOW或MorphToken请先更改您的交易币",
"change_wallet_alert_title": "更换当前钱包", "change_wallet_alert_title": "更换当前钱包",
"change_wallet_alert_content": "您是否想将当前钱包改为 ${wallet_name}?", "change_wallet_alert_content": "您是否想将当前钱包改为 ${wallet_name}?",
"creating_new_wallet": "创建新钱包", "creating_new_wallet": "创建新钱包",
@ -725,5 +724,6 @@
"enterWalletConnectURI": "输入 WalletConnect URI", "enterWalletConnectURI": "输入 WalletConnect URI",
"seed_key": "种子钥匙", "seed_key": "种子钥匙",
"enter_seed_phrase": "输入您的种子短语", "enter_seed_phrase": "输入您的种子短语",
"add_contact": "增加联系人" "add_contact": "增加联系人",
"exchange_provider_unsupported": "${providerName}不再支持!"
} }