diff --git a/.gitignore b/.gitignore
index 0580d006c..b5c6f1e12 100644
--- a/.gitignore
+++ b/.gitignore
@@ -97,4 +97,7 @@ android/app/.cxx/**
ios/Flutter/.last_build_id
/lib/generated/**
#**#
-/**/#**#
\ No newline at end of file
+/**/#**#
+
+**/google-services.json
+**/GoogleService-Info.plist
\ No newline at end of file
diff --git a/PRIVACY.md b/PRIVACY.md
index 5f20032b6..2ee87b344 100644
--- a/PRIVACY.md
+++ b/PRIVACY.md
@@ -1,6 +1,6 @@
Privacy Policy
-Last modified: February 23, 2021
+Last modified: May 21, 2021
Introduction
============
@@ -22,7 +22,7 @@ Definitions
- "App" means the software program provided by the Company, downloaded by You on any electronic device, named Cake Wallet.
- "Device" means any device that can access the App, such as a cell phone or tablet device.
- - "Node" means a full Monero or Bitcoin Node, which transmits data to your App for processing and synchronization, and to which your Device transmits transactions which you would like to submit to the Monero or Bitcoin networks.
+ - "Node" means a full Monero or Bitcoin or Litecoin Node, which transmits data to your App for processing and synchronization, and to which your Device transmits transactions which you would like to submit to the Monero or Bitcoin or Litecoin networks.
- "Cake Wallet Nodes" refers to the set of cryptocurrency nodes operated and maintained by Cake Technologies.
- "Service" refers to the App.
- "Third-party Service" refers to any service integrated into the Cake Wallet Application. This includes ChangeNow.
@@ -34,7 +34,7 @@ Information We Collect About You and How We Collect It
We collect several types of information from and about users of our App, including information:
- By which you may be personally identified, such as name, e-mail address, or and a/any other identifier by which you may be contacted online or offline ("personal information" or "Personal Data”), ONLY when you provide it to us;
- - Device IP address, the block height to which your wallet is synchronized, and any transactions which you use our Node to submit to the Monero or Bitcoin networks.
+ - Device IP address, the block height to which your wallet is synchronized, and any transactions which you use our Node to submit to the Monero or Bitcoin or Litecoin networks.
We collect this information:
- Directly from you when you provide it to us.
- Automatically as you use the App, if you use one of the Cake Wallet Nodes. Information collected automatically may include IP address and block height.
@@ -45,7 +45,7 @@ Information We Collect About You and How We Collect It
Data relating to your funds, and their security and privacy, remains on your device at ALL times. Your private keys, seeds, backup files, and wallet passcode are your own responsibility. This data is not received, collected, or stored by Cake Technologies at any time, for any reason.
- Personal Data collected through the Cake Wallet Nodes is limited to your device's IP address, the block height to which your wallet is synchronized, and any transactions which you use our Node to submit to the Monero or Bitcoin networks. Personal Data received by Cake Technologies in this manner is not stored for any length of time, and thus Cake Technologies is both unwilling to and incapable of sharing this data, or using it for any purpose beyond ensuring your appropriate connection to our Nodes.
+ Personal Data collected through the Cake Wallet Nodes is limited to your device's IP address, the block height to which your wallet is synchronized, and any transactions which you use our Node to submit to the Monero or Bitcoin or Litecoin networks. Personal Data received by Cake Technologies in this manner is not stored for any length of time, and thus Cake Technologies is both unwilling to and incapable of sharing this data, or using it for any purpose beyond ensuring your appropriate connection to our Nodes.
If you decide to use a Node offered by any third party, some of which we offer by default in the Cake Wallet Application, said third party will receive this Personal Data instead of Cake Technologies. We take no responsibility for the actions of any third-party Node offered within the Application. If you decide to synchronize your Wallet using your own Node, neither Cake Technologies nor any third party will have access to this Personal Data.
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 0c6a46dc4..ee68ec0db 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -24,6 +24,10 @@ if (flutterVersionName == null) {
apply plugin: 'com.android.application'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
+if (file("./google-services.json").exists()) {
+ apply plugin: 'com.google.gms.google-services'
+}
+
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
@@ -83,4 +87,6 @@ dependencies {
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
+ implementation 'com.google.firebase:firebase-core:19.0.0'
+ implementation 'com.google.firebase:firebase-messaging:19.0.0'
}
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index abf27576f..c53d1ea7b 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -7,6 +7,7 @@
-
diff --git a/android/app/src/main/java/com/cakewallet/cake_wallet/Application.java b/android/app/src/main/java/com/cakewallet/cake_wallet/Application.java
new file mode 100644
index 000000000..c3b51c14c
--- /dev/null
+++ b/android/app/src/main/java/com/cakewallet/cake_wallet/Application.java
@@ -0,0 +1,21 @@
+package com.cakewallet.cake_wallet;
+
+import io.flutter.app.FlutterApplication;
+import io.flutter.plugin.common.PluginRegistry;
+import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback;
+import io.flutter.plugins.GeneratedPluginRegistrant;
+import io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService;
+import io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin;
+
+public class Application extends FlutterApplication implements PluginRegistrantCallback {
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ FlutterFirebaseMessagingService.setPluginRegistrant(this);
+ }
+
+ @Override
+ public void registerWith(PluginRegistry registry) {
+ FirebaseMessagingPlugin.registerWith(registry.registrarFor("io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin"));
+ }
+}
\ No newline at end of file
diff --git a/android/build.gradle b/android/build.gradle
index 0baed694d..0d11c6b94 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -6,6 +6,7 @@ buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:3.5.4'
+ classpath 'com.google.gms:google-services:4.3.8'
}
}
diff --git a/assets/images/2.0x/github.png b/assets/images/2.0x/github.png
new file mode 100644
index 000000000..e80b428e5
Binary files /dev/null and b/assets/images/2.0x/github.png differ
diff --git a/assets/images/3.0x/github.png b/assets/images/3.0x/github.png
new file mode 100644
index 000000000..86b48e446
Binary files /dev/null and b/assets/images/3.0x/github.png differ
diff --git a/assets/images/github.png b/assets/images/github.png
new file mode 100644
index 000000000..847a269a2
Binary files /dev/null and b/assets/images/github.png differ
diff --git a/assets/images/moonpay-icon.png b/assets/images/moonpay-icon.png
new file mode 100644
index 000000000..3c0260108
Binary files /dev/null and b/assets/images/moonpay-icon.png differ
diff --git a/assets/text/Terms_of_Use.txt b/assets/text/Terms_of_Use.txt
index 4d6e6def4..dfb359f28 100644
--- a/assets/text/Terms_of_Use.txt
+++ b/assets/text/Terms_of_Use.txt
@@ -1,90 +1,188 @@
-Last Modified: March 1, 2021
+Last Modified: May 21, 2021
+
Acceptance of the Terms of Use
-These terms of use are entered into by and between You and Cake Technologies LLC ("Company," "we," or "us"). The following terms and conditions "Terms of Use") govern your access to and use of the Cake Wallet app, including any content, functionality, and services offered on or through the Cake Wallet app (the “App").
-Please read the Terms of Use carefully before you start to use the App. By using the App you accept and agree to be bound and abide by these Terms of Use and our Privacy Policy, , incorporated herein by reference. If you do not wish to agree to these Terms of Use or the Privacy Policy, you must not access or use the App.
+==============================
+ These terms of use are entered into by and between You and Cake Technologies LLC ("Company," "we," or "us"). The following terms and conditions "Terms of Use") govern your access to and use of the Cake Wallet app, including any content, functionality, and services offered on or through the Cake Wallet app (the “App").
+ Please read the Terms of Use carefully before you start to use the App. By using the App you accept and agree to be bound and abide by these Terms of Use and our Privacy Policy, , incorporated herein by reference. If you do not wish to agree to these Terms of Use or the Privacy Policy, you must not access or use the App.
+
Changes to the Terms of Use
-We may revise and update these Terms of Use from time to time in our sole discretion. All changes are effective immediately when we post them, and apply to all access to and use of the App thereafter.
-Your continued use of the App following the posting of revised Terms of Use means that you accept and agree to the changes. You are expected to check this page from time to time so you are aware of any changes, as they are binding on you.
+===========================
+
+ We may revise and update these Terms of Use from time to time in our sole discretion. All changes are effective immediately when we post them, and apply to all access to and use of the App thereafter.
+ Your continued use of the App following the posting of revised Terms of Use means that you accept and agree to the changes. You are expected to check this page from time to time so you are aware of any changes, as they are binding on you.
+
Accessing the App and Security
-We reserve the right to withdraw or amend this App, and any service or material we provide on the App, in our sole discretion without notice. We will not be liable if for any reason all or any part of the App is unavailable at any time or for any period.
-You are responsible for both:
-Making all arrangements necessary for you to have access to the App.
-Ensuring that all persons who access the App through your internet connection are aware of these Terms of Use and comply with them.
-To access the App or some of the resources it offers, you may be asked to provide certain registration details or other information. It is a condition of your use of the App that all the information you provide on the App is correct, current, and complete. You agree that all information you provide during the use of this App or otherwise, including, but not limited to, through the use of any interactive features on the App, is governed by our Privacy Policy, and you consent to all actions we take with respect to your information consistent with our Privacy Policy.
-If you choose, or are provided with, a seed or private keys for any wallet within the App, you must treat such information as confidential, and you MUST NOT disclose it to any other person or entity.
+==============================
+
+ We reserve the right to withdraw or amend this App, and any service or material we provide on the App, in our sole discretion without notice. We will not be liable if for any reason all or any part of the App is unavailable at any time or for any period.
+
+ You are responsible for the following:
+
+ - Making all arrangements necessary for you to have access to the App.
+
+ - Ensuring that all persons who access the App through your internet connection are aware of these Terms of Use and comply with them.
+
+ - To access the App or some of the resources it offers, you may be asked to provide certain registration details or other information. It is a condition of your use of the App that all the information you provide on the App is correct, current, and complete. You agree that all information you provide during the use of this App or otherwise, including, but not limited to, through the use of any interactive features on the App, is governed by our Privacy Policy, and you consent to all actions we take with respect to your information consistent with our Privacy Policy.
+
+ - If you choose, or are provided with, a seed or private keys for any wallet within the App, you MUST treat such information as confidential, and you MUST NOT disclose it to any other person or entity.
+
+ - You MUST keep the app up to date. Failure to update the Cake Wallet application means you will not be receiving the latest security fixes and features.
+
Intellectual Property Rights
-The App and its entire contents, features, and functionality (including but not limited to all information, software, text, displays, images, video, and audio, and the design, selection, and arrangement thereof) are owned by the Company, its licensors, or other providers of such material and are protected by United States and international copyright, trademark, patent, trade secret, and other intellectual property or proprietary rights laws.
-These Terms of Use permit you to use the App for your personal and commercial use. You are permitted to download, store, publicly display, publicly perform, republish and transmit any of the code in our App.
-You are also permitted to reproduce, distribute, modify, or create derivative works of, any of the code in our App, under the condition that any derivative work of this App remains under an open source license.
-You must not:
-Modify copies of any images from the Application.
-Use any illustrations, photographs, video or audio sequences, or any graphics separately from the accompanying text.
-Delete or modify any copyright, trademark, or other rights notices from copies of materials from this site.
-Claim ownership of any code, image, text or any other information authored or created by Cake Technologies.
+============================
+
+ The App and its entire contents, features, and functionality (including but not limited to all information, software, text, displays, images, video, and audio, and the design, selection, and arrangement thereof) are owned by the Company, its licensors, or other providers of such material and are protected by United States and international copyright, trademark, patent, trade secret, and other intellectual property or proprietary rights laws.
+
+ These Terms of Use permit you to use the App for your personal and commercial use. You are permitted to download, store, publicly display, publicly perform, republish and transmit any of the code in our App.
+ You are also permitted to reproduce, distribute, modify, or create derivative works of, any of the code in our App, under the condition that any derivative work of this App remains under an open source license.
+
+ You must not:
+ - Modify copies of any images from the Application.
+ - Use any illustrations, photographs, video or audio sequences, or any graphics separately from the accompanying text.
+ - Delete or modify any copyright, trademark, or other rights notices from copies of materials from this site.
+ - Claim ownership of any code, image, text or any other information authored or created by Cake Technologies.
Trademarks
-The Company name, the term Cake Wallet, the Company logo, and all related names, logos, product and service names, designs, and slogans are trademarks of the Company or its affiliates or licensors. You must not use such marks without the prior written permission of the Company. All other names, logos, product and service names, designs, and slogans on this App are the trademarks of their respective owners.
+==========
+
+ The Company name, the term Cake Wallet, the Company logo, and all related names, logos, product and service names, designs, and slogans are trademarks of the Company or its affiliates or licensors. You must not use such marks without the prior written permission of the Company. All other names, logos, product and service names, designs, and slogans on this App are the trademarks of their respective owners.
+
Prohibited Uses
-You may use the App only for lawful purposes and in accordance with these Terms of Use. You agree not to use the App:
-In any way that violates any applicable federal, state, local, or international law or regulation (including, without limitation, any laws regarding the export of data or software to and from the US or other countries).
-For the purpose of exploiting, harming, or attempting to exploit or harm minors in any way by exposing them to inappropriate content, asking for personally identifiable information, or otherwise.
-To impersonate or attempt to impersonate the Company, a Company employee, another user, or any other person or entity (including, without limitation, by using email addresses associated with any of the foregoing).
-To engage in any other conduct that restricts or inhibits anyone's use or enjoyment of the App, or which, as determined by us, may harm the Company or users of the App, or expose them to liability.
-Additionally, you agree not to:
-Use the App in any manner that could disable, overburden, damage, or impair the App or interfere with any other party's use of the App, including their ability to engage in real time activities through the App.
-Use any robot, spider, or other automatic device, process, or means to access the App for any purpose, including monitoring or copying any of the material on the App.
-Use any manual process to monitor or copy any of the material on the App, or for any other purpose not expressly authorized in these Terms of Use, without our prior written consent.
-Use any device, software, or routine that interferes with the proper working of the App or the Nodes operated by Cake Technologies.
-Introduce any viruses, Trojan horses, worms, logic bombs, or other material that is malicious or technologically harmful.
-Attempt to gain unauthorized access to, interfere with, damage, or disrupt any parts of the App, or any node, server, computer, or database connected to the App.
-Attack the App or the Nodes operated by Cake Technologies via a denial-of-service attack or a distributed denial-of-service attack.
-Otherwise attempt to interfere with the proper working of the App or the Nodes operated by Cake Technologies.
+===============
+ You may use the App only for lawful purposes and in accordance with these Terms of Use. You agree not to use the App:
+
+ - In any way that violates any applicable federal, state, local, or international law or regulation (including, without limitation, any laws regarding the export of data or software to and from the US or other countries).
+
+ - For the purpose of exploiting, harming, or attempting to exploit or harm minors in any way by exposing them to inappropriate content, asking for personally identifiable information, or otherwise.
+
+ - To impersonate or attempt to impersonate the Company, a Company employee, another user, or any other person or entity (including, without limitation, by using email addresses associated with any of the foregoing).
+
+ - To engage in any other conduct that restricts or inhibits anyone's use or enjoyment of the App, or which, as determined by us, may harm the Company or users of the App, or expose them to liability.
+
+ Additionally, you agree not to:
+
+ - Use the App in any manner that could disable, overburden, damage, or impair the App or interfere with any other party's use of the App, including their ability to engage in real time activities through the App.
+
+ - Use any robot, spider, or other automatic device, process, or means to access the App for any purpose, including monitoring or copying any of the material on the App.
+
+ - Use any manual process to monitor or copy any of the material on the App, or for any other purpose not expressly authorized in these Terms of Use, without our prior written consent.
+
+ - Use any device, software, or routine that interferes with the proper working of the App or the Nodes operated by Cake Technologies.
+
+ - Introduce any viruses, Trojan horses, worms, logic bombs, or other material that is malicious or technologically harmful.
+
+ - Attempt to gain unauthorized access to, interfere with, damage, or disrupt any parts of the App, or any node, server, computer, or database connected to the App.
+
+ - Attack the App or the Nodes operated by Cake Technologies via a denial-of-service attack or a distributed denial-of-service attack.
+
+ - Otherwise attempt to interfere with the proper working of the App or the Nodes operated by Cake Technologies.
+
Information About You and Your Visits to the App
-All information we collect on this App is subject to our Privacy Policy. By using the App, you consent to all actions taken by us with respect to your information in compliance with the Privacy Policy.
+================================================
+
+ All information we collect on this App is subject to our Privacy Policy. By using the App, you consent to all actions taken by us with respect to your information in compliance with the Privacy Policy.
+
Links from the App
-If the App contains links to other sites and resources provided by third parties, these links are provided for your convenience only. We have no control over the contents of those sites or resources, and accept no responsibility for them or for any loss or damage that may arise from your use of them. If you decide to access any of the third-party Apps or services linked to this App, you do so entirely at your own risk and subject to the terms and conditions of use for such Apps.
+==================
+
+ If the App contains links to other sites and resources provided by third parties, these links are provided for your convenience only. We have no control over the contents of those sites or resources, and accept no responsibility for them or for any loss or damage that may arise from your use of them. If you decide to access any of the third-party Apps or services linked to this App, you do so entirely at your own risk and subject to the terms and conditions of use for such Apps.
Geographic Restrictions
-The owner of the App is based in the State of Florida in the United States. Please consult with qualified legal counsel to assess the appropriate use of the App or any of its contents in the jurisdiction(s) you intend to use the App. The owner of the App makes no representation or warranty as to the suitability for use, compliance or other matter of law with respect to use in any jurisdiction. If you access the App from outside the United States, you do so on your own initiative and are responsible for compliance with local laws and regulations.
+=======================
+
+ The owner of the App is based in the State of Florida in the United States. Please consult with qualified legal counsel to assess the appropriate use of the App or any of its contents in the jurisdiction(s) you intend to use the App. The owner of the App makes no representation or warranty as to the suitability for use, compliance or other matter of law with respect to use in any jurisdiction. If you access the App from outside the United States, you do so on your own initiative and are responsible for compliance with local laws and regulations.
+
Translations
-The App may contain translations of the English version of the content available on the App. These translations are provided only as a convenience. In the event of any conflict between the English language version and the translated version, the English language version shall take precedence. If you notice any inconsistencies, please report them on GitHub.
+============
+
+ The App may contain translations of the English version of the content available on the App. These translations are provided only as a convenience. In the event of any conflict between the English language version and the translated version, the English language version shall take precedence. If you notice any inconsistencies, please report them on GitHub.
+
Risks Related to the use of the App
-The App, the Company and the Company’s owners, partners, employees, contributors, and any affiliates will not be responsible for any losses, damages or claims arising from:
-Mistakes made by the user of any Monero-related and/or Bitcoin-related software or service, e.g., forgotten passwords, payments sent to wrong Monero and/or Bitcoin addresses, or accidental deletion of wallets;
-Software problems of the App and/or any Monero-related or Bitcoin-related software or service, e.g., corrupted wallet file, incorrectly constructed transactions, unsafe cryptographic libraries, malware affecting the App and/or any Monero-related or Bitcoin-related software or service;
-Technical failures in the hardware of the user of any Monero-related or Bitcoin-related software or service, e.g., data loss due to a faulty or damaged storage device;
-Security problems experienced by the user of any Monero-related and/or Bitcoin-related software or service, e.g., unauthorized access to users' wallets and/or accounts; or
-Actions or inactions of third parties and/or events experienced by third parties, e.g., bankruptcy of service providers, information security attacks on service providers, and fraud conducted by third parties.
+===================================
+
+ The App, the Company and the Company’s owners, partners, employees, contributors, and any affiliates will not be responsible for any losses, damages or claims arising from:
+
+ - Mistakes made by the user of any Monero-related and/or Bitcoin-related and/or Litecoin-related software or service, e.g., forgotten passwords, payments sent to wrong Monero and/or Bitcoin and/or Litecoin addresses, or accidental deletion of wallets;
+
+ - Software problems of the App and/or any Monero-related or Bitcoin-related or Litecoin-related oftware or service, e.g., corrupted wallet file, incorrectly constructed transactions, unsafe cryptographic libraries, malware affecting the App and/or any Monero-related or Bitcoin-related or Litecoin-related software or service;
+
+ - Technical failures in the hardware of the user of any Monero-related and/or Bitcoin-related and/or Litecoin-related software or service, e.g., data loss due to a faulty or damaged storage device;
+
+ - Security problems experienced by the user of any Monero-related and/or Bitcoin-related and/or Litecoin-related software or service, e.g., unauthorized access to users' wallets and/or accounts; or
+
+ - Actions or inactions of third parties and/or events experienced by third parties, e.g., bankruptcy of service providers, information security attacks on service providers, and fraud conducted by third parties.
+
Investment Risks
-All investments, including investments in Monero and Bitcoin, are speculative in nature and involve substantial risk of loss. We encourage investors to invest carefully. We also encourage investors to get personal advice from professional investment advisors and to make independent investigations before making any investment. We do not in any way guarantee the success of any action you take with respect to investments on the App or otherwise. Past performance is not necessarily indicative of future results. All investments, including investments in Monero or Bitcoin, carry risk and all investment decisions of an individual remain the responsibility of that individual. Do not enter any investment without fully understanding the worst-case scenario of that investment, including but not limited to, large market fluctuations or total loss.
+================
+
+ All investments, including investments in Monero, Litecoin and Bitcoin, are speculative in nature and involve substantial risk of loss. We encourage investors to invest carefully. We also encourage investors to get personal advice from professional investment advisors and to make independent investigations before making any investment. We do not in any way guarantee the success of any action you take with respect to investments on the App or otherwise. Past performance is not necessarily indicative of future results. All investments, including investments in Monero, Litecoin or Bitcoin, carry risk and all investment decisions of an individual remain the responsibility of that individual. Do not enter any investment without fully understanding the worst-case scenario of that investment, including but not limited to, large market fluctuations or total loss.
+
Tax Matters
-The users of the App are solely responsible in determining what, if any, taxes apply to their Monero and/or Bitcoin transactions. Cake Technologies is not responsible for determining any taxes that apply to such transactions. You agree not to hold Cake Technologies responsible for any issues relating to the taxation of purchases, sale, exchanges, transfers, or any other transactions related to any cryptocurrency.
-Monero & Bitcoin Transactions
-The App does not store Monero or Bitcoin. Monero and Bitcoin exist only by virtue of the ownership record maintained in the Monero and Bitcoin networks. Any transfer of title in Monero or Bitcoin occurs within a decentralized Monero or Bitcoin network, and not in the App.
+===========
+
+ The users of the App are solely responsible in determining what, if any, taxes apply to their Monero, Litecoin and/or Bitcoin transactions. Cake Technologies is not responsible for determining any taxes that apply to such transactions. You agree not to hold Cake Technologies responsible for any issues relating to the taxation of purchases, sale, exchanges, transfers, or any other transactions related to any cryptocurrency.
+
+Monero, Bitcoin & Litecoin Transactions
+=======================================
+
+ The App does not store Monero, Litecoin or Bitcoin. Monero, Litecoin and Bitcoin exist only by virtue of the ownership record maintained in the Monero, Litecoin and Bitcoin networks. Any transfer of title in Monero, Litecoin or Bitcoin occurs within a decentralized Monero, Litecoin or Bitcoin network, and not in the App.
Disclaimer of Warranties
-You understand that we cannot and do not guarantee or warrant that files available for downloading from the internet or the App will be free of viruses or other destructive code. You are responsible for implementing sufficient procedures and checkpoints to satisfy your particular requirements for anti-virus protection and accuracy of data input and output, and for maintaining a means external to our site for any reconstruction of any lost data. TO THE FULLEST EXTENT PROVIDED BY LAW, WE WILL NOT BE LIABLE FOR ANY LOSS OR DAMAGE CAUSED BY A DISTRIBUTED DENIAL-OF-SERVICE ATTACK, VIRUSES, OR OTHER TECHNOLOGICALLY HARMFUL MATERIAL THAT MAY INFECT YOUR COMPUTER EQUIPMENT, COMPUTER PROGRAMS, DATA, OR OTHER PROPRIETARY MATERIAL DUE TO YOUR USE OF THE APP OR ANY SERVICES OR ITEMS OBTAINED THROUGH THE APP OR TO YOUR DOWNLOADING OF ANY MATERIAL POSTED ON IT, OR ON ANY APP LINKED TO IT.
-YOUR USE OF THE APP, ITS CONTENT, AND ANY SERVICES OR ITEMS OBTAINED THROUGH THE APP IS AT YOUR OWN RISK. THE APP, ITS CONTENT, AND ANY SERVICES OR ITEMS OBTAINED THROUGH THE APP ARE PROVIDED ON AN "AS IS" AND "AS AVAILABLE" BASIS, WITHOUT ANY WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED. NEITHER THE COMPANY NOR ANY PERSON ASSOCIATED WITH THE COMPANY MAKES ANY WARRANTY OR REPRESENTATION WITH RESPECT TO THE COMPLETENESS, SECURITY, RELIABILITY, QUALITY, ACCURACY, OR AVAILABILITY OF THE APP. WITHOUT LIMITING THE FOREGOING, NEITHER THE COMPANY NOR ANYONE ASSOCIATED WITH THE COMPANY REPRESENTS OR WARRANTS THAT THE APP, ITS CONTENT, OR ANY SERVICES OR ITEMS OBTAINED THROUGH THE APP WILL BE ACCURATE, RELIABLE, ERROR-FREE, OR UNINTERRUPTED, THAT DEFECTS WILL BE CORRECTED, THAT OUR SITE OR THE SERVER THAT MAKES IT AVAILABLE ARE FREE OF VIRUSES OR OTHER HARMFUL COMPONENTS, OR THAT THE APP OR ANY SERVICES OR ITEMS OBTAINED THROUGH THE APP WILL OTHERWISE MEET YOUR NEEDS OR EXPECTATIONS.
-TO THE FULLEST EXTENT PROVIDED BY LAW, THE COMPANY HEREBY DISCLAIMS ALL WARRANTIES OF ANY KIND, WHETHER EXPRESS OR IMPLIED, STATUTORY, OR OTHERWISE, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT, AND FITNESS FOR PARTICULAR PURPOSE. THE APP IS PROVIDED ON AN “AS IS” BASIS.
-THE FOREGOING DOES NOT AFFECT ANY WARRANTIES THAT CANNOT BE EXCLUDED OR LIMITED UNDER APPLICABLE LAW.
+========================
+
+ You understand that we cannot and do not guarantee or warrant that files available for downloading from the internet or the App will be free of viruses or other destructive code. You are responsible for implementing sufficient procedures and checkpoints to satisfy your particular requirements for anti-virus protection and accuracy of data input and output, and for maintaining a means external to our site for any reconstruction of any lost data. TO THE FULLEST EXTENT PROVIDED BY LAW, WE WILL NOT BE LIABLE FOR ANY LOSS OR DAMAGE CAUSED BY A DISTRIBUTED DENIAL-OF-SERVICE ATTACK, VIRUSES, OR OTHER TECHNOLOGICALLY HARMFUL MATERIAL THAT MAY INFECT YOUR COMPUTER EQUIPMENT, COMPUTER PROGRAMS, DATA, OR OTHER PROPRIETARY MATERIAL DUE TO YOUR USE OF THE APP OR ANY SERVICES OR ITEMS OBTAINED THROUGH THE APP OR TO YOUR DOWNLOADING OF ANY MATERIAL POSTED ON IT, OR ON ANY APP LINKED TO IT.
+
+ YOUR USE OF THE APP, ITS CONTENT, AND ANY SERVICES OR ITEMS OBTAINED THROUGH THE APP IS AT YOUR OWN RISK. THE APP, ITS CONTENT, AND ANY SERVICES OR ITEMS OBTAINED THROUGH THE APP ARE PROVIDED ON AN "AS IS" AND "AS AVAILABLE" BASIS, WITHOUT ANY WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED. NEITHER THE COMPANY NOR ANY PERSON ASSOCIATED WITH THE COMPANY MAKES ANY WARRANTY OR REPRESENTATION WITH RESPECT TO THE COMPLETENESS, SECURITY, RELIABILITY, QUALITY, ACCURACY, OR AVAILABILITY OF THE APP. WITHOUT LIMITING THE FOREGOING, NEITHER THE COMPANY NOR ANYONE ASSOCIATED WITH THE COMPANY REPRESENTS OR WARRANTS THAT THE APP, ITS CONTENT, OR ANY SERVICES OR ITEMS OBTAINED THROUGH THE APP WILL BE ACCURATE, RELIABLE, ERROR-FREE, OR UNINTERRUPTED, THAT DEFECTS WILL BE CORRECTED, THAT OUR SITE OR THE SERVER THAT MAKES IT AVAILABLE ARE FREE OF VIRUSES OR OTHER HARMFUL COMPONENTS, OR THAT THE APP OR ANY SERVICES OR ITEMS OBTAINED THROUGH THE APP WILL OTHERWISE MEET YOUR NEEDS OR EXPECTATIONS.
+
+ TO THE FULLEST EXTENT PROVIDED BY LAW, THE COMPANY HEREBY DISCLAIMS ALL WARRANTIES OF ANY KIND, WHETHER EXPRESS OR IMPLIED, STATUTORY, OR OTHERWISE, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT, AND FITNESS FOR PARTICULAR PURPOSE. THE APP IS PROVIDED ON AN “AS IS” BASIS.
+
+ THE FOREGOING DOES NOT AFFECT ANY WARRANTIES THAT CANNOT BE EXCLUDED OR LIMITED UNDER APPLICABLE LAW.
+
Limitation on Liability
-TO THE FULLEST EXTENT PROVIDED BY LAW, IN NO EVENT WILL THE COMPANY, ITS AFFILIATES, OR THEIR LICENSORS, SERVICE PROVIDERS, EMPLOYEES, AGENTS, OFFICERS, OR DIRECTORS BE LIABLE FOR DAMAGES OF ANY KIND, UNDER ANY LEGAL THEORY, ARISING OUT OF OR IN CONNECTION WITH YOUR USE, OR INABILITY TO USE, THE APP, ANY APPS LINKED TO IT, ANY CONTENT ON THE APP OR SUCH OTHER APPS, INCLUDING ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL, CONSEQUENTIAL, OR PUNITIVE DAMAGES, INCLUDING BUT NOT LIMITED TO, PERSONAL INJURY, PAIN AND SUFFERING, EMOTIONAL DISTRESS, LOSS OF REVENUE, LOSS OF PROFITS, LOSS OF BUSINESS OR ANTICIPATED SAVINGS, LOSS OF USE, LOSS OF GOODWILL, LOSS OF DATA, AND WHETHER CAUSED BY TORT (INCLUDING NEGLIGENCE), BREACH OF CONTRACT, OR OTHERWISE, EVEN IF FORESEEABLE.
-The limitation of liability set out above does not apply to liability resulting from our gross negligence or willful misconduct.
-THE FOREGOING DOES NOT AFFECT ANY LIABILITY THAT CANNOT BE EXCLUDED OR LIMITED UNDER APPLICABLE LAW.
+=======================
+
+ TO THE FULLEST EXTENT PROVIDED BY LAW, IN NO EVENT WILL THE COMPANY, ITS AFFILIATES, OR THEIR LICENSORS, SERVICE PROVIDERS, EMPLOYEES, AGENTS, OFFICERS, OR DIRECTORS BE LIABLE FOR DAMAGES OF ANY KIND, UNDER ANY LEGAL THEORY, ARISING OUT OF OR IN CONNECTION WITH YOUR USE, OR INABILITY TO USE, THE APP, ANY APPS LINKED TO IT, ANY CONTENT ON THE APP OR SUCH OTHER APPS, INCLUDING ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL, CONSEQUENTIAL, OR PUNITIVE DAMAGES, INCLUDING BUT NOT LIMITED TO, PERSONAL INJURY, PAIN AND SUFFERING, EMOTIONAL DISTRESS, LOSS OF REVENUE, LOSS OF PROFITS, LOSS OF BUSINESS OR ANTICIPATED SAVINGS, LOSS OF USE, LOSS OF GOODWILL, LOSS OF DATA, AND WHETHER CAUSED BY TORT (INCLUDING NEGLIGENCE), BREACH OF CONTRACT, OR OTHERWISE, EVEN IF FORESEEABLE.
+
+ The limitation of liability set out above does not apply to liability resulting from our gross negligence or willful misconduct.
+
+ THE FOREGOING DOES NOT AFFECT ANY LIABILITY THAT CANNOT BE EXCLUDED OR LIMITED UNDER APPLICABLE LAW.
+
Indemnification
-You agree to defend, indemnify, and hold harmless the Company, its affiliates, licensors, and service providers, and its and their respective officers, directors, employees, contractors, agents, licensors, suppliers, successors, and assigns from and against any claims, liabilities, damages, judgments, awards, losses, costs, expenses, or fees (including reasonable attorneys' fees) arising out of or relating to your violation of these Terms of Use or your use of the App, including, but not limited to, your User Contributions, any use of the App's content, services, and products other than as expressly authorized in these Terms of Use, or your use of any information obtained from the App.
+===============
+
+ You agree to defend, indemnify, and hold harmless the Company, its affiliates, licensors, and service providers, and its and their respective officers, directors, employees, contractors, agents, licensors, suppliers, successors, and assigns from and against any claims, liabilities, damages, judgments, awards, losses, costs, expenses, or fees (including reasonable attorneys' fees) arising out of or relating to your violation of these Terms of Use or your use of the App, including, but not limited to, your User Contributions, any use of the App's content, services, and products other than as expressly authorized in these Terms of Use, or your use of any information obtained from the App.
+
Governing Law and Jurisdiction
-All matters relating to the App and these Terms of Use, and any dispute or claim arising therefrom or related thereto (in each case, including non-contractual disputes or claims), shall be governed by and construed in accordance with the internal laws of the State of Florida without giving effect to any choice or conflict of law provision or rule (whether of the State of Florida or any other jurisdiction).
-Any legal suit, action, or proceeding arising out of, or related to, these Terms of Use or the App shall be instituted exclusively in the federal courts of the United States or the courts of the State of Florida, although we retain the right to bring any suit, action, or proceeding against you for breach of these Terms of Use in your country of residence or any other relevant country. You waive any and all objections to the exercise of jurisdiction over you by such courts and to venue in such courts.
+==============================
+
+ All matters relating to the App and these Terms of Use, and any dispute or claim arising therefrom or related thereto (in each case, including non-contractual disputes or claims), shall be governed by and construed in accordance with the internal laws of the State of Florida without giving effect to any choice or conflict of law provision or rule (whether of the State of Florida or any other jurisdiction).
+
+ Any legal suit, action, or proceeding arising out of, or related to, these Terms of Use or the App shall be instituted exclusively in the federal courts of the United States or the courts of the State of Florida, although we retain the right to bring any suit, action, or proceeding against you for breach of these Terms of Use in your country of residence or any other relevant country. You waive any and all objections to the exercise of jurisdiction over you by such courts and to venue in such courts.
+
Arbitration
-At Company's sole discretion, it may require You to submit any disputes arising from these Terms of Use or use of the App, including disputes arising from or concerning their interpretation, violation, invalidity, non-performance, or termination, to final and binding arbitration under the Rules of Arbitration of the American Arbitration Association applying Florida law.
+===========
+
+ At Company's sole discretion, it may require You to submit any disputes arising from these Terms of Use or use of the App, including disputes arising from or concerning their interpretation, violation, invalidity, non-performance, or termination, to final and binding arbitration under the Rules of Arbitration of the American Arbitration Association applying Florida law.
+
Limitation on Time to File Claims
+=================================
+
ANY CAUSE OF ACTION OR CLAIM YOU MAY HAVE ARISING OUT OF OR RELATING TO THESE TERMS OF USE OR THE APP MUST BE COMMENCED WITHIN ONE (1) YEAR AFTER THE CAUSE OF ACTION ACCRUES; OTHERWISE, SUCH CAUSE OF ACTION OR CLAIM IS PERMANENTLY BARRED.
+
Waiver and Severability
-No waiver by the Company of any term or condition set out in these Terms of Use shall be deemed a further or continuing waiver of such term or condition or a waiver of any other term or condition, and any failure of the Company to assert a right or provision under these Terms of Use shall not constitute a waiver of such right or provision.
-If any provision of these Terms of Use is held by a court or other tribunal of competent jurisdiction to be invalid, illegal, or unenforceable for any reason, such provision shall be eliminated or limited to the minimum extent such that the remaining provisions of the Terms of Use will continue in full force and effect.
+=======================
+
+ No waiver by the Company of any term or condition set out in these Terms of Use shall be deemed a further or continuing waiver of such term or condition or a waiver of any other term or condition, and any failure of the Company to assert a right or provision under these Terms of Use shall not constitute a waiver of such right or provision.
+
+ If any provision of these Terms of Use is held by a court or other tribunal of competent jurisdiction to be invalid, illegal, or unenforceable for any reason, such provision shall be eliminated or limited to the minimum extent such that the remaining provisions of the Terms of Use will continue in full force and effect.
+
Entire Agreement
-The Terms of Use and our Privacy Policy constitute the sole and entire agreement between you and Cake Technologies Inc. regarding the App and supersede all prior and contemporaneous understandings, agreements, representations, and warranties, both written and oral, regarding the App.
+================
+
+ The Terms of Use and our Privacy Policy constitute the sole and entire agreement between you and Cake Technologies Inc. regarding the App and supersede all prior and contemporaneous understandings, agreements, representations, and warranties, both written and oral, regarding the App.
+
Your Comments and Concerns
-This App is operated by Cake Technologies Inc.
-All feedback, comments, requests for technical support, and other communications relating to the App should be directed to info@cakewallet.com.
+==========================
+
+ This App is operated by Cake Technologies Inc.
+ All feedback, comments, and other communications relating to the App should be directed to info@cakewallet.com. All requests for technical support should be directed to support@cakewallet.com.
diff --git a/cw_monero/ios/Classes/monero_api.cpp b/cw_monero/ios/Classes/monero_api.cpp
index dd1ab3cbb..d58f4e509 100644
--- a/cw_monero/ios/Classes/monero_api.cpp
+++ b/cw_monero/ios/Classes/monero_api.cpp
@@ -134,6 +134,7 @@ extern "C"
uint32_t subaddrAccount;
int8_t direction;
int8_t isPending;
+ uint32_t subaddrIndex;
char *hash;
char *paymentId;
@@ -146,6 +147,8 @@ extern "C"
fee = transaction->fee();
blockHeight = transaction->blockHeight();
subaddrAccount = transaction->subaddrAccount();
+ std::set::iterator it = transaction->subaddrIndex().begin();
+ subaddrIndex = *it;
confirmations = transaction->confirmations();
datetime = static_cast(transaction->timestamp());
direction = transaction->direction();
diff --git a/cw_monero/lib/structs/transaction_info_row.dart b/cw_monero/lib/structs/transaction_info_row.dart
index 0a0613a42..37b0d02e8 100644
--- a/cw_monero/lib/structs/transaction_info_row.dart
+++ b/cw_monero/lib/structs/transaction_info_row.dart
@@ -23,6 +23,9 @@ class TransactionInfoRow extends Struct {
@Int8()
int isPending;
+ @Uint32()
+ int subaddrIndex;
+
Pointer hash;
Pointer paymentId;
diff --git a/ios/Podfile b/ios/Podfile
index e26de900c..3cfff7b1d 100644
--- a/ios/Podfile
+++ b/ios/Podfile
@@ -36,6 +36,7 @@ target 'Runner' do
# Cake Wallet (Legacy)
pod 'CryptoSwift'
+ pod 'Firebase/Messaging', '6.33.0'
end
post_install do |installer|
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index 879041cac..50f9b20d2 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -62,18 +62,84 @@ PODS:
- file_picker (0.0.1):
- DKImagePickerController/PhotoGallery
- Flutter
+ - Firebase/CoreOnly (6.33.0):
+ - FirebaseCore (= 6.10.3)
+ - Firebase/Messaging (6.33.0):
+ - Firebase/CoreOnly
+ - FirebaseMessaging (~> 4.7.0)
+ - firebase_core (0.5.3):
+ - Firebase/CoreOnly (~> 6.33.0)
+ - Flutter
+ - firebase_messaging (7.0.3):
+ - Firebase/CoreOnly (~> 6.33.0)
+ - Firebase/Messaging (~> 6.33.0)
+ - firebase_core
+ - Flutter
+ - FirebaseCore (6.10.3):
+ - FirebaseCoreDiagnostics (~> 1.6)
+ - GoogleUtilities/Environment (~> 6.7)
+ - GoogleUtilities/Logger (~> 6.7)
+ - FirebaseCoreDiagnostics (1.7.0):
+ - GoogleDataTransport (~> 7.4)
+ - GoogleUtilities/Environment (~> 6.7)
+ - GoogleUtilities/Logger (~> 6.7)
+ - nanopb (~> 1.30906.0)
+ - FirebaseInstallations (1.7.0):
+ - FirebaseCore (~> 6.10)
+ - GoogleUtilities/Environment (~> 6.7)
+ - GoogleUtilities/UserDefaults (~> 6.7)
+ - PromisesObjC (~> 1.2)
+ - FirebaseInstanceID (4.8.0):
+ - FirebaseCore (~> 6.10)
+ - FirebaseInstallations (~> 1.6)
+ - GoogleUtilities/Environment (~> 6.7)
+ - GoogleUtilities/UserDefaults (~> 6.7)
+ - FirebaseMessaging (4.7.1):
+ - FirebaseCore (~> 6.10)
+ - FirebaseInstanceID (~> 4.7)
+ - GoogleUtilities/AppDelegateSwizzler (~> 6.7)
+ - GoogleUtilities/Environment (~> 6.7)
+ - GoogleUtilities/Reachability (~> 6.7)
+ - GoogleUtilities/UserDefaults (~> 6.7)
+ - Protobuf (>= 3.9.2, ~> 3.9)
- Flutter (1.0.0)
- flutter_secure_storage (3.3.1):
- Flutter
+ - GoogleDataTransport (7.5.1):
+ - nanopb (~> 1.30906.0)
+ - GoogleUtilities/AppDelegateSwizzler (6.7.2):
+ - GoogleUtilities/Environment
+ - GoogleUtilities/Logger
+ - GoogleUtilities/Network
+ - GoogleUtilities/Environment (6.7.2):
+ - PromisesObjC (~> 1.2)
+ - GoogleUtilities/Logger (6.7.2):
+ - GoogleUtilities/Environment
+ - GoogleUtilities/Network (6.7.2):
+ - GoogleUtilities/Logger
+ - "GoogleUtilities/NSData+zlib"
+ - GoogleUtilities/Reachability
+ - "GoogleUtilities/NSData+zlib (6.7.2)"
+ - GoogleUtilities/Reachability (6.7.2):
+ - GoogleUtilities/Logger
+ - GoogleUtilities/UserDefaults (6.7.2):
+ - GoogleUtilities/Logger
- local_auth (0.0.1):
- Flutter
- MTBBarcodeScanner (5.0.11)
+ - nanopb (1.30906.0):
+ - nanopb/decode (= 1.30906.0)
+ - nanopb/encode (= 1.30906.0)
+ - nanopb/decode (1.30906.0)
+ - nanopb/encode (1.30906.0)
- package_info (0.0.1):
- Flutter
- path_provider (0.0.1):
- Flutter
- "permission_handler (5.1.0+2)":
- Flutter
+ - PromisesObjC (1.2.12)
+ - Protobuf (3.17.0)
- Reachability (3.2)
- SDWebImage (5.9.1):
- SDWebImage/Core (= 5.9.1)
@@ -97,6 +163,9 @@ DEPENDENCIES:
- devicelocale (from `.symlinks/plugins/devicelocale/ios`)
- esys_flutter_share (from `.symlinks/plugins/esys_flutter_share/ios`)
- file_picker (from `.symlinks/plugins/file_picker/ios`)
+ - Firebase/Messaging (= 6.33.0)
+ - firebase_core (from `.symlinks/plugins/firebase_core/ios`)
+ - firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
- Flutter (from `Flutter`)
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
- local_auth (from `.symlinks/plugins/local_auth/ios`)
@@ -113,7 +182,18 @@ SPEC REPOS:
- CryptoSwift
- DKImagePickerController
- DKPhotoGallery
+ - Firebase
+ - FirebaseCore
+ - FirebaseCoreDiagnostics
+ - FirebaseInstallations
+ - FirebaseInstanceID
+ - FirebaseMessaging
+ - GoogleDataTransport
+ - GoogleUtilities
- MTBBarcodeScanner
+ - nanopb
+ - PromisesObjC
+ - Protobuf
- Reachability
- SDWebImage
- SwiftProtobuf
@@ -132,6 +212,10 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/esys_flutter_share/ios"
file_picker:
:path: ".symlinks/plugins/file_picker/ios"
+ firebase_core:
+ :path: ".symlinks/plugins/firebase_core/ios"
+ firebase_messaging:
+ :path: ".symlinks/plugins/firebase_messaging/ios"
Flutter:
:path: Flutter
flutter_secure_storage:
@@ -163,13 +247,26 @@ SPEC CHECKSUMS:
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
esys_flutter_share: 403498dab005b36ce1f8d7aff377e81f0621b0b4
file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1
+ Firebase: 8db6f2d1b2c5e2984efba4949a145875a8f65fe5
+ firebase_core: 5d6a02f3d85acd5f8321c2d6d62877626a670659
+ firebase_messaging: 0aea2cd5885b65e19ede58ee3507f485c992cc75
+ FirebaseCore: d889d9e12535b7f36ac8bfbf1713a0836a3012cd
+ FirebaseCoreDiagnostics: 770ac5958e1372ce67959ae4b4f31d8e127c3ac1
+ FirebaseInstallations: 466c7b4d1f58fe16707693091da253726a731ed2
+ FirebaseInstanceID: bd3ffc24367f901a43c063b36c640b345a4a5dd1
+ FirebaseMessaging: 5eca4ef173de76253352511aafef774caa1cba2a
Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c
flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec
+ GoogleDataTransport: f56af7caa4ed338dc8e138a5d7c5973e66440833
+ GoogleUtilities: 7f2f5a07f888cdb145101d6042bc4422f57e70b3
local_auth: 25938960984c3a7f6e3253e3f8d962fdd16852bd
MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb
+ nanopb: 59317e09cf1f1a0af72f12af412d54edf52603fc
package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
permission_handler: ccb20a9fad0ee9b1314a52b70b76b473c5f8dab0
+ PromisesObjC: 3113f7f76903778cf4a0586bd1ab89329a0b7b97
+ Protobuf: 7327d4444215b5f18e560a97f879ff5503c4581c
Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96
SDWebImage: a990c053fff71e388a10f3357edb0be17929c9c5
share: 0b2c3e82132f5888bccca3351c504d0003b3b410
@@ -179,6 +276,6 @@ SPEC CHECKSUMS:
url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef
webview_flutter: 9f491a9b5a66f2573946a389b2677987b0ff8c0b
-PODFILE CHECKSUM: 5b5f101b119a1b6eb857c967d462832a9062dec4
+PODFILE CHECKSUM: f316539722a6f9dbb0d0f1065a27fa7ea38c6f88
COCOAPODS: 1.9.3
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index 79c69b9ed..6f6193063 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
+ 0C37B8B926678E9100C6E5A9 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0C37B8B826678E9100C6E5A9 /* GoogleService-Info.plist */; };
0C44A71A2518EF8000B570ED /* decrypt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C44A7192518EF8000B570ED /* decrypt.swift */; };
0C9D68C9264854B60011B691 /* secRandom.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C9D68C8264854B60011B691 /* secRandom.swift */; };
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
@@ -19,6 +20,7 @@
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
+ 0C37B8B826678E9100C6E5A9 /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = ""; };
0C400E0F25B21ABB0025E469 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; };
0C44A7192518EF8000B570ED /* decrypt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = decrypt.swift; sourceTree = ""; };
0C9986A3251A932F00D566FD /* CryptoSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = CryptoSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -96,6 +98,7 @@
97C146E51CF9000F007C117D = {
isa = PBXGroup;
children = (
+ 0C37B8B826678E9100C6E5A9 /* GoogleService-Info.plist */,
0C44A7182518EF4A00B570ED /* CakeWallet */,
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
@@ -191,6 +194,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 0C37B8B926678E9100C6E5A9 /* GoogleService-Info.plist in Resources */,
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
@@ -362,9 +366,10 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
- CURRENT_PROJECT_VERSION = 40;
+ CURRENT_PROJECT_VERSION = 49;
DEVELOPMENT_TEAM = 32J6BB6VUS;
ENABLE_BITCODE = NO;
+ EXCLUDED_SOURCE_FILE_NAMES = "";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
@@ -379,7 +384,7 @@
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
- MARKETING_VERSION = 4.2.0;
+ MARKETING_VERSION = 4.2.3;
PRODUCT_BUNDLE_IDENTIFIER = com.fotolockr.cakewallet;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -505,9 +510,10 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
- CURRENT_PROJECT_VERSION = 40;
+ CURRENT_PROJECT_VERSION = 49;
DEVELOPMENT_TEAM = 32J6BB6VUS;
ENABLE_BITCODE = NO;
+ EXCLUDED_SOURCE_FILE_NAMES = "";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
@@ -522,7 +528,7 @@
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
- MARKETING_VERSION = 4.2.0;
+ MARKETING_VERSION = 4.2.3;
PRODUCT_BUNDLE_IDENTIFIER = com.fotolockr.cakewallet;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -540,9 +546,10 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
- CURRENT_PROJECT_VERSION = 40;
+ CURRENT_PROJECT_VERSION = 49;
DEVELOPMENT_TEAM = 32J6BB6VUS;
ENABLE_BITCODE = NO;
+ EXCLUDED_SOURCE_FILE_NAMES = "";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
@@ -557,7 +564,7 @@
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
- MARKETING_VERSION = 4.2.0;
+ MARKETING_VERSION = 4.2.3;
PRODUCT_BUNDLE_IDENTIFIER = com.fotolockr.cakewallet;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift
index e7c300079..2a3505ef9 100644
--- a/ios/Runner/AppDelegate.swift
+++ b/ios/Runner/AppDelegate.swift
@@ -7,6 +7,10 @@ import Flutter
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
+ if #available(iOS 10.0, *) {
+ UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
+ }
+
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let legacyMigrationChannel = FlutterMethodChannel(
name: "com.cakewallet.cakewallet/legacy_wallet_migration",
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index 970c892cd..267805951 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -37,6 +37,11 @@
Enable Face ID for fast and secure access to wallets and private keys
NSPhotoLibraryUsageDescription
We need access to documents folder for get acces to open/save backup file
+ UIBackgroundModes
+
+ fetch
+ remote-notification
+
UILaunchStoryboardName
LaunchScreen
UIMainStoryboardFile
diff --git a/ios/Runner/Runner.entitlements b/ios/Runner/Runner.entitlements
index 0c67376eb..903def2af 100644
--- a/ios/Runner/Runner.entitlements
+++ b/ios/Runner/Runner.entitlements
@@ -1,5 +1,8 @@
-
+
+ aps-environment
+ development
+
diff --git a/lib/bitcoin/bitcoin_mnemonic_is_incorrect_exception.dart b/lib/bitcoin/bitcoin_mnemonic_is_incorrect_exception.dart
index 5171a4f05..8d0583ce5 100644
--- a/lib/bitcoin/bitcoin_mnemonic_is_incorrect_exception.dart
+++ b/lib/bitcoin/bitcoin_mnemonic_is_incorrect_exception.dart
@@ -1,5 +1,5 @@
class BitcoinMnemonicIsIncorrectException implements Exception {
@override
String toString() =>
- 'Bitcoin mnemonic has incorrect format. Mnemonic should contain 24 words separated by space.';
+ 'Bitcoin mnemonic has incorrect format. Mnemonic should contain 12 or 24 words separated by space.';
}
diff --git a/lib/bitcoin/electrum_transaction_history.dart b/lib/bitcoin/electrum_transaction_history.dart
index 1d5e894c0..2aabf1304 100644
--- a/lib/bitcoin/electrum_transaction_history.dart
+++ b/lib/bitcoin/electrum_transaction_history.dart
@@ -35,7 +35,7 @@ abstract class ElectrumTransactionHistoryBase
@override
void addMany(Map transactions) =>
- this.transactions.addAll(transactions);
+ transactions.forEach((_, tx) => _updateOrInsert(tx));
@override
Future save() async {
diff --git a/lib/buy/buy_amount.dart b/lib/buy/buy_amount.dart
new file mode 100644
index 000000000..3cf3543d8
--- /dev/null
+++ b/lib/buy/buy_amount.dart
@@ -0,0 +1,12 @@
+import 'package:flutter/foundation.dart';
+
+class BuyAmount {
+ BuyAmount({
+ @required this.sourceAmount,
+ @required this.destAmount,
+ this.minAmount = 0});
+
+ final double sourceAmount;
+ final double destAmount;
+ final int minAmount;
+}
\ No newline at end of file
diff --git a/lib/buy/buy_exception.dart b/lib/buy/buy_exception.dart
new file mode 100644
index 000000000..28064fdfc
--- /dev/null
+++ b/lib/buy/buy_exception.dart
@@ -0,0 +1,12 @@
+import 'package:flutter/foundation.dart';
+import 'package:cake_wallet/buy/buy_provider_description.dart';
+
+class BuyException implements Exception {
+ BuyException({@required this.description, @required this.text});
+
+ final BuyProviderDescription description;
+ final String text;
+
+ @override
+ String toString() => '${description.title}: $text';
+}
\ No newline at end of file
diff --git a/lib/buy/buy_provider.dart b/lib/buy/buy_provider.dart
new file mode 100644
index 000000000..b908d7bc5
--- /dev/null
+++ b/lib/buy/buy_provider.dart
@@ -0,0 +1,27 @@
+import 'package:cake_wallet/buy/buy_amount.dart';
+import 'package:cake_wallet/buy/buy_provider_description.dart';
+import 'package:cake_wallet/buy/order.dart';
+import 'package:cake_wallet/core/wallet_base.dart';
+import 'package:cake_wallet/entities/wallet_type.dart';
+
+abstract class BuyProvider {
+ BuyProvider({this.wallet, this.isTestEnvironment});
+
+ final WalletBase wallet;
+ final bool isTestEnvironment;
+
+ String get title;
+ BuyProviderDescription get description;
+ String get trackUrl;
+
+ WalletType get walletType => wallet.type;
+ String get walletAddress => wallet.address;
+ String get walletId => wallet.id;
+
+ @override
+ String toString() => title;
+
+ Future requestUrl(String amount, String sourceCurrency);
+ Future findOrderById(String id);
+ Future calculateAmount(String amount, String sourceCurrency);
+}
\ No newline at end of file
diff --git a/lib/buy/buy_provider_description.dart b/lib/buy/buy_provider_description.dart
new file mode 100644
index 000000000..46b3bcdc1
--- /dev/null
+++ b/lib/buy/buy_provider_description.dart
@@ -0,0 +1,21 @@
+import 'package:cake_wallet/entities/enumerable_item.dart';
+
+class BuyProviderDescription extends EnumerableItem
+ with Serializable {
+ const BuyProviderDescription({String title, int raw})
+ : super(title: title, raw: raw);
+
+ static const wyre = BuyProviderDescription(title: 'Wyre', raw: 0);
+ static const moonPay = BuyProviderDescription(title: 'MoonPay', raw: 1);
+
+ static BuyProviderDescription deserialize({int raw}) {
+ switch (raw) {
+ case 0:
+ return wyre;
+ case 1:
+ return moonPay;
+ default:
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/lib/buy/get_buy_provider_icon.dart b/lib/buy/get_buy_provider_icon.dart
new file mode 100644
index 000000000..f284b6f04
--- /dev/null
+++ b/lib/buy/get_buy_provider_icon.dart
@@ -0,0 +1,28 @@
+import 'package:flutter/material.dart';
+import 'package:cake_wallet/buy/buy_provider_description.dart';
+
+Image getBuyProviderIcon(BuyProviderDescription providerDescription,
+ {bool isWhiteIconColor = false}) {
+
+ final _wyreIcon =
+ Image.asset('assets/images/wyre-icon.png', width: 36, height: 36);
+ final _moonPayWhiteIcon =
+ Image.asset('assets/images/moonpay-icon.png', color: Colors.white,
+ width: 36, height: 34);
+ final _moonPayBlackIcon =
+ Image.asset('assets/images/moonpay-icon.png', color: Colors.black,
+ width: 36, height: 34);
+
+ if (providerDescription != null) {
+ switch (providerDescription) {
+ case BuyProviderDescription.wyre:
+ return _wyreIcon;
+ case BuyProviderDescription.moonPay:
+ return isWhiteIconColor ? _moonPayWhiteIcon : _moonPayBlackIcon;
+ default:
+ return null;
+ }
+ } else {
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/lib/buy/moonpay/moonpay_buy_provider.dart b/lib/buy/moonpay/moonpay_buy_provider.dart
new file mode 100644
index 000000000..65effe483
--- /dev/null
+++ b/lib/buy/moonpay/moonpay_buy_provider.dart
@@ -0,0 +1,144 @@
+import 'dart:convert';
+import 'package:crypto/crypto.dart';
+import 'package:cake_wallet/buy/buy_exception.dart';
+import 'package:http/http.dart';
+import 'package:cake_wallet/buy/buy_amount.dart';
+import 'package:cake_wallet/buy/buy_provider.dart';
+import 'package:cake_wallet/buy/buy_provider_description.dart';
+import 'package:cake_wallet/buy/order.dart';
+import 'package:cake_wallet/core/wallet_base.dart';
+import 'package:cake_wallet/entities/wallet_type.dart';
+import 'package:cake_wallet/exchange/trade_state.dart';
+import 'package:cake_wallet/.secrets.g.dart' as secrets;
+
+class MoonPayBuyProvider extends BuyProvider {
+ MoonPayBuyProvider({WalletBase wallet, bool isTestEnvironment = false})
+ : super(wallet: wallet, isTestEnvironment: isTestEnvironment) {
+ baseUrl = isTestEnvironment ? _baseTestUrl : _baseProductUrl;
+ }
+
+ static const _baseTestUrl = 'https://buy-staging.moonpay.com';
+ static const _baseProductUrl = 'https://buy.moonpay.com';
+ static const _apiUrl = 'https://api.moonpay.com';
+ static const _currenciesSuffix = '/v3/currencies';
+ static const _quoteSuffix = '/buy_quote';
+ static const _transactionsSuffix = '/v1/transactions';
+ static const _ipAddressSuffix = '/v4/ip_address';
+ static const _apiKey = secrets.moonPayApiKey;
+ static const _secretKey = secrets.moonPaySecretKey;
+
+ @override
+ String get title => 'MoonPay';
+
+ @override
+ BuyProviderDescription get description => BuyProviderDescription.moonPay;
+
+ String get currencyCode =>
+ walletTypeToCryptoCurrency(walletType).title.toLowerCase();
+
+ @override
+ String get trackUrl => baseUrl + '/transaction_receipt?transactionId=';
+
+ String baseUrl;
+
+ @override
+ Future requestUrl(String amount, String sourceCurrency) async {
+ final enabledPaymentMethods =
+ 'credit_debit_card%2Capple_pay%2Cgoogle_pay%2Csamsung_pay'
+ '%2Csepa_bank_transfer%2Cgbp_bank_transfer%2Cgbp_open_banking_payment';
+
+ final suffix = '?apiKey=' + _apiKey + '¤cyCode=' +
+ currencyCode + '&enabledPaymentMethods=' + enabledPaymentMethods +
+ '&walletAddress=' + walletAddress +
+ '&baseCurrencyCode=' + sourceCurrency.toLowerCase() +
+ '&baseCurrencyAmount=' + amount + '&lockAmount=true' +
+ '&showAllCurrencies=false' + '&showWalletAddressForm=false';
+
+ final originalUrl = baseUrl + suffix;
+
+ final messageBytes = utf8.encode(suffix);
+ final key = utf8.encode(_secretKey);
+ final hmac = Hmac(sha256, key);
+ final digest = hmac.convert(messageBytes);
+ final signature = base64.encode(digest.bytes);
+ final urlWithSignature = originalUrl +
+ '&signature=${Uri.encodeComponent(signature)}';
+
+ return isTestEnvironment ? originalUrl : urlWithSignature;
+ }
+
+ @override
+ Future calculateAmount(String amount, String sourceCurrency) async {
+ final url = _apiUrl + _currenciesSuffix + '/$currencyCode' +
+ _quoteSuffix + '/?apiKey=' + _apiKey +
+ '&baseCurrencyAmount=' + amount +
+ '&baseCurrencyCode=' + sourceCurrency.toLowerCase();
+
+ final response = await get(url);
+
+ if (response.statusCode != 200) {
+ throw BuyException(
+ description: description,
+ text: 'Quote is not found!');
+ }
+
+ final responseJSON = json.decode(response.body) as Map;
+ final sourceAmount = responseJSON['totalAmount'] as double;
+ final destAmount = responseJSON['quoteCurrencyAmount'] as double;
+ final minSourceAmount = responseJSON['baseCurrency']['minAmount'] as int;
+
+ return BuyAmount(
+ sourceAmount: sourceAmount,
+ destAmount: destAmount,
+ minAmount: minSourceAmount);
+ }
+
+ @override
+ Future findOrderById(String id) async {
+ final url = _apiUrl + _transactionsSuffix + '/$id' +
+ '?apiKey=' + _apiKey;
+
+ final response = await get(url);
+
+ if (response.statusCode != 200) {
+ throw BuyException(
+ description: description,
+ text: 'Transaction $id is not found!');
+ }
+
+ final responseJSON = json.decode(response.body) as Map;
+ final status = responseJSON['status'] as String;
+ final state = TradeState.deserialize(raw: status);
+ final createdAtRaw = responseJSON['createdAt'] as String;
+ final createdAt = DateTime.parse(createdAtRaw).toLocal();
+ final amount = responseJSON['quoteCurrencyAmount'] as double;
+
+ return Order(
+ id: id,
+ provider: description,
+ transferId: id,
+ state: state,
+ createdAt: createdAt,
+ amount: amount.toString(),
+ receiveAddress: walletAddress,
+ walletId: walletId
+ );
+ }
+
+ static Future onEnabled() async {
+ final url = _apiUrl + _ipAddressSuffix + '?apiKey=' + _apiKey;
+ var isBuyEnable = false;
+
+ final response = await get(url);
+
+ try {
+ final responseJSON = json.decode(response.body) as Map;
+ isBuyEnable = responseJSON['isBuyAllowed'] as bool;
+ } catch (e) {
+ isBuyEnable = false;
+ print(e.toString());
+ }
+
+ return isBuyEnable;
+ }
+}
\ No newline at end of file
diff --git a/lib/entities/order.dart b/lib/buy/order.dart
similarity index 76%
rename from lib/entities/order.dart
rename to lib/buy/order.dart
index 1676edd99..54c13bd37 100644
--- a/lib/entities/order.dart
+++ b/lib/buy/order.dart
@@ -1,3 +1,4 @@
+import 'package:cake_wallet/buy/buy_provider_description.dart';
import 'package:hive/hive.dart';
import 'package:cake_wallet/exchange/trade_state.dart';
import 'package:cake_wallet/entities/format_amount.dart';
@@ -8,6 +9,7 @@ part 'order.g.dart';
class Order extends HiveObject {
Order(
{this.id,
+ BuyProviderDescription provider,
this.transferId,
this.from,
this.to,
@@ -16,7 +18,8 @@ class Order extends HiveObject {
this.amount,
this.receiveAddress,
this.walletId})
- : stateRaw = state?.raw;
+ : providerRaw = provider?.raw,
+ stateRaw = state?.raw;
static const typeId = 8;
static const boxName = 'Orders';
@@ -51,5 +54,11 @@ class Order extends HiveObject {
@HiveField(8)
String walletId;
+ @HiveField(9)
+ int providerRaw;
+
+ BuyProviderDescription get provider =>
+ BuyProviderDescription.deserialize(raw: providerRaw);
+
String amountFormatted() => formatAmount(amount);
}
\ No newline at end of file
diff --git a/lib/buy/wyre/wyre_buy_provider.dart b/lib/buy/wyre/wyre_buy_provider.dart
new file mode 100644
index 000000000..f1100d130
--- /dev/null
+++ b/lib/buy/wyre/wyre_buy_provider.dart
@@ -0,0 +1,163 @@
+import 'dart:convert';
+import 'package:cake_wallet/buy/buy_exception.dart';
+import 'package:http/http.dart';
+import 'package:cake_wallet/buy/buy_amount.dart';
+import 'package:cake_wallet/buy/buy_provider.dart';
+import 'package:cake_wallet/buy/buy_provider_description.dart';
+import 'package:cake_wallet/buy/order.dart';
+import 'package:cake_wallet/core/wallet_base.dart';
+import 'package:cake_wallet/entities/wallet_type.dart';
+import 'package:cake_wallet/exchange/trade_state.dart';
+import 'package:cake_wallet/.secrets.g.dart' as secrets;
+
+class WyreBuyProvider extends BuyProvider {
+ WyreBuyProvider({WalletBase wallet, bool isTestEnvironment = false})
+ : super(wallet: wallet, isTestEnvironment: isTestEnvironment) {
+ baseApiUrl = isTestEnvironment
+ ? _baseTestApiUrl
+ : _baseProductApiUrl;
+ }
+
+ static const _baseTestApiUrl = 'https://api.testwyre.com';
+ static const _baseProductApiUrl = 'https://api.sendwyre.com';
+ static const _trackTestUrl = 'https://dash.testwyre.com/track/';
+ static const _trackProductUrl = 'https://dash.sendwyre.com/track/';
+ static const _ordersSuffix = '/v3/orders';
+ static const _reserveSuffix = '/reserve';
+ static const _quoteSuffix = '/quote/partner';
+ static const _timeStampSuffix = '?timestamp=';
+ static const _transferSuffix = '/v2/transfer/';
+ static const _trackSuffix = '/track';
+ static const _countryCode = 'US';
+ static const _secretKey = secrets.wyreSecretKey;
+ static const _accountId = secrets.wyreAccountId;
+
+ @override
+ String get title => 'Wyre';
+
+ @override
+ BuyProviderDescription get description => BuyProviderDescription.wyre;
+
+ @override
+ String get trackUrl => isTestEnvironment
+ ? _trackTestUrl
+ : _trackProductUrl;
+
+ String baseApiUrl;
+
+ @override
+ Future requestUrl(String amount, String sourceCurrency) async {
+ final timestamp = DateTime.now().millisecondsSinceEpoch.toString();
+ final url = baseApiUrl + _ordersSuffix + _reserveSuffix +
+ _timeStampSuffix + timestamp;
+ final body = {
+ 'amount': amount,
+ 'sourceCurrency': sourceCurrency,
+ 'destCurrency': walletTypeToCryptoCurrency(walletType).title,
+ 'dest': walletTypeToString(walletType).toLowerCase() + ':' + walletAddress,
+ 'referrerAccountId': _accountId,
+ 'lockFields': ['amount', 'sourceCurrency', 'destCurrency', 'dest']
+ };
+
+ final response = await post(url,
+ headers: {
+ 'Authorization': 'Bearer $_secretKey',
+ 'Content-Type': 'application/json',
+ 'cache-control': 'no-cache'
+ },
+ body: json.encode(body));
+
+ if (response.statusCode != 200) {
+ throw BuyException(
+ description: description,
+ text: 'Url $url is not found!');
+ }
+
+ final responseJSON = json.decode(response.body) as Map;
+ final urlFromResponse = responseJSON['url'] as String;
+ return urlFromResponse;
+ }
+
+ @override
+ Future calculateAmount(String amount, String sourceCurrency) async {
+ final quoteUrl = _baseProductApiUrl + _ordersSuffix + _quoteSuffix;
+ final body = {
+ 'amount': amount,
+ 'sourceCurrency': sourceCurrency,
+ 'destCurrency': walletTypeToCryptoCurrency(walletType).title,
+ 'dest': walletTypeToString(walletType).toLowerCase() + ':' + walletAddress,
+ 'accountId': _accountId,
+ 'country': _countryCode
+ };
+
+ final response = await post(quoteUrl,
+ headers: {
+ 'Authorization': 'Bearer $_secretKey',
+ 'Content-Type': 'application/json',
+ 'cache-control': 'no-cache'
+ },
+ body: json.encode(body));
+
+ if (response.statusCode != 200) {
+ throw BuyException(
+ description: description,
+ text: 'Quote is not found!');
+ }
+
+ final responseJSON = json.decode(response.body) as Map;
+ final sourceAmount = responseJSON['sourceAmount'] as double;
+ final destAmount = responseJSON['destAmount'] as double;
+
+ return BuyAmount(sourceAmount: sourceAmount, destAmount: destAmount);
+ }
+
+ @override
+ Future findOrderById(String id) async {
+ final orderUrl = baseApiUrl + _ordersSuffix + '/$id';
+ final orderResponse = await get(orderUrl);
+
+ if (orderResponse.statusCode != 200) {
+ throw BuyException(
+ description: description,
+ text: 'Order $id is not found!');
+ }
+
+ final orderResponseJSON =
+ json.decode(orderResponse.body) as Map;
+ final transferId = orderResponseJSON['transferId'] as String;
+ final from = orderResponseJSON['sourceCurrency'] as String;
+ final to = orderResponseJSON['destCurrency'] as String;
+ final status = orderResponseJSON['status'] as String;
+ final state = TradeState.deserialize(raw: status.toLowerCase());
+ final createdAtRaw = orderResponseJSON['createdAt'] as int;
+ final createdAt =
+ DateTime.fromMillisecondsSinceEpoch(createdAtRaw).toLocal();
+
+ final transferUrl =
+ baseApiUrl + _transferSuffix + transferId + _trackSuffix;
+ final transferResponse = await get(transferUrl);
+
+ if (transferResponse.statusCode != 200) {
+ throw BuyException(
+ description: description,
+ text: 'Transfer $transferId is not found!');
+ }
+
+ final transferResponseJSON =
+ json.decode(transferResponse.body) as Map;
+ final amount = transferResponseJSON['destAmount'] as double;
+
+ return Order(
+ id: id,
+ provider: description,
+ transferId: transferId,
+ from: from,
+ to: to,
+ state: state,
+ createdAt: createdAt,
+ amount: amount.toString(),
+ receiveAddress: walletAddress,
+ walletId: walletId
+ );
+ }
+}
\ No newline at end of file
diff --git a/lib/di.dart b/lib/di.dart
index cae3a068f..37b6c5968 100644
--- a/lib/di.dart
+++ b/lib/di.dart
@@ -4,11 +4,9 @@ import 'package:cake_wallet/core/backup_service.dart';
import 'package:cake_wallet/core/wallet_service.dart';
import 'package:cake_wallet/entities/biometric_auth.dart';
import 'package:cake_wallet/entities/contact_record.dart';
-import 'package:cake_wallet/entities/load_current_wallet.dart';
-import 'package:cake_wallet/entities/order.dart';
+import 'package:cake_wallet/buy/order.dart';
import 'package:cake_wallet/entities/transaction_description.dart';
import 'package:cake_wallet/entities/transaction_info.dart';
-import 'package:cake_wallet/entities/wyre_service.dart';
import 'package:cake_wallet/monero/monero_wallet_service.dart';
import 'package:cake_wallet/entities/contact.dart';
import 'package:cake_wallet/entities/node.dart';
@@ -16,7 +14,8 @@ import 'package:cake_wallet/exchange/trade.dart';
import 'package:cake_wallet/reactions/on_authentication_state_change.dart';
import 'package:cake_wallet/src/screens/backup/backup_page.dart';
import 'package:cake_wallet/src/screens/backup/edit_backup_password_page.dart';
-
+import 'package:cake_wallet/src/screens/buy/buy_webview_page.dart';
+import 'package:cake_wallet/src/screens/buy/pre_order_page.dart';
import 'package:cake_wallet/src/screens/contact/contact_list_page.dart';
import 'package:cake_wallet/src/screens/contact/contact_page.dart';
import 'package:cake_wallet/src/screens/exchange_trade/exchange_confirm_page.dart';
@@ -43,7 +42,6 @@ import 'package:cake_wallet/src/screens/transaction_details/transaction_details_
import 'package:cake_wallet/src/screens/wallet_keys/wallet_keys_page.dart';
import 'package:cake_wallet/src/screens/exchange/exchange_page.dart';
import 'package:cake_wallet/src/screens/exchange/exchange_template_page.dart';
-import 'package:cake_wallet/src/screens/wyre/wyre_page.dart';
import 'package:cake_wallet/store/dashboard/orders_store.dart';
import 'package:cake_wallet/store/node_list_store.dart';
import 'package:cake_wallet/store/secret_store.dart';
@@ -62,6 +60,8 @@ import 'package:cake_wallet/src/screens/subaddress/address_edit_or_create_page.d
import 'package:cake_wallet/src/screens/wallet_list/wallet_list_page.dart';
import 'package:cake_wallet/store/wallet_list_store.dart';
import 'package:cake_wallet/view_model/backup_view_model.dart';
+import 'package:cake_wallet/view_model/buy/buy_amount_view_model.dart';
+import 'package:cake_wallet/view_model/buy/buy_view_model.dart';
import 'package:cake_wallet/view_model/contact_list/contact_list_view_model.dart';
import 'package:cake_wallet/view_model/contact_list/contact_view_model.dart';
import 'package:cake_wallet/view_model/edit_backup_password_view_model.dart';
@@ -90,7 +90,6 @@ import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart';
import 'package:cake_wallet/view_model/wallet_restore_view_model.dart';
import 'package:cake_wallet/view_model/wallet_seed_view_model.dart';
import 'package:cake_wallet/view_model/exchange/exchange_view_model.dart';
-import 'package:cake_wallet/view_model/wyre_view_model.dart';
import 'package:flutter/widgets.dart';
import 'package:get_it/get_it.dart';
import 'package:hive/hive.dart';
@@ -113,6 +112,7 @@ import 'package:cake_wallet/store/templates/exchange_template_store.dart';
import 'package:cake_wallet/entities/template.dart';
import 'package:cake_wallet/exchange/exchange_template.dart';
import 'package:cake_wallet/.secrets.g.dart' as secrets;
+import 'package:cake_wallet/entities/push_notifications_service.dart';
final getIt = GetIt.instance;
@@ -152,6 +152,7 @@ Future setup(
final isBitcoinBuyEnabled = (secrets.wyreSecretKey?.isNotEmpty ?? false) &&
(secrets.wyreApiKey?.isNotEmpty ?? false) &&
(secrets.wyreAccountId?.isNotEmpty ?? false);
+
final settingsStore = await SettingsStoreBase.load(
nodeSource: _nodeSource, isBitcoinBuyEnabled: isBitcoinBuyEnabled);
@@ -232,6 +233,9 @@ Future setup(
settingsStore: getIt.get(),
fiatConvertationStore: getIt.get()));
+
+ getIt.registerFactory(() => PushNotificationsService());
+
getIt.registerFactory(() => DashboardViewModel(
balanceViewModel: getIt.get(),
appStore: getIt.get(),
@@ -239,9 +243,8 @@ Future setup(
tradeFilterStore: getIt.get(),
transactionFilterStore: getIt.get(),
settingsStore: settingsStore,
- ordersSource: _ordersSource,
ordersStore: getIt.get(),
- wyreViewModel: getIt.get()));
+ pushNotificationsService: getIt.get()));
getIt.registerFactory(() => AuthService(
secureStorage: getIt.get(),
@@ -487,10 +490,14 @@ Future setup(
getIt
.registerFactoryParam(
- (TransactionInfo transactionInfo, _) => TransactionDetailsViewModel(
- transactionInfo: transactionInfo,
- transactionDescriptionBox: _transactionDescriptionBox,
- settingsStore: getIt.get()));
+ (TransactionInfo transactionInfo, _) {
+ final wallet = getIt.get().wallet;
+ return TransactionDetailsViewModel(
+ transactionInfo: transactionInfo,
+ transactionDescriptionBox: _transactionDescriptionBox,
+ wallet: wallet,
+ settingsStore: getIt.get());
+ });
getIt.registerFactoryParam(
(TransactionInfo transactionInfo, _) => TransactionDetailsPage(
@@ -537,22 +544,37 @@ Future setup(
getIt.registerFactoryParam((Trade trade, _) =>
TradeDetailsPage(getIt.get(param1: trade)));
+ getIt.registerFactory(() => BuyAmountViewModel());
+
getIt.registerFactory(() {
- return WyreService(appStore: getIt.get());
+ final wallet = getIt.get().wallet;
+
+ return BuyViewModel(_ordersSource, getIt.get(),
+ getIt.get(), getIt.get(),
+ wallet: wallet);
});
getIt.registerFactory(() {
- return WyreViewModel(ordersSource, getIt.get(),
- wyreService: getIt.get());
+ return PreOrderPage(buyViewModel: getIt.get());
});
- getIt.registerFactoryParam((String url, _) =>
- WyrePage(getIt.get(),
- ordersStore: getIt.get(), url: url));
+ getIt.registerFactoryParam(
+ (List args, _) {
+ final url = args.first as String;
+ final buyViewModel = args[1] as BuyViewModel;
- getIt.registerFactoryParam((order, _) =>
- OrderDetailsViewModel(
- wyreViewModel: getIt.get(), orderForDetails: order));
+ return BuyWebViewPage(buyViewModel: buyViewModel,
+ ordersStore: getIt.get(), url: url);
+ });
+
+ getIt.registerFactoryParam(
+ (order, _) {
+ final wallet = getIt.get().wallet;
+
+ return OrderDetailsViewModel(
+ wallet: wallet,
+ orderForDetails: order);
+ });
getIt.registerFactoryParam((Order order, _) =>
OrderDetailsPage(getIt.get(param1: order)));
diff --git a/lib/entities/biometric_auth.dart b/lib/entities/biometric_auth.dart
index ab5d62445..10a05ebff 100644
--- a/lib/entities/biometric_auth.dart
+++ b/lib/entities/biometric_auth.dart
@@ -7,7 +7,7 @@ class BiometricAuth {
Future isAuthenticated() async {
try {
- return await _localAuth.authenticateWithBiometrics(
+ return await _localAuth.authenticate(
localizedReason: S.current.biometric_auth_reason,
useErrorDialogs: true,
stickyAuth: false);
diff --git a/lib/entities/preferences_key.dart b/lib/entities/preferences_key.dart
index 6d55748cc..82db7d5d9 100644
--- a/lib/entities/preferences_key.dart
+++ b/lib/entities/preferences_key.dart
@@ -19,4 +19,5 @@ class PreferencesKey {
'current_default_settings_migration_version';
static const moneroTransactionPriority = 'current_fee_priority_monero';
static const bitcoinTransactionPriority = 'current_fee_priority_bitcoin';
+ static const shouldShowReceiveWarning = 'should_show_receive_warning';
}
diff --git a/lib/entities/push_notifications_service.dart b/lib/entities/push_notifications_service.dart
new file mode 100644
index 000000000..bf5226af3
--- /dev/null
+++ b/lib/entities/push_notifications_service.dart
@@ -0,0 +1,49 @@
+import 'dart:io';
+import 'package:cake_wallet/main.dart';
+import 'package:cake_wallet/utils/show_bar.dart';
+import 'package:firebase_messaging/firebase_messaging.dart';
+
+class PushNotificationsService {
+ PushNotificationsService._();
+
+ factory PushNotificationsService() => _instance;
+
+ static final PushNotificationsService _instance = PushNotificationsService._();
+ static Future _onBackgroundMessage(Map message) async {}
+ static Future _showNotification(Map message) async {
+ Map alert = {};
+ String msg = '';
+ String title = '';
+
+ if (Platform.isIOS) {
+ alert = message['aps']['alert'] as Map ?? {};
+ msg = alert['body'] as String ?? '';
+ title = alert['title'] as String ?? '';
+ }
+
+ if (Platform.isAndroid) {
+ msg = message['notification']['body'] as String ?? '';
+ title = message['notification']['title'] as String ?? '';
+ }
+
+ await showBar(navigatorKey.currentContext, msg, titleText: title, duration: null);
+ }
+
+ final _firebaseMessaging = FirebaseMessaging();
+ bool _initialized = false;
+
+ Future init() async {
+ if (_initialized) {
+ return;
+ }
+
+ _firebaseMessaging.requestNotificationPermissions();
+ _firebaseMessaging.configure(
+ onMessage: (message) async => _showNotification(message),
+ onLaunch: (message) async => _showNotification(message),
+ onResume: (message) async => _showNotification(message),
+ onBackgroundMessage: _onBackgroundMessage);
+
+ _initialized = true;
+ }
+}
\ No newline at end of file
diff --git a/lib/entities/wallet_type.dart b/lib/entities/wallet_type.dart
index d59f336c0..b8a36e709 100644
--- a/lib/entities/wallet_type.dart
+++ b/lib/entities/wallet_type.dart
@@ -71,7 +71,7 @@ String walletTypeToDisplayName(WalletType type) {
case WalletType.bitcoin:
return 'Bitcoin (Electrum)';
case WalletType.litecoin:
- return 'Litecoin';
+ return 'Litecoin (Electrum)';
default:
return '';
}
diff --git a/lib/entities/wyre_exception.dart b/lib/entities/wyre_exception.dart
deleted file mode 100644
index 85d9f5b60..000000000
--- a/lib/entities/wyre_exception.dart
+++ /dev/null
@@ -1,8 +0,0 @@
-class WyreException implements Exception {
- WyreException(this.description);
-
- String description;
-
- @override
- String toString() => description;
-}
\ No newline at end of file
diff --git a/lib/entities/wyre_service.dart b/lib/entities/wyre_service.dart
deleted file mode 100644
index 63346f0e4..000000000
--- a/lib/entities/wyre_service.dart
+++ /dev/null
@@ -1,113 +0,0 @@
-import 'dart:convert';
-import 'package:cake_wallet/entities/wyre_exception.dart';
-import 'package:cake_wallet/exchange/trade_state.dart';
-import 'package:cake_wallet/store/app_store.dart';
-import 'package:flutter/foundation.dart';
-import 'package:http/http.dart';
-import 'package:cake_wallet/.secrets.g.dart' as secrets;
-import 'package:cake_wallet/entities/order.dart';
-import 'package:cake_wallet/entities/wallet_type.dart';
-
-class WyreService {
- WyreService({@required this.appStore, this.isTestEnvironment = false}) {
- baseApiUrl = isTestEnvironment ? _baseTestApiUrl : _baseProductApiUrl;
- trackUrl = isTestEnvironment ? _trackTestUrl : _trackProductUrl;
- }
-
- static const _baseTestApiUrl = 'https://api.testwyre.com';
- static const _baseProductApiUrl = 'https://api.sendwyre.com';
- static const _trackTestUrl = 'https://dash.testwyre.com/track/';
- static const _trackProductUrl = 'https://dash.sendwyre.com/track/';
- static const _ordersSuffix = '/v3/orders';
- static const _reserveSuffix = '/reserve';
- static const _timeStampSuffix = '?timestamp=';
- static const _transferSuffix = '/v2/transfer/';
- static const _trackSuffix = '/track';
-
- final bool isTestEnvironment;
- final AppStore appStore;
-
- WalletType get walletType => appStore.wallet.type;
- String get walletAddress => appStore.wallet.address;
- String get walletId => appStore.wallet.id;
-
- String baseApiUrl;
- String trackUrl;
-
- Future getWyreUrl() async {
- final timestamp = DateTime.now().millisecondsSinceEpoch.toString();
- final url = baseApiUrl +
- _ordersSuffix +
- _reserveSuffix +
- _timeStampSuffix +
- timestamp;
- final secretKey = secrets.wyreSecretKey;
- final accountId = secrets.wyreAccountId;
- final body = {
- 'destCurrency': walletTypeToCryptoCurrency(walletType).title,
- 'dest':
- walletTypeToString(walletType).toLowerCase() + ':' + walletAddress,
- 'referrerAccountId': accountId,
- 'lockFields': ['destCurrency', 'dest']
- };
-
- final response = await post(url,
- headers: {
- 'Authorization': 'Bearer $secretKey',
- 'Content-Type': 'application/json',
- 'cache-control': 'no-cache'
- },
- body: json.encode(body));
-
- if (response.statusCode != 200) {
- throw WyreException('Url $url is not found!');
- }
-
- final responseJSON = json.decode(response.body) as Map;
- final urlFromResponse = responseJSON['url'] as String;
- return urlFromResponse;
- }
-
- Future findOrderById(String id) async {
- final orderUrl = baseApiUrl + _ordersSuffix + '/$id';
- final orderResponse = await get(orderUrl);
-
- if (orderResponse.statusCode != 200) {
- throw WyreException('Order $id is not found!');
- }
-
- final orderResponseJSON =
- json.decode(orderResponse.body) as Map;
- final transferId = orderResponseJSON['transferId'] as String;
- final from = orderResponseJSON['sourceCurrency'] as String;
- final to = orderResponseJSON['destCurrency'] as String;
- final status = orderResponseJSON['status'] as String;
- final state = TradeState.deserialize(raw: status.toLowerCase());
- final createdAtRaw = orderResponseJSON['createdAt'] as int;
- final createdAt =
- DateTime.fromMillisecondsSinceEpoch(createdAtRaw).toLocal();
-
- final transferUrl =
- baseApiUrl + _transferSuffix + transferId + _trackSuffix;
- final transferResponse = await get(transferUrl);
-
- if (transferResponse.statusCode != 200) {
- throw WyreException('Transfer $transferId is not found!');
- }
-
- final transferResponseJSON =
- json.decode(transferResponse.body) as Map;
- final amount = transferResponseJSON['destAmount'] as double;
-
- return Order(
- id: id,
- transferId: transferId,
- from: from,
- to: to,
- state: state,
- createdAt: createdAt,
- amount: amount.toString(),
- receiveAddress: walletAddress,
- walletId: walletId);
- }
-}
diff --git a/lib/exchange/trade_state.dart b/lib/exchange/trade_state.dart
index 7095626b9..9f08b4df2 100644
--- a/lib/exchange/trade_state.dart
+++ b/lib/exchange/trade_state.dart
@@ -27,6 +27,12 @@ class TradeState extends EnumerableItem with Serializable {
static const finished = TradeState(raw: 'finished', title: 'Finished');
static const waiting = TradeState(raw: 'waiting', title: 'Waiting');
static const processing = TradeState(raw: 'processing', title: 'Processing');
+ static const waitingPayment =
+ TradeState(raw: 'waitingPayment', title: 'Waiting payment');
+ static const waitingAuthorization =
+ TradeState(raw: 'waitingAuthorization', title: 'Waiting authorization');
+ static const failed = TradeState(raw: 'failed', title: 'Failed');
+ static const completed = TradeState(raw: 'completed', title: 'Completed');
static TradeState deserialize({String raw}) {
switch (raw) {
@@ -62,6 +68,14 @@ class TradeState extends EnumerableItem with Serializable {
return waiting;
case 'processing':
return processing;
+ case 'waitingPayment':
+ return waitingPayment;
+ case 'waitingAuthorization':
+ return waitingAuthorization;
+ case 'failed':
+ return failed;
+ case 'completed':
+ return completed;
default:
return null;
}
diff --git a/lib/main.dart b/lib/main.dart
index 1a1724e3e..b24943f3d 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,5 +1,5 @@
import 'package:cake_wallet/entities/language_service.dart';
-import 'package:cake_wallet/entities/order.dart';
+import 'package:cake_wallet/buy/order.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:hive/hive.dart';
diff --git a/lib/monero/monero_transaction_info.dart b/lib/monero/monero_transaction_info.dart
index 6f099fbfa..0a700835a 100644
--- a/lib/monero/monero_transaction_info.dart
+++ b/lib/monero/monero_transaction_info.dart
@@ -8,7 +8,7 @@ import 'package:cw_monero/transaction_history.dart';
class MoneroTransactionInfo extends TransactionInfo {
MoneroTransactionInfo(this.id, this.height, this.direction, this.date,
- this.isPending, this.amount, this.accountIndex, this.fee);
+ this.isPending, this.amount, this.accountIndex, this.addressIndex, this.fee);
MoneroTransactionInfo.fromMap(Map map)
: id = (map['hash'] ?? '') as String,
@@ -21,6 +21,7 @@ class MoneroTransactionInfo extends TransactionInfo {
isPending = parseBoolFromString(map['isPending'] as String),
amount = map['amount'] as int,
accountIndex = int.parse(map['accountIndex'] as String),
+ addressIndex = map['addressIndex'] as int,
key = getTxKey((map['hash'] ?? '') as String),
fee = map['fee'] as int ?? 0;
@@ -33,6 +34,7 @@ class MoneroTransactionInfo extends TransactionInfo {
isPending = row.isPending != 0,
amount = row.getAmount(),
accountIndex = row.subaddrAccount,
+ addressIndex = row.subaddrIndex,
key = getTxKey(row.getHash()),
fee = row.fee;
@@ -44,6 +46,7 @@ class MoneroTransactionInfo extends TransactionInfo {
final bool isPending;
final int amount;
final int fee;
+ final int addressIndex;
String recipientAddress;
String key;
diff --git a/lib/monero/monero_wallet.dart b/lib/monero/monero_wallet.dart
index 92742273c..e902f1080 100644
--- a/lib/monero/monero_wallet.dart
+++ b/lib/monero/monero_wallet.dart
@@ -271,6 +271,11 @@ abstract class MoneroWalletBase extends WalletBase
+ monero_wallet.getAddress(
+ accountIndex: accountIndex,
+ addressIndex: addressIndex);
+
@override
Future