Merge branch 'main' into CAKE-192-implement-unstoppable-domain

This commit is contained in:
M 2021-06-08 15:09:03 +03:00
commit 43f0719efe
90 changed files with 2028 additions and 478 deletions

5
.gitignore vendored
View file

@ -97,4 +97,7 @@ android/app/.cxx/**
ios/Flutter/.last_build_id
/lib/generated/**
#**#
/**/#**#
/**/#**#
**/google-services.json
**/GoogleService-Info.plist

View file

@ -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.

View file

@ -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()) {
@ -85,4 +89,6 @@ dependencies {
androidTestImplementation 'androidx.test:runner:1.3.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation 'com.unstoppabledomains:resolution:1.13.0'
implementation 'com.google.firebase:firebase-core:19.0.0'
implementation 'com.google.firebase:firebase-messaging:19.0.0'
}

View file

@ -7,6 +7,7 @@
<uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" />
<application
android:name=".Application"
android:label="Cake Wallet"
android:allowBackup="false"
android:fullBackupContent="false"
@ -29,7 +30,6 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<meta-data
android:name="flutterEmbedding"
android:value="2" />

View file

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

View file

@ -6,6 +6,7 @@ buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:4.1.3'
classpath 'com.google.gms:google-services:4.3.8'
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 981 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
assets/images/github.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 507 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -21,4 +21,11 @@
is_default: false
-
uri: node.imonero.org:18081
is_default: false
is_default: false
uri: node.c3pool.com:18081
is_default: false
uri: xmr.prprpr.icu:18081
is_default: false

View file

@ -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 Companys 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 Companys 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.

View file

@ -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<uint32_t>::iterator it = transaction->subaddrIndex().begin();
subaddrIndex = *it;
confirmations = transaction->confirmations();
datetime = static_cast<int64_t>(transaction->timestamp());
direction = transaction->direction();

View file

@ -23,6 +23,9 @@ class TransactionInfoRow extends Struct {
@Int8()
int isPending;
@Uint32()
int subaddrIndex;
Pointer<Utf8> hash;
Pointer<Utf8> paymentId;

View file

@ -37,6 +37,7 @@ target 'Runner' do
# Cake Wallet (Legacy)
pod 'CryptoSwift'
pod 'UnstoppableDomainsResolution', '~> 0.3.6'
pod 'Firebase/Messaging', '6.33.0'
end
post_install do |installer|

View file

@ -65,18 +65,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)
@ -104,6 +170,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`)
@ -123,7 +192,18 @@ SPEC REPOS:
- DKImagePickerController
- DKPhotoGallery
- EthereumAddress
- Firebase
- FirebaseCore
- FirebaseCoreDiagnostics
- FirebaseInstallations
- FirebaseInstanceID
- FirebaseMessaging
- GoogleDataTransport
- GoogleUtilities
- MTBBarcodeScanner
- nanopb
- PromisesObjC
- Protobuf
- Reachability
- SDWebImage
- SwiftProtobuf
@ -143,6 +223,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:
@ -176,13 +260,26 @@ SPEC CHECKSUMS:
esys_flutter_share: 403498dab005b36ce1f8d7aff377e81f0621b0b4
EthereumAddress: 39fe8e11cf04e4e9902b55ae653dbc4e0aee5f30
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
@ -193,6 +290,5 @@ SPEC CHECKSUMS:
url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef
webview_flutter: 9f491a9b5a66f2573946a389b2677987b0ff8c0b
PODFILE CHECKSUM: 2172f10eb8ff8378f8d6e3e2c1366a0e6cdea018
COCOAPODS: 1.10.1

View file

@ -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 = "<group>"; };
0C400E0F25B21ABB0025E469 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
0C44A7192518EF8000B570ED /* decrypt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = decrypt.swift; sourceTree = "<group>"; };
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 = 44;
DEVELOPMENT_TEAM = 32J6BB6VUS;
ENABLE_BITCODE = NO;
EXCLUDED_SOURCE_FILE_NAMES = "\"$(SRCROOT)/Runner/GoogleService-Info.plist\"";
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 = 44;
DEVELOPMENT_TEAM = 32J6BB6VUS;
ENABLE_BITCODE = NO;
EXCLUDED_SOURCE_FILE_NAMES = "\"$(SRCROOT)/Runner/GoogleService-Info.plist\"";
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 = 44;
DEVELOPMENT_TEAM = 32J6BB6VUS;
ENABLE_BITCODE = NO;
EXCLUDED_SOURCE_FILE_NAMES = "\"$(SRCROOT)/Runner/GoogleService-Info.plist\"";
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";

View file

@ -12,6 +12,10 @@ import UnstoppableDomainsResolution
_ 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",

View file

@ -37,6 +37,11 @@
<string>Enable Face ID for fast and secure access to wallets and private keys</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>We need access to documents folder for get acces to open/save backup file</string>
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>remote-notification</string>
</array>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>

View file

@ -1,5 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict/>
<dict>
<key>aps-environment</key>
<string>development</string>
</dict>
</plist>

View file

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

View file

@ -35,7 +35,7 @@ abstract class ElectrumTransactionHistoryBase
@override
void addMany(Map<String, ElectrumTransactionInfo> transactions) =>
this.transactions.addAll(transactions);
transactions.forEach((_, tx) => _updateOrInsert(tx));
@override
Future<void> save() async {

12
lib/buy/buy_amount.dart Normal file
View file

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

View file

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

27
lib/buy/buy_provider.dart Normal file
View file

@ -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<String> requestUrl(String amount, String sourceCurrency);
Future<Order> findOrderById(String id);
Future<BuyAmount> calculateAmount(String amount, String sourceCurrency);
}

View file

@ -0,0 +1,21 @@
import 'package:cake_wallet/entities/enumerable_item.dart';
class BuyProviderDescription extends EnumerableItem<int>
with Serializable<int> {
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;
}
}
}

View file

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

View file

@ -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<String> 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 + '&currencyCode=' +
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<BuyAmount> 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<String, dynamic>;
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<Order> 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<String, dynamic>;
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<bool> 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<String, dynamic>;
isBuyEnable = responseJSON['isBuyAllowed'] as bool;
} catch (e) {
isBuyEnable = false;
print(e.toString());
}
return isBuyEnable;
}
}

View file

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

View file

@ -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<String> 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<String, dynamic>;
final urlFromResponse = responseJSON['url'] as String;
return urlFromResponse;
}
@override
Future<BuyAmount> 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<String, dynamic>;
final sourceAmount = responseJSON['sourceAmount'] as double;
final destAmount = responseJSON['destAmount'] as double;
return BuyAmount(sourceAmount: sourceAmount, destAmount: destAmount);
}
@override
Future<Order> 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<String, dynamic>;
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<String, dynamic>;
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
);
}
}

View file

@ -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<SettingsStore>(),
fiatConvertationStore: getIt.get<FiatConversionStore>()));
getIt.registerFactory(() => PushNotificationsService());
getIt.registerFactory(() => DashboardViewModel(
balanceViewModel: getIt.get<BalanceViewModel>(),
appStore: getIt.get<AppStore>(),
@ -239,9 +243,8 @@ Future setup(
tradeFilterStore: getIt.get<TradeFilterStore>(),
transactionFilterStore: getIt.get<TransactionFilterStore>(),
settingsStore: settingsStore,
ordersSource: _ordersSource,
ordersStore: getIt.get<OrdersStore>(),
wyreViewModel: getIt.get<WyreViewModel>()));
pushNotificationsService: getIt.get<PushNotificationsService>()));
getIt.registerFactory<AuthService>(() => AuthService(
secureStorage: getIt.get<FlutterSecureStorage>(),
@ -487,10 +490,14 @@ Future setup(
getIt
.registerFactoryParam<TransactionDetailsViewModel, TransactionInfo, void>(
(TransactionInfo transactionInfo, _) => TransactionDetailsViewModel(
transactionInfo: transactionInfo,
transactionDescriptionBox: _transactionDescriptionBox,
settingsStore: getIt.get<SettingsStore>()));
(TransactionInfo transactionInfo, _) {
final wallet = getIt.get<AppStore>().wallet;
return TransactionDetailsViewModel(
transactionInfo: transactionInfo,
transactionDescriptionBox: _transactionDescriptionBox,
wallet: wallet,
settingsStore: getIt.get<SettingsStore>());
});
getIt.registerFactoryParam<TransactionDetailsPage, TransactionInfo, void>(
(TransactionInfo transactionInfo, _) => TransactionDetailsPage(
@ -537,22 +544,37 @@ Future setup(
getIt.registerFactoryParam<TradeDetailsPage, Trade, void>((Trade trade, _) =>
TradeDetailsPage(getIt.get<TradeDetailsViewModel>(param1: trade)));
getIt.registerFactory(() => BuyAmountViewModel());
getIt.registerFactory(() {
return WyreService(appStore: getIt.get<AppStore>());
final wallet = getIt.get<AppStore>().wallet;
return BuyViewModel(_ordersSource, getIt.get<OrdersStore>(),
getIt.get<SettingsStore>(), getIt.get<BuyAmountViewModel>(),
wallet: wallet);
});
getIt.registerFactory(() {
return WyreViewModel(ordersSource, getIt.get<OrdersStore>(),
wyreService: getIt.get<WyreService>());
return PreOrderPage(buyViewModel: getIt.get<BuyViewModel>());
});
getIt.registerFactoryParam<WyrePage, String, void>((String url, _) =>
WyrePage(getIt.get<WyreViewModel>(),
ordersStore: getIt.get<OrdersStore>(), url: url));
getIt.registerFactoryParam<BuyWebViewPage, List, void>(
(List args, _) {
final url = args.first as String;
final buyViewModel = args[1] as BuyViewModel;
getIt.registerFactoryParam<OrderDetailsViewModel, Order, void>((order, _) =>
OrderDetailsViewModel(
wyreViewModel: getIt.get<WyreViewModel>(), orderForDetails: order));
return BuyWebViewPage(buyViewModel: buyViewModel,
ordersStore: getIt.get<OrdersStore>(), url: url);
});
getIt.registerFactoryParam<OrderDetailsViewModel, Order, void>(
(order, _) {
final wallet = getIt.get<AppStore>().wallet;
return OrderDetailsViewModel(
wallet: wallet,
orderForDetails: order);
});
getIt.registerFactoryParam<OrderDetailsPage, Order, void>((Order order, _) =>
OrderDetailsPage(getIt.get<OrderDetailsViewModel>(param1: order)));

View file

@ -7,7 +7,7 @@ class BiometricAuth {
Future<bool> isAuthenticated() async {
try {
return await _localAuth.authenticateWithBiometrics(
return await _localAuth.authenticate(
localizedReason: S.current.biometric_auth_reason,
useErrorDialogs: true,
stickyAuth: false);

View file

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

View file

@ -0,0 +1,45 @@
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<dynamic> _onBackgroundMessage(Map<String, dynamic> message) async {}
final _firebaseMessaging = FirebaseMessaging();
bool _initialized = false;
Future<void> init() async {
if (_initialized) {
return;
}
_firebaseMessaging.requestNotificationPermissions();
_firebaseMessaging.configure(
onMessage: (message) async {
Map<dynamic, dynamic> alert = <dynamic, dynamic>{};
String msg = '';
String title = '';
if (Platform.isIOS) {
alert = message['aps']['alert'] as Map<dynamic, dynamic> ?? <dynamic, dynamic>{};
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<void>(navigatorKey.currentContext, msg, titleText: title, duration: null);
},
onBackgroundMessage: _onBackgroundMessage);
_initialized = true;
}
}

View file

@ -71,7 +71,7 @@ String walletTypeToDisplayName(WalletType type) {
case WalletType.bitcoin:
return 'Bitcoin (Electrum)';
case WalletType.litecoin:
return 'Litecoin';
return 'Litecoin (Electrum)';
default:
return '';
}

View file

@ -1,8 +0,0 @@
class WyreException implements Exception {
WyreException(this.description);
String description;
@override
String toString() => description;
}

View file

@ -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<String> 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<String, dynamic>;
final urlFromResponse = responseJSON['url'] as String;
return urlFromResponse;
}
Future<Order> 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<String, dynamic>;
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<String, dynamic>;
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);
}
}

View file

@ -27,6 +27,12 @@ class TradeState extends EnumerableItem<String> with Serializable<String> {
static const finished = TradeState(raw: 'finished', title: 'Finished');
static const waiting = TradeState(raw: 'waiting', title: 'Waiting');
static const processing = TradeState(raw: 'processing', title: 'Processing');
static const waitingPayment =
TradeState(raw: 'waitingPayment', title: 'Waiting payment');
static const 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<String> with Serializable<String> {
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;
}

View file

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

View file

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

View file

@ -271,6 +271,11 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
await walletInfo.save();
}
String getTransactionAddress(int accountIndex, int addressIndex) =>
monero_wallet.getAddress(
accountIndex: accountIndex,
addressIndex: addressIndex);
@override
Future<Map<String, MoneroTransactionInfo>> fetchTransactions() async {
monero_transaction_history.refreshTransactions();

View file

@ -23,6 +23,7 @@ class Palette {
static const Color persianRed = Color.fromRGBO(206, 55, 55, 1.0);
static const Color blueCraiola = Color.fromRGBO(69, 110, 255, 1.0);
static const Color blueGreyCraiola = Color.fromRGBO(106, 177, 207, 1.0);
static const Color greyBlueCraiola = Color.fromRGBO(116, 139, 219, 1.0);
static const Color darkBlueCraiola = Color.fromRGBO(53, 86, 136, 1.0);
static const Color pinkFlamingo = Color.fromRGBO(240, 60, 243, 1.0);
static const Color redHat = Color.fromRGBO(209, 68, 37, 1.0);

View file

@ -1,16 +1,18 @@
import 'package:cake_wallet/entities/contact_record.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/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/order_details/order_details_page.dart';
import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart';
import 'package:cake_wallet/src/screens/restore/restore_from_backup_page.dart';
import 'package:cake_wallet/src/screens/restore/wallet_restore_page.dart';
import 'package:cake_wallet/src/screens/seed/pre_seed_page.dart';
import 'package:cake_wallet/src/screens/support/support_page.dart';
import 'package:cake_wallet/src/screens/wyre/wyre_page.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/view_model/buy/buy_view_model.dart';
import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
@ -299,10 +301,17 @@ Route<dynamic> createRoute(RouteSettings settings) {
builder: (_) =>
getIt.get<OrderDetailsPage>(param1: settings.arguments as Order));
case Routes.wyre:
case Routes.preOrder:
return MaterialPageRoute<void>(
builder: (_) =>
getIt.get<WyrePage>(param1: settings.arguments as String));
getIt.get<PreOrderPage>());
case Routes.buyWebView:
final args = settings.arguments as List;
return MaterialPageRoute<void>(
builder: (_) =>
getIt.get<BuyWebViewPage>(param1: args));
case Routes.restoreWalletFromSeedDetails:
final args = settings.arguments as List;

View file

@ -53,5 +53,6 @@ class Routes {
static const restoreFromBackup = '/restore_from_backup';
static const support = '/support';
static const orderDetails = '/order_details';
static const wyre = '/wyre';
static const preOrder = '/pre_order';
static const buyWebView = '/buy_web_view';
}

View file

@ -1,20 +1,23 @@
import 'dart:async';
import 'dart:io';
import 'package:cake_wallet/buy/buy_provider.dart';
import 'package:cake_wallet/buy/moonpay/moonpay_buy_provider.dart';
import 'package:cake_wallet/buy/wyre/wyre_buy_provider.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/store/dashboard/orders_store.dart';
import 'package:cake_wallet/view_model/wyre_view_model.dart';
import 'package:cake_wallet/view_model/buy/buy_view_model.dart';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class WyrePage extends BasePage {
WyrePage(this.wyreViewModel,
{@required this.ordersStore, @required this.url});
class BuyWebViewPage extends BasePage {
BuyWebViewPage({@required this.buyViewModel,
@required this.ordersStore, @required this.url});
final OrdersStore ordersStore;
final String url;
final WyreViewModel wyreViewModel;
final BuyViewModel buyViewModel;
@override
String get title => S.current.buy;
@ -27,26 +30,27 @@ class WyrePage extends BasePage {
@override
Widget body(BuildContext context) =>
WyrePageBody(wyreViewModel, ordersStore: ordersStore, url: url);
BuyWebViewPageBody(buyViewModel, ordersStore: ordersStore, url: url);
}
class WyrePageBody extends StatefulWidget {
WyrePageBody(this.wyreViewModel, {this.ordersStore, this.url});
class BuyWebViewPageBody extends StatefulWidget {
BuyWebViewPageBody(this.buyViewModel, {this.ordersStore, this.url});
final OrdersStore ordersStore;
final String url;
final WyreViewModel wyreViewModel;
final BuyViewModel buyViewModel;
@override
WyrePageBodyState createState() => WyrePageBodyState();
BuyWebViewPageBodyState createState() => BuyWebViewPageBodyState();
}
class WyrePageBodyState extends State<WyrePageBody> {
class BuyWebViewPageBodyState extends State<BuyWebViewPageBody> {
String orderId;
WebViewController _webViewController;
GlobalKey _webViewkey;
Timer _timer;
bool _isSaving;
BuyProvider _provider;
@override
void initState() {
@ -54,35 +58,17 @@ class WyrePageBodyState extends State<WyrePageBody> {
_webViewkey = GlobalKey();
_isSaving = false;
widget.ordersStore.orderId = '';
_provider = widget.buyViewModel.selectedProvider;
if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
_timer?.cancel();
_timer = Timer.periodic(Duration(seconds: 1), (timer) async {
if (_provider is WyreBuyProvider) {
_saveOrder(keyword: 'completed', splitSymbol: '/');
}
try {
if (_webViewController == null || _isSaving) {
return;
}
final url = await _webViewController.currentUrl();
if (url.contains('completed')) {
final urlParts = url.split('/');
orderId = urlParts.last;
widget.ordersStore.orderId = orderId;
if (orderId.isNotEmpty) {
_isSaving = true;
await widget.wyreViewModel.saveOrder(orderId);
timer.cancel();
}
}
} catch (e) {
_isSaving = false;
print(e);
}
});
if (_provider is MoonPayBuyProvider) {
_saveOrder(keyword: 'transactionId', splitSymbol: '=');
}
}
@override
@ -94,4 +80,33 @@ class WyrePageBodyState extends State<WyrePageBody> {
onWebViewCreated: (WebViewController controller) =>
setState(() => _webViewController = controller));
}
void _saveOrder({String keyword, String splitSymbol}) {
_timer?.cancel();
_timer = Timer.periodic(Duration(seconds: 1), (timer) async {
try {
if (_webViewController == null || _isSaving) {
return;
}
final url = await _webViewController.currentUrl();
if (url.contains(keyword)) {
final urlParts = url.split(splitSymbol);
orderId = urlParts.last;
widget.ordersStore.orderId = orderId;
if (orderId.isNotEmpty) {
_isSaving = true;
await widget.buyViewModel.saveOrder(orderId);
timer.cancel();
}
}
} catch (e) {
_isSaving = false;
print(e);
}
});
}
}

View file

@ -0,0 +1,288 @@
import 'dart:ui';
import 'package:cake_wallet/buy/buy_amount.dart';
import 'package:cake_wallet/buy/buy_provider.dart';
import 'package:cake_wallet/buy/moonpay/moonpay_buy_provider.dart';
import 'package:cake_wallet/src/screens/buy/widgets/buy_list_item.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/buy/buy_view_model.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:keyboard_actions/keyboard_actions.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/base_page.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/generated/i18n.dart';
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
import 'package:cake_wallet/src/widgets/trail_button.dart';
import 'package:mobx/mobx.dart';
import 'package:url_launcher/url_launcher.dart';
class PreOrderPage extends BasePage {
PreOrderPage({@required this.buyViewModel})
: _amountFocus = FocusNode(),
_amountController = TextEditingController() {
_amountController.addListener(() {
final amount = _amountController.text;
if (amount != buyViewModel.buyAmountViewModel.amount) {
buyViewModel.buyAmountViewModel.amount = amount;
buyViewModel.selectedProvider = null;
}
});
reaction((_) => buyViewModel.buyAmountViewModel.amount, (String amount) {
if (_amountController.text != amount) {
_amountController.text = amount;
}
if (amount.isEmpty) {
buyViewModel.selectedProvider = null;
buyViewModel.isShowProviderButtons = false;
} else {
buyViewModel.isShowProviderButtons = true;
}
});
}
static const _amountPattern = '^([0-9]+([.\,][0-9]{0,2})?|[.\,][0-9]{1,2})\$';
final BuyViewModel buyViewModel;
final FocusNode _amountFocus;
final TextEditingController _amountController;
@override
String get title => S.current.buy_bitcoin;
@override
Color get titleColor => Colors.white;
@override
bool get resizeToAvoidBottomInset => false;
@override
bool get extendBodyBehindAppBar => true;
@override
AppBarStyle get appBarStyle => AppBarStyle.transparent;
@override
Widget trailing(context) => TrailButton(
caption: S.of(context).clear,
onPressed: () {
buyViewModel.reset();
});
@override
Widget body(BuildContext context) {
return KeyboardActions(
config: KeyboardActionsConfig(
keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
keyboardBarColor: Theme.of(context).accentTextTheme.body2
.backgroundColor,
nextFocus: false,
actions: [
KeyboardActionsItem(
focusNode: _amountFocus,
toolbarButtons: [(_) => KeyboardDoneButton()],
),
]),
child: Container(
height: 0,
color: Theme.of(context).backgroundColor,
child: ScrollableWithBottomSection(
contentPadding: EdgeInsets.only(bottom: 24),
content: Observer(builder: (_) => Column(
children: [
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(24),
bottomRight: Radius.circular(24)),
gradient: LinearGradient(colors: [
Theme.of(context).primaryTextTheme.subhead.color,
Theme.of(context)
.primaryTextTheme
.subhead
.decorationColor,
], begin: Alignment.topLeft, end: Alignment.bottomRight),
),
child: Padding(
padding: EdgeInsets.only(top: 100, bottom: 65),
child: Center(
child: Container(
width: 210,
child: BaseTextFormField(
focusNode: _amountFocus,
controller: _amountController,
keyboardType:
TextInputType.numberWithOptions(
signed: false, decimal: true),
inputFormatters: [
FilteringTextInputFormatter
.allow(RegExp(_amountPattern))
],
prefixIcon: Padding(
padding: EdgeInsets.only(top: 2),
child:
Text(buyViewModel.fiatCurrency.title + ': ',
style: TextStyle(
fontSize: 36,
fontWeight: FontWeight.w600,
color: Colors.white,
)),
),
hintText: '0.00',
borderColor: Theme.of(context)
.primaryTextTheme
.body2
.decorationColor,
borderWidth: 0.5,
textStyle: TextStyle(
fontSize: 36,
fontWeight: FontWeight.w500,
color: Colors.white),
placeholderTextStyle: TextStyle(
color: Theme.of(context)
.primaryTextTheme
.headline
.decorationColor,
fontWeight: FontWeight.w500,
fontSize: 36),
)
)
)
)
),
if (buyViewModel.isShowProviderButtons) Padding(
padding: EdgeInsets.only(top: 38, bottom: 18),
child: Text(
S.of(context).buy_with + ':',
textAlign: TextAlign.center,
style: TextStyle(
color: Theme.of(context).primaryTextTheme.title.color,
fontSize: 18,
fontWeight: FontWeight.bold
),
)
),
if (buyViewModel.isShowProviderButtons)
...buyViewModel.items.map(
(item) => Observer(builder: (_) =>
FutureBuilder<BuyAmount>(
future: item.buyAmount,
builder: (context, AsyncSnapshot<BuyAmount> snapshot) {
double sourceAmount;
double destAmount;
int minAmount;
if (snapshot.hasData) {
sourceAmount = snapshot.data.sourceAmount;
destAmount = snapshot.data.destAmount;
minAmount = snapshot.data.minAmount;
} else {
sourceAmount = 0.0;
destAmount = 0.0;
minAmount = 0;
}
return Padding(
padding:
EdgeInsets.only(left: 15, top: 20, right: 15),
child: Observer(builder: (_) {
return BuyListItem(
selectedProvider:
buyViewModel.selectedProvider,
provider: item.provider,
sourceAmount: sourceAmount,
sourceCurrency: buyViewModel.fiatCurrency,
destAmount: destAmount,
destCurrency: buyViewModel.cryptoCurrency,
onTap: ((buyViewModel.doubleAmount != 0.0)
&& (snapshot.hasData)) ? () =>
onSelectBuyProvider(
context: context,
provider: item.provider,
sourceAmount: sourceAmount,
minAmount: minAmount
) : null
);
})
);
}
))
)
],
)),
bottomSectionPadding:
EdgeInsets.only(left: 24, right: 24, bottom: 24),
bottomSection: Observer(builder: (_) {
return LoadingPrimaryButton(
onPressed: () => onPresentProvider(context: context),
text: buyViewModel.selectedProvider == null
? S.of(context).buy
: S.of(context).buy_with +
' ${buyViewModel.selectedProvider
.description.title}',
color: Theme.of(context).accentTextTheme.body2.color,
textColor: Colors.white,
isLoading: buyViewModel.isRunning,
isDisabled: (buyViewModel.selectedProvider == null) ||
buyViewModel.isDisabled
);
})
)
)
);
}
void onSelectBuyProvider({BuildContext context, BuyProvider provider,
double sourceAmount, int minAmount}) {
if ((provider is MoonPayBuyProvider)&&
(buyViewModel.buyAmountViewModel.doubleAmount < minAmount)) {
showPopUp<void>(
context: context,
builder: (BuildContext context) {
return AlertWithOneAction(
alertTitle: 'MoonPay',
alertContent: S.of(context).moonpay_alert_text(
minAmount.toString(),
buyViewModel.fiatCurrency.toString()),
buttonText: S.of(context).ok,
buttonAction: () => Navigator.of(context).pop());
});
return;
}
buyViewModel.selectedProvider = provider;
sourceAmount > 0
? buyViewModel.isDisabled = false
: buyViewModel.isDisabled = true;
}
Future<void> onPresentProvider({BuildContext context}) async {
if (buyViewModel.isRunning) {
return;
}
buyViewModel.isRunning = true;
final url = await buyViewModel.fetchUrl();
if (url.isNotEmpty) {
if (buyViewModel.selectedProvider is MoonPayBuyProvider) {
if (await canLaunch(url)) await launch(url);
} else {
await Navigator.of(context)
.pushNamed(Routes.buyWebView,
arguments: [url, buyViewModel]);
}
}
buyViewModel.reset();
buyViewModel.isRunning = false;
}
}

View file

@ -0,0 +1,116 @@
import 'package:cake_wallet/buy/buy_provider.dart';
import 'package:cake_wallet/buy/get_buy_provider_icon.dart';
import 'package:cake_wallet/entities/crypto_currency.dart';
import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cake_wallet/palette.dart';
import 'package:flutter/material.dart';
class BuyListItem extends StatelessWidget {
BuyListItem({
@required this.selectedProvider,
@required this.provider,
@required this.sourceAmount,
@required this.sourceCurrency,
@required this.destAmount,
@required this.destCurrency,
@required this.onTap
});
final BuyProvider selectedProvider;
final BuyProvider provider;
final double sourceAmount;
final FiatCurrency sourceCurrency;
final double destAmount;
final CryptoCurrency destCurrency;
final void Function() onTap;
@override
Widget build(BuildContext context) {
final isSelected = selectedProvider?.description == provider.description;
final providerIcon = getBuyProviderIcon(provider.description,
isWhiteIconColor: isSelected);
final backgroundColor = isSelected
? Palette.greyBlueCraiola
: Palette.shadowWhite;
final primaryTextColor = isSelected
? Colors.white
: Palette.darkGray;
final secondaryTextColor = isSelected
? Colors.white
: Palette.darkBlueCraiola;
return GestureDetector(
onTap: () => onTap?.call(),
child: Container(
height: 102,
padding: EdgeInsets.only(
left: 20,
//top: 33,
right: 20
),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(25)),
color: backgroundColor
),
child: Stack(
children: [
Positioned(
top: 33,
left: 0,
right: 0,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
if (providerIcon != null) Padding(
padding: EdgeInsets.only(right: 10),
child: providerIcon
),
Text(
provider.description.title,
style: TextStyle(
color: secondaryTextColor,
fontSize: 20,
fontWeight: FontWeight.bold
),
)
],
),
Text(
'${destAmount?.toString()} ${destCurrency.title}',
style: TextStyle(
color: secondaryTextColor,
fontSize: 20,
fontWeight: FontWeight.bold
),
),
],
)
),
Positioned(
top: 65,
right: 0,
child: Text(
'${sourceAmount?.toString()} ${sourceCurrency.title}',
style: TextStyle(
color: primaryTextColor,
fontSize: 16,
fontWeight: FontWeight.bold
),
),
)
],
)
)
);
}
}

View file

@ -132,29 +132,12 @@ class DashboardPage extends BasePage {
image: exchangeImage,
title: S.of(context).exchange,
route: Routes.exchange),
Observer(
builder: (_) => Stack(
clipBehavior: Clip.none,
alignment: Alignment.topCenter,
children: [
if (walletViewModel.isRunningWebView)
Positioned(
top: -5,
child: SpinKitRing(
color: Theme.of(context).buttonColor,
lineWidth: 3,
size: 70.0,
),
),
ActionButton(
image: buyImage,
title: S.of(context).buy,
onClick: walletViewModel.isRunningWebView
? null
: () async =>
await _onClickBuyButton(context))
],
)),
ActionButton(
image: buyImage,
title: S.of(context).buy,
onClick: () async =>
await _onClickBuyButton(context),
),
],
),
)
@ -167,7 +150,8 @@ class DashboardPage extends BasePage {
return;
}
pages.add(AddressPage(addressListViewModel: addressListViewModel));
pages.add(AddressPage(addressListViewModel: addressListViewModel,
walletViewModel: walletViewModel));
pages.add(BalancePage(dashboardViewModel: walletViewModel));
pages.add(TransactionsPage(dashboardViewModel: walletViewModel));
@ -183,7 +167,7 @@ class DashboardPage extends BasePage {
return AlertWithOneAction(
alertTitle: S.of(context).pre_seed_title,
alertContent:
S.of(context).outdated_electrum_wallet_desceription,
S.of(context).outdated_electrum_wallet_description,
buttonText: S.of(context).understand,
buttonAction: () => Navigator.of(context).pop());
});
@ -197,14 +181,7 @@ class DashboardPage extends BasePage {
switch (walletType) {
case WalletType.bitcoin:
try {
walletViewModel.isRunningWebView = true;
final url = await walletViewModel.wyreViewModel.wyreUrl;
await Navigator.of(context).pushNamed(Routes.wyre, arguments: url);
walletViewModel.isRunningWebView = false;
} catch (_) {
walletViewModel.isRunningWebView = false;
}
Navigator.of(context).pushNamed(Routes.preOrder);
break;
default:
await showPopUp<void>(

View file

@ -1,5 +1,11 @@
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/themes/theme_base.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_view_model.dart';
import 'package:cake_wallet/src/screens/receive/widgets/qr_widget.dart';
@ -7,17 +13,43 @@ import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:keyboard_actions/keyboard_actions.dart';
import 'package:mobx/mobx.dart';
class AddressPage extends StatelessWidget {
AddressPage({@required this.addressListViewModel})
AddressPage({@required this.addressListViewModel,
this.walletViewModel})
: _cryptoAmountFocus = FocusNode();
final WalletAddressListViewModel addressListViewModel;
final DashboardViewModel walletViewModel;
final FocusNode _cryptoAmountFocus;
@override
Widget build(BuildContext context) {
autorun((_) async {
if (!walletViewModel.isOutdatedElectrumWallet
|| !walletViewModel.settingsStore.shouldShowReceiveWarning) {
return;
}
await Future<void>.delayed(Duration(seconds: 1));
await showPopUp<void>(
context: context,
builder: (BuildContext context) {
return AlertWithTwoActions(
alertTitle: S.of(context).pre_seed_title,
alertContent: S.of(context).outdated_electrum_wallet_receive_warning,
leftButtonText: S.of(context).understand,
actionLeftButton: () => Navigator.of(context).pop(),
rightButtonText: S.of(context).do_not_show_me,
actionRightButton: () {
walletViewModel.settingsStore.setShouldShowReceiveWarning(false);
Navigator.of(context).pop();
});
});
});
return KeyboardActions(
autoScroll: false,
disableScroll: true,
@ -42,7 +74,8 @@ class AddressPage extends StatelessWidget {
child: Observer(builder: (_) => QRWidget(
addressListViewModel: addressListViewModel,
amountTextFieldFocusNode: _cryptoAmountFocus,
isAmountFieldShow: !addressListViewModel.hasAccounts))
isAmountFieldShow: !addressListViewModel.hasAccounts,
isBright: walletViewModel.settingsStore.currentTheme.type == ThemeType.bright))
),
Observer(builder: (_) {
return addressListViewModel.hasAddressList

View file

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:auto_size_text/auto_size_text.dart';

View file

@ -1,22 +1,33 @@
import 'package:cake_wallet/buy/buy_provider_description.dart';
import 'package:cake_wallet/buy/get_buy_provider_icon.dart';
import 'package:cake_wallet/themes/theme_base.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/store/settings_store.dart';
class OrderRow extends StatelessWidget {
OrderRow({
@required this.onTap,
@required this.provider,
this.from,
this.to,
this.createdAtFormattedDate,
this.formattedAmount});
final VoidCallback onTap;
final BuyProviderDescription provider;
final String from;
final String to;
final String createdAtFormattedDate;
final String formattedAmount;
final wyreImage =
Image.asset('assets/images/wyre-icon.png', width: 36, height: 36);
@override
Widget build(BuildContext context) {
final currentTheme = getIt.get<SettingsStore>().currentTheme;
final isWhiteIconColor = currentTheme.type != ThemeType.light;
final providerIcon = getBuyProviderIcon(provider,
isWhiteIconColor: isWhiteIconColor);
return InkWell(
onTap: onTap,
child: Container(
@ -26,8 +37,10 @@ class OrderRow extends StatelessWidget {
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
wyreImage,
SizedBox(width: 12),
if (providerIcon != null) Padding(
padding: EdgeInsets.only(right: 12),
child: providerIcon,
),
Expanded(
child: Column(
mainAxisSize: MainAxisSize.min,

View file

@ -84,6 +84,7 @@ class TransactionsPage extends StatelessWidget {
onTap: () => Navigator.of(context).pushNamed(
Routes.orderDetails,
arguments: order),
provider: order.provider,
from: order.from,
to: order.to,
createdAtFormattedDate:

View file

@ -175,7 +175,7 @@ class ExchangeTemplatePage extends BasePage {
initialIsAddressEditable:
exchangeViewModel.isReceiveAddressEnabled,
isAmountEstimated: true,
currencies: CryptoCurrency.all,
currencies: exchangeViewModel.receiveCurrencies,
onCurrencySelected: (currency) =>
exchangeViewModel.changeReceiveCurrency(
currency: currency),

View file

@ -45,6 +45,7 @@ class CurrencyPickerState extends State<CurrencyPicker> {
color: Palette.darkBlueCraiola,
);
final int crossAxisCount = 3;
final int maxNumberItemsInAlert = 12;
final int itemsCount;
final double backgroundHeight = 280;
final double thumbHeight = 72;
@ -148,6 +149,7 @@ class CurrencyPickerState extends State<CurrencyPicker> {
);
})
),
if (itemsCount > maxNumberItemsInAlert)
CakeScrollbar(
backgroundHeight: backgroundHeight,
thumbHeight: thumbHeight,

View file

@ -98,6 +98,12 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
showInformation(widget.exchangeTradeViewModel, context);
}
@override
void dispose() {
super.dispose();
widget.exchangeTradeViewModel.timer?.cancel();
}
@override
Widget build(BuildContext context) {
final copyImage = Image.asset('assets/images/copy_content.png',

View file

@ -19,7 +19,33 @@ class OrderDetailsPage extends BasePage {
final OrderDetailsViewModel orderDetailsViewModel;
@override
Widget body(BuildContext context) {
Widget body(BuildContext context) =>
OrderDetailsPageBody(orderDetailsViewModel);
}
class OrderDetailsPageBody extends StatefulWidget {
OrderDetailsPageBody(this.orderDetailsViewModel);
final OrderDetailsViewModel orderDetailsViewModel;
@override
OrderDetailsPageBodyState createState() =>
OrderDetailsPageBodyState(orderDetailsViewModel);
}
class OrderDetailsPageBodyState extends State<OrderDetailsPageBody> {
OrderDetailsPageBodyState(this.orderDetailsViewModel);
final OrderDetailsViewModel orderDetailsViewModel;
@override
void dispose() {
super.dispose();
orderDetailsViewModel.timer?.cancel();
}
@override
Widget build(BuildContext context) {
return Observer(builder: (_) {
return SectionStandardList(
sectionCount: 1,
@ -44,4 +70,5 @@ class OrderDetailsPage extends BasePage {
});
});
}
}

View file

@ -1,6 +1,7 @@
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
import 'package:cake_wallet/themes/theme_base.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
@ -34,6 +35,9 @@ class ReceivePage extends BasePage {
@override
Color get backgroundDarkColor => Colors.transparent;
@override
bool get resizeToAvoidBottomInset => false;
final FocusNode _cryptoAmountFocus;
@override
@ -124,7 +128,8 @@ class ReceivePage extends BasePage {
child: QRWidget(
addressListViewModel: addressListViewModel,
isAmountFieldShow: true,
amountTextFieldFocusNode: _cryptoAmountFocus),
amountTextFieldFocusNode: _cryptoAmountFocus,
isBright: currentTheme.type == ThemeType.bright),
),
Observer(
builder: (_) => ListView.separated(

View file

@ -13,7 +13,8 @@ class QRWidget extends StatelessWidget {
QRWidget(
{@required this.addressListViewModel,
this.isAmountFieldShow = false,
this.amountTextFieldFocusNode})
this.amountTextFieldFocusNode,
this.isBright})
: amountController = TextEditingController(),
_formKey = GlobalKey<FormState>() {
amountController.addListener(() => addressListViewModel.amount =
@ -25,6 +26,7 @@ class QRWidget extends StatelessWidget {
final TextEditingController amountController;
final FocusNode amountTextFieldFocusNode;
final GlobalKey<FormState> _formKey;
final bool isBright;
@override
Widget build(BuildContext context) {
@ -55,7 +57,7 @@ class QRWidget extends StatelessWidget {
),
child: QrImage(
data: addressListViewModel.uri.toString(),
backgroundColor: Colors.transparent,
backgroundColor: isBright ? Colors.black : Colors.transparent,
foregroundColor: Theme.of(context).accentTextTheme.
display3.backgroundColor,
),

View file

@ -19,7 +19,33 @@ class TradeDetailsPage extends BasePage {
final TradeDetailsViewModel tradeDetailsViewModel;
@override
Widget body(BuildContext context) {
Widget body(BuildContext context) =>
TradeDetailsPageBody(tradeDetailsViewModel);
}
class TradeDetailsPageBody extends StatefulWidget {
TradeDetailsPageBody(this.tradeDetailsViewModel);
final TradeDetailsViewModel tradeDetailsViewModel;
@override
TradeDetailsPageBodyState createState() =>
TradeDetailsPageBodyState(tradeDetailsViewModel);
}
class TradeDetailsPageBodyState extends State<TradeDetailsPageBody> {
TradeDetailsPageBodyState(this.tradeDetailsViewModel);
final TradeDetailsViewModel tradeDetailsViewModel;
@override
void dispose() {
super.dispose();
tradeDetailsViewModel.timer?.cancel();
}
@override
Widget build(BuildContext context) {
return Observer(builder: (_) {
return SectionStandardList(
sectionCount: 1,
@ -44,4 +70,5 @@ class TradeDetailsPage extends BasePage {
});
});
}
}

View file

@ -26,7 +26,8 @@ class BaseTextFormField extends StatelessWidget {
this.placeholderTextStyle,
this.maxLength,
this.focusNode,
this.initialValue});
this.initialValue,
this.borderWidth = 1.0});
final TextEditingController controller;
final TextInputType keyboardType;
@ -52,6 +53,7 @@ class BaseTextFormField extends StatelessWidget {
final bool readOnly;
final bool enableInteractiveSelection;
final String initialValue;
final double borderWidth;
@override
Widget build(BuildContext context) {
@ -88,17 +90,17 @@ class BaseTextFormField extends StatelessWidget {
borderSide: BorderSide(
color: borderColor ??
Theme.of(context).primaryTextTheme.title.backgroundColor,
width: 1.0)),
width: borderWidth)),
disabledBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: borderColor ??
Theme.of(context).primaryTextTheme.title.backgroundColor,
width: 1.0)),
width: borderWidth)),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: borderColor ??
Theme.of(context).primaryTextTheme.title.backgroundColor,
width: 1.0))),
width: borderWidth))),
validator: validator,
);
}

View file

@ -1,5 +1,5 @@
import 'dart:async';
import 'package:cake_wallet/entities/order.dart';
import 'package:cake_wallet/buy/order.dart';
import 'package:cake_wallet/view_model/dashboard/order_list_item.dart';
import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart';

View file

@ -8,7 +8,6 @@ import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart';
import 'package:package_info/package_info.dart';
import 'package:devicelocale/devicelocale.dart';
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/entities/wallet_type.dart';
import 'package:shared_preferences/shared_preferences.dart';
@ -18,6 +17,7 @@ import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cake_wallet/entities/node.dart';
import 'package:cake_wallet/entities/monero_transaction_priority.dart';
import 'package:cake_wallet/entities/action_list_display_mode.dart';
import 'package:cake_wallet/.secrets.g.dart' as secrets;
part 'settings_store.g.dart';
@ -147,6 +147,12 @@ abstract class SettingsStoreBase with Store {
bool isBitcoinBuyEnabled;
bool get shouldShowReceiveWarning =>
_sharedPreferences.getBool(PreferencesKey.shouldShowReceiveWarning) ?? true;
Future<void> setShouldShowReceiveWarning(bool value) async =>
_sharedPreferences.setBool(PreferencesKey.shouldShowReceiveWarning, value);
static Future<SettingsStore> load(
{@required Box<Node> nodeSource,
@required bool isBitcoinBuyEnabled,
@ -242,8 +248,13 @@ abstract class SettingsStoreBase with Store {
BitcoinTransactionPriority.medium,
BalanceDisplayMode initialBalanceDisplayMode =
BalanceDisplayMode.availableBalance}) async {
final isBitcoinBuyEnabled = (secrets.wyreSecretKey?.isNotEmpty ?? false) &&
(secrets.wyreApiKey?.isNotEmpty ?? false) &&
(secrets.wyreAccountId?.isNotEmpty ?? false);
final settings = await SettingsStoreBase.load(
nodeSource: nodeSource,
isBitcoinBuyEnabled: isBitcoinBuyEnabled,
initialBalanceDisplayMode: initialBalanceDisplayMode,
initialFiatCurrency: initialFiatCurrency,
initialMoneroTransactionPriority: initialMoneroTransactionPriority,

View file

@ -2,8 +2,11 @@ import 'package:flushbar/flushbar.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
Future<T> showBar<T>(BuildContext context, String text,
{bool isDark = false, Duration duration = const Duration(seconds: 1), bool isDismissible = true}) {
Future<T> showBar<T>(BuildContext context, String messageText,
{bool isDark = false,
Duration duration = const Duration(seconds: 1),
bool isDismissible = true,
String titleText}) {
final bar = Flushbar<T>(
boxShadows: [
BoxShadow(
@ -14,9 +17,14 @@ Future<T> showBar<T>(BuildContext context, String text,
backgroundColor: isDark ? Colors.black : Colors.white,
borderRadius: 35,
margin: EdgeInsets.all(50),
messageText: Text(text,
titleText: titleText != null
? Text(titleText,
textAlign: TextAlign.center,
style: TextStyle(color: isDark ? Colors.white : Colors.black, fontWeight: FontWeight.bold, fontSize: 24.0))
: null,
messageText: Text(messageText,
textAlign: TextAlign.center,
style: TextStyle(color: isDark ? Colors.white : Colors.black)),
style: TextStyle(color: isDark ? Colors.white : Colors.black, fontSize: 16)),
duration: duration,
isDismissible: isDismissible,
flushbarPosition: FlushbarPosition.TOP,

View file

@ -0,0 +1,28 @@
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/entities/fiat_currency.dart';
part 'buy_amount_view_model.g.dart';
class BuyAmountViewModel = BuyAmountViewModelBase with _$BuyAmountViewModel;
abstract class BuyAmountViewModelBase with Store {
BuyAmountViewModelBase() : amount = '';
@observable
String amount;
FiatCurrency get fiatCurrency => FiatCurrency.usd;
@computed
double get doubleAmount {
double _amount;
try {
_amount = double.parse(amount.replaceAll(',', '.')) ?? 0.0;
} catch (e) {
_amount = 0.0;
}
return _amount;
}
}

View file

@ -0,0 +1,29 @@
import 'package:cake_wallet/buy/buy_amount.dart';
import 'package:cake_wallet/buy/buy_provider.dart';
import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cake_wallet/view_model/buy/buy_amount_view_model.dart';
class BuyItem {
BuyItem({this.provider, this.buyAmountViewModel});
final BuyProvider provider;
final BuyAmountViewModel buyAmountViewModel;
double get amount => buyAmountViewModel.doubleAmount;
FiatCurrency get fiatCurrency => buyAmountViewModel.fiatCurrency;
Future<BuyAmount> get buyAmount async {
BuyAmount _buyAmount;
try {
_buyAmount = await provider
.calculateAmount(amount?.toString(), fiatCurrency.title);
} catch (e) {
_buyAmount = BuyAmount(sourceAmount: 0.0, destAmount: 0.0);
print(e.toString());
}
return _buyAmount;
}
}

View file

@ -0,0 +1,110 @@
import 'package:cake_wallet/buy/buy_provider.dart';
import 'package:cake_wallet/buy/moonpay/moonpay_buy_provider.dart';
import 'package:cake_wallet/buy/wyre/wyre_buy_provider.dart';
import 'package:cake_wallet/entities/crypto_currency.dart';
import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cake_wallet/entities/wallet_type.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/view_model/buy/buy_item.dart';
import 'package:flutter/foundation.dart';
import 'package:hive/hive.dart';
import 'package:cake_wallet/buy/order.dart';
import 'package:cake_wallet/store/dashboard/orders_store.dart';
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/core/wallet_base.dart';
import 'buy_amount_view_model.dart';
part 'buy_view_model.g.dart';
class BuyViewModel = BuyViewModelBase with _$BuyViewModel;
abstract class BuyViewModelBase with Store {
BuyViewModelBase(this.ordersSource, this.ordersStore, this.settingsStore,
this.buyAmountViewModel, {@required this.wallet}) {
_fetchBuyItems();
isRunning = false;
isDisabled = true;
isShowProviderButtons = false;
}
final Box<Order> ordersSource;
final OrdersStore ordersStore;
final SettingsStore settingsStore;
final BuyAmountViewModel buyAmountViewModel;
final WalletBase wallet;
@observable
BuyProvider selectedProvider;
@observable
List<BuyItem> items;
@observable
bool isRunning;
@observable
bool isDisabled;
@observable
bool isShowProviderButtons;
WalletType get type => wallet.type;
double get doubleAmount => buyAmountViewModel.doubleAmount;
FiatCurrency get fiatCurrency => buyAmountViewModel.fiatCurrency;
CryptoCurrency get cryptoCurrency => walletTypeToCryptoCurrency(type);
Future <String> fetchUrl() async {
String _url = '';
try {
_url = await selectedProvider
?.requestUrl(doubleAmount?.toString(), fiatCurrency.title);
} catch (e) {
print(e.toString());
}
return _url;
}
Future<void> saveOrder(String orderId) async {
try {
final order = await selectedProvider?.findOrderById(orderId);
order.from = fiatCurrency.title;
order.to = cryptoCurrency.title;
await ordersSource.add(order);
ordersStore.setOrder(order);
} catch (e) {
print(e.toString());
}
}
void reset() {
buyAmountViewModel.amount = '';
selectedProvider = null;
}
Future<void> _fetchBuyItems() async {
final List<BuyProvider> _providerList = [WyreBuyProvider(wallet: wallet)];
var isMoonPayEnabled = false;
try {
isMoonPayEnabled = await MoonPayBuyProvider.onEnabled();
} catch (e) {
isMoonPayEnabled = false;
print(e.toString());
}
if (isMoonPayEnabled) {
_providerList.add(MoonPayBuyProvider(wallet: wallet));
}
items = _providerList.map((provider) =>
BuyItem(provider: provider, buyAmountViewModel: buyAmountViewModel))
.toList();
}
}

View file

@ -1,6 +1,9 @@
import 'package:cake_wallet/core/transaction_history.dart';
import 'package:cake_wallet/entities/balance.dart';
import 'package:cake_wallet/entities/order.dart';
import 'package:cake_wallet/entities/push_notifications_service.dart';
import 'package:cake_wallet/buy/order.dart';
import 'package:cake_wallet/entities/transaction_history.dart';
import 'package:cake_wallet/exchange/trade_state.dart';
import 'package:cake_wallet/monero/account.dart';
import 'package:cake_wallet/monero/monero_balance.dart';
import 'package:cake_wallet/monero/monero_transaction_info.dart';
@ -17,7 +20,9 @@ import 'package:cake_wallet/view_model/dashboard/order_list_item.dart';
import 'package:cake_wallet/view_model/dashboard/trade_list_item.dart';
import 'package:cake_wallet/view_model/dashboard/transaction_list_item.dart';
import 'package:cake_wallet/view_model/dashboard/action_list_item.dart';
import 'package:cake_wallet/view_model/wyre_view_model.dart';
import 'package:cake_wallet/view_model/dashboard/action_list_display_mode.dart';
import 'package:crypto/crypto.dart';
import 'package:flutter/services.dart';
import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/core/wallet_base.dart';
@ -42,9 +47,9 @@ abstract class DashboardViewModelBase with Store {
this.tradeFilterStore,
this.transactionFilterStore,
this.settingsStore,
this.ordersSource,
this.ordersStore,
this.wyreViewModel}) {
PushNotificationsService pushNotificationsService}) {
_pushNotificationsService = pushNotificationsService;
filterItems = {
S.current.transactions: [
FilterItem(
@ -79,8 +84,6 @@ abstract class DashboardViewModelBase with Store {
]
};
isRunningWebView = false;
name = appStore.wallet?.name;
wallet ??= appStore.wallet;
type = wallet.type;
@ -133,6 +136,8 @@ abstract class DashboardViewModelBase with Store {
return true;
});
Future.delayed(Duration(seconds: 2), () => _pushNotificationsService.init());
}
@observable
@ -147,9 +152,6 @@ abstract class DashboardViewModelBase with Store {
@observable
String subname;
@observable
bool isRunningWebView;
@computed
String get address => wallet.address;
@ -205,8 +207,6 @@ abstract class DashboardViewModelBase with Store {
bool get hasRescan => wallet.type == WalletType.monero;
Box<Order> ordersSource;
BalanceViewModel balanceViewModel;
AppStore appStore;
@ -221,24 +221,24 @@ abstract class DashboardViewModelBase with Store {
TransactionFilterStore transactionFilterStore;
WyreViewModel wyreViewModel;
Map<String, List<FilterItem>> filterItems;
bool get isBuyEnabled => settingsStore.isBitcoinBuyEnabled;
PushNotificationsService _pushNotificationsService;
ReactionDisposer _onMoneroAccountChangeReaction;
ReactionDisposer _onMoneroBalanceChangeReaction;
@observable
bool isOutdatedElectrumWallet;
Future<void> reconnect() async {
final node = appStore.settingsStore.getCurrentNode(wallet.type);
await wallet.connectToNode(node: node);
}
@observable
bool isOutdatedElectrumWallet;
@action
void _onWalletChange(
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>,

View file

@ -1,4 +1,4 @@
import 'package:cake_wallet/entities/order.dart';
import 'package:cake_wallet/buy/order.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/view_model/dashboard/action_list_item.dart';
import 'package:cake_wallet/entities/balance_display_mode.dart';

View file

@ -45,7 +45,7 @@ abstract class ExchangeTradeViewModelBase with Store {
_updateTrade();
_timer = Timer.periodic(Duration(seconds: 20), (_) async => _updateTrade());
timer = Timer.periodic(Duration(seconds: 20), (_) async => _updateTrade());
}
final WalletBase wallet;
@ -71,7 +71,7 @@ abstract class ExchangeTradeViewModelBase with Store {
ExchangeProvider _provider;
Timer _timer;
Timer timer;
@action
Future confirmSending() async {

View file

@ -1,12 +1,16 @@
import 'dart:async';
import 'package:cake_wallet/entities/order.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/utils/date_formatter.dart';
import 'package:cake_wallet/view_model/wyre_view_model.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:url_launcher/url_launcher.dart';
import 'package:cake_wallet/core/wallet_base.dart';
import 'package:cake_wallet/buy/moonpay/moonpay_buy_provider.dart';
import 'package:cake_wallet/buy/wyre/wyre_buy_provider.dart';
part 'order_details_view_model.g.dart';
@ -14,16 +18,27 @@ class OrderDetailsViewModel = OrderDetailsViewModelBase
with _$OrderDetailsViewModel;
abstract class OrderDetailsViewModelBase with Store {
OrderDetailsViewModelBase({this.wyreViewModel, Order orderForDetails}) {
OrderDetailsViewModelBase({WalletBase wallet, Order orderForDetails}) {
order = orderForDetails;
if (order.provider != null) {
switch (order.provider) {
case BuyProviderDescription.wyre:
_provider = WyreBuyProvider(wallet: wallet);
break;
case BuyProviderDescription.moonPay:
_provider = MoonPayBuyProvider(wallet: wallet);
break;
}
}
items = ObservableList<StandartListItem>();
_updateItems();
_updateOrder();
_timer = Timer.periodic(Duration(seconds: 20), (_) async => _updateOrder());
timer = Timer.periodic(Duration(seconds: 20), (_) async => _updateOrder());
}
@observable
@ -32,21 +47,25 @@ abstract class OrderDetailsViewModelBase with Store {
@observable
ObservableList<StandartListItem> items;
WyreViewModel wyreViewModel;
BuyProvider _provider;
Timer _timer;
Timer timer;
@action
Future<void> _updateOrder() async {
try {
final updatedOrder =
await wyreViewModel.wyreService.findOrderById(order.id);
updatedOrder.receiveAddress = order.receiveAddress;
updatedOrder.walletId = order.walletId;
order = updatedOrder;
_updateItems();
if (_provider != null) {
final updatedOrder = await _provider.findOrderById(order.id);
updatedOrder.from = order.from;
updatedOrder.to = order.to;
updatedOrder.receiveAddress = order.receiveAddress;
updatedOrder.walletId = order.walletId;
if (order.provider != null) {
updatedOrder.providerRaw = order.provider.raw;
}
order = updatedOrder;
_updateItems();
}
} catch (e) {
print(e.toString());
}
@ -54,8 +73,6 @@ abstract class OrderDetailsViewModelBase with Store {
void _updateItems() {
final dateFormat = DateFormatter.withCurrentLocal();
final buildURL =
wyreViewModel.trackUrl + '${order.transferId}';
items?.clear();
@ -68,18 +85,37 @@ abstract class OrderDetailsViewModelBase with Store {
value: order.state != null
? order.state.toString()
: S.current.trade_details_fetching),
TrackTradeListItem(
title: 'Track',
value: buildURL,
onTap: () {
launch(buildURL);
}),
StandartListItem(
title: S.current.trade_details_created_at,
value: dateFormat.format(order.createdAt).toString()),
StandartListItem(
title: S.current.trade_details_pair,
value: '${order.from}${order.to}')
]);
if (order.provider != null) {
items.add(
StandartListItem(
title: 'Buy provider',
value: order.provider.title)
);
}
if (_provider?.trackUrl?.isNotEmpty ?? false) {
final buildURL = _provider.trackUrl + '${order.transferId}';
items.add(
TrackTradeListItem(
title: 'Track',
value: buildURL,
onTap: () => launch(buildURL)
)
);
}
items.add(
StandartListItem(
title: S.current.trade_details_created_at,
value: dateFormat.format(order.createdAt).toString())
);
items.add(
StandartListItem(
title: S.current.trade_details_pair,
value: '${order.from}${order.to}')
);
}
}

View file

@ -24,6 +24,15 @@ abstract class SupportViewModelBase with Store {
title: 'Email',
linkTitle: 'support@cakewallet.com',
link: 'mailto:support@cakewallet.com'),
LinkListItem(
title: 'Website',
linkTitle: 'cakewallet.com',
link: 'https://cakewallet.com'),
LinkListItem(
title: 'GitHub',
icon: 'assets/images/github.png',
linkTitle: S.current.apk_update,
link: 'https://github.com/cake-tech/cake_wallet/releases'),
LinkListItem(
title: 'Telegram',
icon: 'assets/images/Telegram.png',

View file

@ -39,7 +39,7 @@ abstract class TradeDetailsViewModelBase with Store {
_updateTrade();
_timer = Timer.periodic(Duration(seconds: 20), (_) async => _updateTrade());
timer = Timer.periodic(Duration(seconds: 20), (_) async => _updateTrade());
}
final Box<Trade> trades;
@ -52,7 +52,7 @@ abstract class TradeDetailsViewModelBase with Store {
ExchangeProvider _provider;
Timer _timer;
Timer timer;
@action
Future<void> _updateTrade() async {

View file

@ -1,11 +1,14 @@
import 'package:cake_wallet/bitcoin/electrum_transaction_info.dart';
import 'package:cake_wallet/core/wallet_base.dart';
import 'package:cake_wallet/entities/transaction_info.dart';
import 'package:cake_wallet/entities/wallet_type.dart';
import 'package:cake_wallet/monero/monero_transaction_info.dart';
import 'package:cake_wallet/monero/monero_wallet.dart';
import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart';
import 'package:cake_wallet/src/screens/transaction_details/textfield_list_item.dart';
import 'package:cake_wallet/src/screens/transaction_details/transaction_details_list_item.dart';
import 'package:cake_wallet/src/screens/transaction_details/blockexplorer_list_item.dart';
import 'package:cake_wallet/entities/transaction_direction.dart';
import 'package:cake_wallet/utils/date_formatter.dart';
import 'package:cake_wallet/entities/transaction_description.dart';
import 'package:hive/hive.dart';
@ -23,6 +26,7 @@ abstract class TransactionDetailsViewModelBase with Store {
TransactionDetailsViewModelBase(
{this.transactionInfo,
this.transactionDescriptionBox,
this.wallet,
this.settingsStore})
: items = [] {
showRecipientAddress = settingsStore?.shouldSaveRecipientAddress ?? false;
@ -51,6 +55,25 @@ abstract class TransactionDetailsViewModelBase with Store {
StandartListItem(title: S.current.transaction_key, value: tx.key));
}
if ((tx.direction == TransactionDirection.incoming)&&
(wallet is MoneroWallet)) {
try {
final accountIndex = tx.accountIndex;
final addressIndex = tx.addressIndex;
final _wallet = wallet as MoneroWallet;
final address =
_wallet.getTransactionAddress(accountIndex, addressIndex);
if (address?.isNotEmpty ?? false) {
_items.add(
StandartListItem(
title: S.current.transaction_details_recipient_address,
value: address));
}
} catch (e) {
print(e.toString());
}
}
items.addAll(_items);
}
@ -124,6 +147,7 @@ abstract class TransactionDetailsViewModelBase with Store {
final TransactionInfo transactionInfo;
final Box<TransactionDescription> transactionDescriptionBox;
final SettingsStore settingsStore;
final WalletBase wallet;
final List<TransactionDetailsListItem> items;
bool showRecipientAddress;

View file

@ -1,34 +0,0 @@
import 'package:cake_wallet/entities/wyre_service.dart';
import 'package:flutter/foundation.dart';
import 'package:hive/hive.dart';
import 'package:cake_wallet/entities/order.dart';
import 'package:cake_wallet/store/dashboard/orders_store.dart';
import 'package:mobx/mobx.dart';
part 'wyre_view_model.g.dart';
class WyreViewModel = WyreViewModelBase with _$WyreViewModel;
abstract class WyreViewModelBase with Store {
WyreViewModelBase(this.ordersSource, this.ordersStore,
{@required this.wyreService});
Future<String> get wyreUrl => wyreService.getWyreUrl();
String get trackUrl => wyreService.trackUrl;
final Box<Order> ordersSource;
final OrdersStore ordersStore;
final WyreService wyreService;
Future<void> saveOrder(String orderId) async {
try {
final order = await wyreService.findOrderById(orderId);
await ordersSource.add(order);
ordersStore.setOrder(order);
} catch (e) {
print(e.toString());
}
}
}

View file

@ -362,6 +362,34 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0-nullsafety.2"
firebase_core:
dependency: transitive
description:
name: firebase_core
url: "https://pub.dartlang.org"
source: hosted
version: "0.5.3"
firebase_core_platform_interface:
dependency: transitive
description:
name: firebase_core_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
firebase_core_web:
dependency: transitive
description:
name: firebase_core_web
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.1+1"
firebase_messaging:
dependency: "direct main"
description:
name: firebase_messaging
url: "https://pub.dartlang.org"
source: hosted
version: "7.0.3"
fixnum:
dependency: transitive
description:
@ -565,7 +593,7 @@ packages:
name: local_auth
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.1"
version: "1.1.6"
logging:
dependency: transitive
description:

View file

@ -11,7 +11,7 @@ description: Cake Wallet.
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 4.2.0+49
version: 4.2.3+53
environment:
sdk: ">=2.7.0 <3.0.0"
@ -49,7 +49,7 @@ dependencies:
path: ./cw_monero
hive: ^1.4.4+1
hive_flutter: ^0.3.1
local_auth: ^1.1.1
local_auth: ^1.1.6
package_info: ^2.0.0
devicelocale: ^0.4.1
auto_size_text: ^2.1.0
@ -78,6 +78,7 @@ dependencies:
file_picker: ^3.0.0-nullsafety.2
unorm_dart: ^0.2.0
permission_handler: ^5.0.1+1
firebase_messaging: ^7.0.3
dev_dependencies:
flutter_test:
@ -151,4 +152,4 @@ flutter:
# weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.dev/custom-fonts/#from-packages
# see https://flutter.dev/custom-fonts/#from-packages

View file

@ -473,9 +473,22 @@
"buy_alert_content" : "Derzeit unterstützen wir nur den Kauf von Bitcoin. Um Bitcoin zu kaufen, erstellen Sie bitte Ihre Bitcoin-Brieftasche oder wechseln Sie zu dieser",
"outdated_electrum_wallet_desceription" : "New Bitcoin wallets created in Cake now have a 24-word seed. It is mandatory that you create a new Bitcoin wallet and transfer all of your funds to the new 24-word wallet, and stop using wallets with a 12-word seed. Please do this immediately to secure your funds.",
"understand" : "I understand",
"address_detected" : "Adresse erkannt",
"address_from_domain" : "Sie haben die Adresse von der unaufhaltsamen Domain ${domain} erhalten"
"address_from_domain" : "Sie haben die Adresse von der unaufhaltsamen Domain ${domain} erhalten",
"outdated_electrum_wallet_description" : "Neue Bitcoin-Geldbörsen, die in Cake erstellt wurden, haben jetzt einen Startwert von 24 Wörtern. Es ist obligatorisch, dass Sie eine neue Bitcoin-Brieftasche erstellen, Ihr gesamtes Geld in die neue 24-Wörter-Brieftasche überweisen und keine Brieftaschen mit einem 12-Wörter-Startwert mehr verwenden. Bitte tun Sie dies sofort, um Ihr Geld zu sichern.",
"understand" : "Ich verstehe",
"apk_update" : "APK Update",
"buy_bitcoin" : "Bitcoin kaufen",
"buy_with" : "Kaufen mit",
"moonpay_alert_text" : "Der Wert des Betrags muss größer oder gleich sein ${minAmount} ${fiatCurrency}",
"outdated_electrum_wallet_receive_warning": "Wenn diese Brieftasche einen 12-Wort-Seed hat und in Cake erstellt wurde, zahlen Sie KEINE Bitcoins in diese Brieftasche ein. Alle auf diese Wallet übertragenen BTC können verloren gehen. Erstellen Sie eine neue 24-Wort-Wallet (tippen Sie auf das Menü oben rechts, wählen Sie Wallets, wählen Sie Create New Wallet und dann Bitcoin) und verschieben Sie Ihre BTC SOFORT dorthin. Neue (24 Wörter) BTC-Wallets von Cake sind sicher",
"do_not_show_me": "Zeig mir das nicht noch einmal"
}

View file

@ -473,9 +473,18 @@
"buy_alert_content" : "Currently we only support the purchase of Bitcoin. To buy Bitcoin, please create or switch to your Bitcoin wallet",
"outdated_electrum_wallet_desceription" : "New Bitcoin wallets created in Cake now have a 24-word seed. It is mandatory that you create a new Bitcoin wallet and transfer all of your funds to the new 24-word wallet, and stop using wallets with a 12-word seed. Please do this immediately to secure your funds.",
"outdated_electrum_wallet_description" : "New Bitcoin wallets created in Cake now have a 24-word seed. It is mandatory that you create a new Bitcoin wallet and transfer all of your funds to the new 24-word wallet, and stop using wallets with a 12-word seed. Please do this immediately to secure your funds.",
"understand" : "I understand",
"address_detected" : "Address detected",
"address_from_domain" : "You got address from unstoppable domain ${domain}"
"address_from_domain" : "You got address from unstoppable domain ${domain}",
"apk_update" : "APK update",
"buy_bitcoin" : "Buy Bitcoin",
"buy_with" : "Buy with",
"moonpay_alert_text" : "Value of the amount must be more or equal to ${minAmount} ${fiatCurrency}",
"outdated_electrum_wallet_receive_warning": "If this wallet has a 12-word seed and was created in Cake, DO NOT deposit Bitcoin into this wallet. Any BTC transferred to this wallet may be lost. Create a new 24-word wallet (tap the menu at the top right, select Wallets, choose Create New Wallet, then select Bitcoin) and IMMEDIATELY move your BTC there. New (24-word) BTC wallets from Cake are secure",
"do_not_show_me": "Do not show me this again"
}

View file

@ -472,10 +472,19 @@
"submit_request" : "presentar una solicitud",
"buy_alert_content" : "Actualmente solo apoyamos la compra de Bitcoin. Para comprar Bitcoin, cree o cambie a su billetera Bitcoin",
"outdated_electrum_wallet_desceription" : "New Bitcoin wallets created in Cake now have a 24-word seed. It is mandatory that you create a new Bitcoin wallet and transfer all of your funds to the new 24-word wallet, and stop using wallets with a 12-word seed. Please do this immediately to secure your funds.",
"understand" : "I understand",
"outdated_electrum_wallet_description" : "Las nuevas carteras de Bitcoin creadas en Cake ahora tienen una semilla de 24 palabras. Es obligatorio que cree una nueva billetera de Bitcoin y transfiera todos sus fondos a la nueva billetera de 24 palabras, y deje de usar billeteras con una semilla de 12 palabras. Haga esto de inmediato para asegurar sus fondos.",
"understand" : "Entiendo",
"address_detected" : "Dirección detectada",
"address_from_domain" : "Tienes la dirección de unstoppable domain ${domain}"
"address_from_domain" : "Tienes la dirección de unstoppable domain ${domain}",
"apk_update" : "Actualización de APK",
"buy_bitcoin" : "Comprar Bitcoin",
"buy_with" : "Compra con",
"moonpay_alert_text" : "El valor de la cantidad debe ser mayor o igual a ${minAmount} ${fiatCurrency}",
"outdated_electrum_wallet_receive_warning": "Si esta billetera tiene una semilla de 12 palabras y se creó en Cake, NO deposite Bitcoin en esta billetera. Cualquier BTC transferido a esta billetera se puede perder. Cree una nueva billetera de 24 palabras (toque el menú en la parte superior derecha, seleccione Monederos, elija Crear nueva billetera, luego seleccione Bitcoin) e INMEDIATAMENTE mueva su BTC allí. Las nuevas carteras BTC (24 palabras) de Cake son seguras",
"do_not_show_me": "no me muestres esto otra vez"
}

View file

@ -473,9 +473,18 @@
"buy_alert_content" : "वर्तमान में हम केवल बिटकॉइन की खरीद का समर्थन करते हैं। बिटकॉइन खरीदने के लिए, कृपया अपना बिटकॉइन वॉलेट बनाएं या स्विच करें",
"outdated_electrum_wallet_desceription" : "New Bitcoin wallets created in Cake now have a 24-word seed. It is mandatory that you create a new Bitcoin wallet and transfer all of your funds to the new 24-word wallet, and stop using wallets with a 12-word seed. Please do this immediately to secure your funds.",
"understand" : "I understand",
"outdated_electrum_wallet_description" : "केक में बनाए गए नए बिटकॉइन वॉलेट में अब 24-शब्द का बीज है। यह अनिवार्य है कि आप एक नया बिटकॉइन वॉलेट बनाएं और अपने सभी फंड को नए 24-शब्द वाले वॉलेट में स्थानांतरित करें, और 12-शब्द बीज वाले वॉलेट का उपयोग करना बंद करें। कृपया अपने धन को सुरक्षित करने के लिए इसे तुरंत करें।",
"understand" : "मुझे समझ",
"address_detected" : "पता लग गया",
"address_from_domain" : "आपको अजेय डोमेन ${domain} से पता मिला है"
"apk_update" : "APK अद्यतन",
"buy_bitcoin" : "बिटकॉइन खरीदें",
"buy_with" : "के साथ खरीदें",
"moonpay_alert_text" : "राशि का मूल्य अधिक है या करने के लिए बराबर होना चाहिए ${minAmount} ${fiatCurrency}",
"outdated_electrum_wallet_receive_warning": "अगर इस वॉलेट में 12 शब्दों का बीज है और इसे केक में बनाया गया है, तो इस वॉलेट में बिटकॉइन जमा न करें। इस वॉलेट में स्थानांतरित किया गया कोई भी बीटीसी खो सकता है। एक नया 24-शब्द वॉलेट बनाएं (ऊपर दाईं ओर स्थित मेनू पर टैप करें, वॉलेट चुनें, नया वॉलेट बनाएं चुनें, फिर बिटकॉइन चुनें) और तुरंत अपना बीटीसी वहां ले जाएं। केक से नए (24-शब्द) बीटीसी वॉलेट सुरक्षित हैं",
"do_not_show_me": "मुझे यह फिर न दिखाएं"
}

View file

@ -471,11 +471,20 @@
"submit_request" : "podnesi zahtjev",
"buy_alert_content" : "Currently we only support the purchase of Bitcoin. To buy Bitcoin, please create or switch to your Bitcoin wallet",
"outdated_electrum_wallet_desceription" : "New Bitcoin wallets created in Cake now have a 24-word seed. It is mandatory that you create a new Bitcoin wallet and transfer all of your funds to the new 24-word wallet, and stop using wallets with a 12-word seed. Please do this immediately to secure your funds.",
"understand" : "I understand",
"buy_alert_content" : "Trenutno podržavamo samo kupnju Bitcoina. Da biste kupili Bitcoin, izradite ili prijeđite na svoj Bitcoin novčanik",
"outdated_electrum_wallet_description" : "Novi Bitcoin novčanici stvoreni u Cakeu sada imaju sjeme od 24 riječi. Obavezno je stvoriti novi Bitcoin novčanik i prenijeti sva svoja sredstva u novi novčanik od 24 riječi te prestati koristiti novčanike s sjemenkom od 12 riječi. Učinite to odmah kako biste osigurali svoja sredstva.",
"understand" : "Razumijem",
"address_detected" : "Adresa je otkrivena",
"address_from_domain" : "Dobili ste adresu od unstoppable domain ${domain}"
"address_from_domain" : "Dobili ste adresu od unstoppable domain ${domain}",
"apk_update" : "APK ažuriranje",
"buy_bitcoin" : "Kupite Bitcoin",
"buy_with" : "Kupite s",
"moonpay_alert_text" : "Vrijednost iznosa mora biti veća ili jednaka ${minAmount} ${fiatCurrency}",
"outdated_electrum_wallet_receive_warning": "Ako ovaj novčanik sadrži sjeme od 12 riječi i stvoren je u Torti, NEMOJTE polagati Bitcoin u ovaj novčanik. Bilo koji BTC prebačen u ovaj novčanik može se izgubiti. Stvorite novi novčanik od 24 riječi (taknite izbornik u gornjem desnom dijelu, odaberite Novčanici, odaberite Stvori novi novčanik, a zatim odaberite Bitcoin) i ODMAH premjestite svoj BTC tamo. Novi BTC novčanici (s 24 riječi) tvrtke Cake sigurni su",
"do_not_show_me": "Ne pokazuj mi ovo više"
}

View file

@ -471,11 +471,20 @@
"submit_request" : "invia una richiesta",
"buy_alert_content" : "Currently we only support the purchase of Bitcoin. To buy Bitcoin, please create or switch to your Bitcoin wallet",
"buy_alert_content" : "Attualmente supportiamo solo l'acquisto di Bitcoin. Per acquistare Bitcoin, crea o passa al tuo portafoglio Bitcoin",
"outdated_electrum_wallet_description" : "I nuovi portafogli Bitcoin creati in Cake ora hanno un seme di 24 parole. È obbligatorio creare un nuovo portafoglio Bitcoin e trasferire tutti i fondi nel nuovo portafoglio di 24 parole e smettere di usare portafogli con un seme di 12 parole. Ti preghiamo di farlo immediatamente per proteggere i tuoi fondi.",
"understand" : "Capisco",
"outdated_electrum_wallet_desceription" : "New Bitcoin wallets created in Cake now have a 24-word seed. It is mandatory that you create a new Bitcoin wallet and transfer all of your funds to the new 24-word wallet, and stop using wallets with a 12-word seed. Please do this immediately to secure your funds.",
"understand" : "I understand",
"address_detected" : "Indirizzo rilevato",
"address_from_domain" : "Hai l'indirizzo da unstoppable domain ${domain}"
"address_from_domain" : "Hai l'indirizzo da unstoppable domain ${domain}",
"apk_update" : "Aggiornamento APK",
"buy_bitcoin" : "Acquista Bitcoin",
"buy_with" : "Acquista con",
"moonpay_alert_text" : "Il valore dell'importo deve essere maggiore o uguale a ${minAmount} ${fiatCurrency}",
"outdated_electrum_wallet_receive_warning": "Se questo portafoglio ha un seme di 12 parole ed è stato creato in Cake, NON depositare Bitcoin in questo portafoglio. Qualsiasi BTC trasferito su questo portafoglio potrebbe andare perso. Crea un nuovo portafoglio di 24 parole (tocca il menu in alto a destra, seleziona Portafogli, scegli Crea nuovo portafoglio, quindi seleziona Bitcoin) e sposta IMMEDIATAMENTE lì il tuo BTC. I nuovi portafogli BTC (24 parole) di Cake sono sicuri",
"do_not_show_me": "Non mostrarmelo di nuovo"
}

View file

@ -473,9 +473,18 @@
"buy_alert_content" : "現在、ビットコインの購入のみをサポートしています。 ビットコインを購入するには、ビットコインウォレットを作成するか切り替えてください",
"outdated_electrum_wallet_desceription" : "New Bitcoin wallets created in Cake now have a 24-word seed. It is mandatory that you create a new Bitcoin wallet and transfer all of your funds to the new 24-word wallet, and stop using wallets with a 12-word seed. Please do this immediately to secure your funds.",
"understand" : "I understand",
"outdated_electrum_wallet_description" : "Cakeで作成された新しいビットコインウォレットには、24ワードのシードがあります。 新しいビットコインウォレットを作成し、すべての資金を新しい24ワードのウォレットに転送し、12ワードのシードを持つウォレットの使用を停止することが必須です。 あなたの資金を確保するためにこれをすぐに行ってください。",
"understand" : "わかります",
"address_detected" : "アドレスが検出されました",
"address_from_domain" : "あなたはからアドレスを得ました unstoppable domain ${domain}"
"address_from_domain" : "あなたはからアドレスを得ました unstoppable domain ${domain}",
"apk_update" : "APKアップデート",
"buy_bitcoin" : "ビットコインを購入する",
"buy_with" : "で購入",
"moonpay_alert_text" : "金額の値は以上でなければなりません ${minAmount} ${fiatCurrency}",
"outdated_electrum_wallet_receive_warning": "このウォレットに 12 ワードのシードがあり、Cake で作成された場合、このウォレットにビットコインを入金しないでください。 このウォレットに転送された BTC は失われる可能性があります。 新しい 24 ワードのウォレットを作成し (右上のメニューをタップし、[ウォレット]、[新しいウォレットの作成]、[ビットコイン] の順に選択)、すぐに BTC をそこに移動します。 Cake の新しい (24 ワード) BTC ウォレットは安全です",
"do_not_show_me": "また僕にこれを見せないでください"
}

View file

@ -473,9 +473,18 @@
"buy_alert_content" : "현재 우리는 비트 코인 구매 만 지원합니다. 비트 코인을 구매하려면 비트 코인 지갑을 생성하거나 전환하십시오",
"outdated_electrum_wallet_desceription" : "New Bitcoin wallets created in Cake now have a 24-word seed. It is mandatory that you create a new Bitcoin wallet and transfer all of your funds to the new 24-word wallet, and stop using wallets with a 12-word seed. Please do this immediately to secure your funds.",
"understand" : "I understand",
"outdated_electrum_wallet_description" : "Cake에서 생성 된 새로운 비트 코인 지갑에는 이제 24 단어 시드가 있습니다. 새로운 비트 코인 지갑을 생성하고 모든 자금을 새로운 24 단어 지갑으로 이체하고 12 단어 시드가있는 지갑 사용을 중지해야합니다. 자금을 확보하려면 즉시이 작업을 수행하십시오.",
"understand" : "이해 했어요",
"address_detected" : "주소 감지",
"address_from_domain" : "주소는 unstoppable domain ${domain}"
"address_from_domain" : "주소는 unstoppable domain ${domain}",
"apk_update" : "APK 업데이트",
"buy_bitcoin" : "비트 코인 구매",
"buy_with" : "구매",
"moonpay_alert_text" : "금액은 다음보다 크거나 같아야합니다 ${minAmount} ${fiatCurrency}",
"outdated_electrum_wallet_receive_warning": "이 지갑에 12 단어 시드가 있고 Cake에서 생성 된 경우이 지갑에 비트 코인을 입금하지 마십시오. 이 지갑으로 전송 된 모든 BTC는 손실 될 수 있습니다. 새로운 24 단어 지갑을 생성하고 (오른쪽 상단의 메뉴를 탭하고 지갑을 선택한 다음 새 지갑 생성을 선택한 다음 비트 코인을 선택하십시오) 즉시 BTC를 그곳으로 이동하십시오. Cake의 새로운 (24 단어) BTC 지갑은 안전합니다",
"do_not_show_me": "나를 다시 표시하지 않음"
}

View file

@ -473,9 +473,18 @@
"buy_alert_content" : "Momenteel ondersteunen we alleen de aankoop van Bitcoin. Om Bitcoin te kopen, moet u uw Bitcoin-portemonnee aanmaken of naar uw Bitcoin-portemonnee overschakelen",
"outdated_electrum_wallet_desceription" : "New Bitcoin wallets created in Cake now have a 24-word seed. It is mandatory that you create a new Bitcoin wallet and transfer all of your funds to the new 24-word wallet, and stop using wallets with a 12-word seed. Please do this immediately to secure your funds.",
"understand" : "I understand",
"outdated_electrum_wallet_description" : "Nieuwe Bitcoin-portefeuilles die in Cake zijn gemaakt, hebben nu een zaadje van 24 woorden. Het is verplicht dat u een nieuwe Bitcoin-portemonnee maakt en al uw geld overmaakt naar de nieuwe portemonnee van 24 woorden, en stopt met het gebruik van wallets met een seed van 12 woorden. Doe dit onmiddellijk om uw geld veilig te stellen.",
"understand" : "Ik begrijp het",
"address_detected" : "Adres gedetecteerd",
"address_from_domain" : "Je adres is van unstoppable domain ${domain}"
"address_from_domain" : "Je adres is van unstoppable domain ${domain}",
"apk_update" : "APK-update",
"buy_bitcoin" : "Koop Bitcoin",
"buy_with" : "Koop met",
"moonpay_alert_text" : "Waarde van het bedrag moet meer of gelijk zijn aan ${minAmount} ${fiatCurrency}",
"outdated_electrum_wallet_receive_warning": "Als deze portemonnee een seed van 12 woorden heeft en is gemaakt in Cake, stort dan GEEN Bitcoin in deze portemonnee. Elke BTC die naar deze portemonnee is overgebracht, kan verloren gaan. Maak een nieuwe portemonnee van 24 woorden (tik op het menu rechtsboven, selecteer Portefeuilles, kies Nieuwe portemonnee maken en selecteer vervolgens Bitcoin) en verplaats je BTC ONMIDDELLIJK daar. Nieuwe (24-woorden) BTC-portefeuilles van Cake zijn veilig",
"do_not_show_me": "laat me dit niet opnieuw zien"
}

View file

@ -473,9 +473,18 @@
"buy_alert_content" : "Obecnie obsługujemy tylko zakup Bitcoinów. Aby kupić Bitcoin, utwórz lub przełącz się na swój portfel Bitcoin",
"outdated_electrum_wallet_desceription" : "New Bitcoin wallets created in Cake now have a 24-word seed. It is mandatory that you create a new Bitcoin wallet and transfer all of your funds to the new 24-word wallet, and stop using wallets with a 12-word seed. Please do this immediately to secure your funds.",
"understand" : "I understand",
"outdated_electrum_wallet_description" : "Nowe portfele Bitcoin utworzone w Cake mają teraz ziarno składające się z 24 słów. Konieczne jest utworzenie nowego portfela Bitcoin i przeniesienie wszystkich środków do nowego portfela na 24 słowa oraz zaprzestanie korzystania z portfeli z zalążkiem na 12 słów. Zrób to natychmiast, aby zabezpieczyć swoje fundusze.",
"understand" : "Rozumiem",
"address_detected" : "Wykryto adres",
"address_from_domain" : "Dostałeś adres od unstoppable domain ${domain}"
"address_from_domain" : "Dostałeś adres od unstoppable domain ${domain}",
"apk_update" : "Aktualizacja APK",
"buy_bitcoin" : "Kup Bitcoin",
"buy_with" : "Kup za pomocą",
"moonpay_alert_text" : "Wartość kwoty musi być większa lub równa ${minAmount} ${fiatCurrency}",
"outdated_electrum_wallet_receive_warning": "Jeśli ten portfel ma 12-wyrazowy seed i został utworzony w Cake, NIE Wpłacaj Bitcoina do tego portfela. Wszelkie BTC przeniesione do tego portfela mogą zostać utracone. Utwórz nowy portfel z 24 słowami (dotknij menu w prawym górnym rogu, wybierz Portfele, wybierz Utwórz nowy portfel, a następnie Bitcoin) i NATYCHMIAST przenieś tam swoje BTC. Nowe (24 słowa) portfele BTC firmy Cake są bezpieczne",
"do_not_show_me": "Nie pokazuj mi tego ponownie"
}

View file

@ -473,9 +473,18 @@
"buy_alert_content" : "Atualmente, apoiamos apenas a compra de Bitcoin. Para comprar Bitcoin, crie ou mude para sua carteira Bitcoin",
"outdated_electrum_wallet_desceription" : "New Bitcoin wallets created in Cake now have a 24-word seed. It is mandatory that you create a new Bitcoin wallet and transfer all of your funds to the new 24-word wallet, and stop using wallets with a 12-word seed. Please do this immediately to secure your funds.",
"understand" : "I understand",
"outdated_electrum_wallet_description" : "As novas carteiras Bitcoin criadas no Cake agora têm uma semente de 24 palavras. É obrigatório que você crie uma nova carteira Bitcoin e transfira todos os seus fundos para a nova carteira de 24 palavras, e pare de usar carteiras com semente de 12 palavras. Faça isso imediatamente para garantir seus fundos.",
"understand" : "Entendo",
"address_detected" : "Endereço detectado",
"address_from_domain" : "Você obteve o endereço de unstoppable domain ${domain}"
"address_from_domain" : "Você obteve o endereço de unstoppable domain ${domain}",
"apk_update" : "Atualização de APK",
"buy_bitcoin" : "Compre Bitcoin",
"buy_with" : "Compre com",
"moonpay_alert_text" : "O valor do montante deve ser maior ou igual a ${minAmount} ${fiatCurrency}",
"outdated_electrum_wallet_receive_warning": "Se esta carteira tiver uma semente de 12 palavras e foi criada no Cake, NÃO deposite Bitcoin nesta carteira. Qualquer BTC transferido para esta carteira pode ser perdido. Crie uma nova carteira de 24 palavras (toque no menu no canto superior direito, selecione Carteiras, escolha Criar Nova Carteira e selecione Bitcoin) e mova IMEDIATAMENTE seu BTC para lá. As novas carteiras BTC (24 palavras) da Cake são seguras",
"do_not_show_me": "não me mostre isso novamente"
}

View file

@ -473,9 +473,18 @@
"buy_alert_content" : "В настоящее время мы поддерживаем только покупку Bitcoin. Чтобы купить Bitcoin, создайте или переключитесь на ваш Bitcoin кошелек",
"outdated_electrum_wallet_desceription" : "New Bitcoin wallets created in Cake now have a 24-word seed. It is mandatory that you create a new Bitcoin wallet and transfer all of your funds to the new 24-word wallet, and stop using wallets with a 12-word seed. Please do this immediately to secure your funds.",
"understand" : "I understand",
"outdated_electrum_wallet_description" : "Новые биткойн-кошельки, созданные в Cake, теперь содержат мнемоническую фразу из 24 слов. Вы обязательно должны создать новый биткойн-кошелек и перевести все свои средства в новый кошелек из 24 слов, а также прекратить использование кошельков с мнемонической фразой из 12 слов. Пожалуйста, сделайте это немедленно, чтобы обезопасить свои средства.",
"understand" : "Понятно",
"address_detected" : "Обнаружен адрес",
"address_from_domain" : "Вы получили адрес из unstoppable domain ${domain}"
"address_from_domain" : "Вы получили адрес из unstoppable domain ${domain}",
"apk_update" : "Обновление APK",
"buy_bitcoin" : "Купить Bitcoin",
"buy_with" : "Купить с помощью",
"moonpay_alert_text" : "Сумма должна быть больше или равна ${minAmount} ${fiatCurrency}",
"outdated_electrum_wallet_receive_warning": "Если этот кошелек имеет мнемоническую фразу из 12 слов и был создан в Cake, НЕ переводите биткойны на этот кошелек. Любые BTC, переведенные на этот кошелек, могут быть потеряны. Создайте новый кошелек с мнемоническои фразы из 24 слов (коснитесь меню в правом верхнем углу, выберите «Кошельки», выберите «Создать новый кошелек», затем выберите «Bitcoin») и НЕМЕДЛЕННО переведите туда свои BTC. Новые (24 слова) кошельки BTC от Cake безопасны",
"do_not_show_me": "Не показывай мне это больше"
}

View file

@ -473,9 +473,18 @@
"buy_alert_content" : "На даний час ми підтримуємо тільки покупку Bitcoin. Щоб купити Bitcoin, будь ласка, створіть або переключіться на ваш Bitcoin гаманець",
"outdated_electrum_wallet_desceription" : "New Bitcoin wallets created in Cake now have a 24-word seed. It is mandatory that you create a new Bitcoin wallet and transfer all of your funds to the new 24-word wallet, and stop using wallets with a 12-word seed. Please do this immediately to secure your funds.",
"understand" : "I understand",
"outdated_electrum_wallet_description" : "Нові біткойн-гаманці, створені в Cake, тепер містять мнемонічну фразу з 24 слів. Обов’язково стовріть новий біткойн-гаманець, переведіть всі кошти на новий гаманець із 24 слів і припиніть використання гаманців із мнемонічною фразою з 12 слів. Зробіть це негайно, щоб убезпечити свої кошти.",
"understand" : "Зрозуміло",
"address_detected" : "Виявлено адресу",
"address_from_domain" : "Ви отримали адресу від unstoppable domain ${domain}"
"address_from_domain" : "Ви отримали адресу від unstoppable domain ${domain}",
"apk_update" : "Оновлення APK",
"buy_bitcoin" : "Купити Bitcoin",
"buy_with" : "Купити за допомогою",
"moonpay_alert_text" : "Значення суми має бути більшим або дорівнювати ${minAmount} ${fiatCurrency}",
"outdated_electrum_wallet_receive_warning": "Якщо цей гаманець має мнемонічну фразу з 12 слів і був створений у Cake, НЕ переводьте біткойни на цей гаманець. Будь-які BTC, переведений на цей гаманець, можуть бути втраченими. Створіть новий гаманець з мнемонічною фразою з 24 слів (торкніться меню у верхньому правому куті, виберіть Гаманці, виберіть Створити новий гаманець, потім виберіть Bitcoin) і НЕГАЙНО переведіть туди свії BTC. Нові (з мнемонічною фразою з 24 слів) гаманці BTC від Cake надійно захищені",
"do_not_show_me": "Не показуй мені це знову"
}

View file

@ -89,7 +89,7 @@
"trade_is_powered_by" : "该交易由 ${provider}",
"copy_address" : "复制地址",
"exchange_result_confirm" : "点击确认 您将发送 ${fetchingLabel} ${from} 从你的钱包里 ${walletName} 到下面显示的地址。 或者您可以从外部钱包发送到以下地址/ QR码。\n\n请按确认继续或返回以更改金额",
"exchange_result_description" : "您必至少发送 ${fetchingLabel} ${from} 到下一页上显示的地址。 如果您发送的金额少于 ${fetchingLabel} ${from},则可能无法转换,因此无法退还。",
"exchange_result_description" : "您必至少发送 ${fetchingLabel} ${from} 到下一页上显示的地址。 如果您发送的金额少于 ${fetchingLabel} ${from},则可能无法转换,因此无法退还。",
"exchange_result_write_down_ID" : "*请复制或写下您上面显示的ID.",
"confirm" : "确认",
"confirm_sending" : "确认发送",
@ -126,17 +126,17 @@
"change" : "更改",
"remove_node" : "删除节点",
"remove_node_message" : "您确定要删除所选节点吗?",
"remove" : "去掉",
"remove" : "确定",
"delete" : "删除",
"add_new_node" : "添加新节点",
"change_current_node_title" : "更改当前节点",
"node_test" : "测试",
"node_connection_successful" : "连接成功",
"node_connection_failed" : "连接失",
"node_connection_failed" : "连接失",
"new_node_testing" : "新节点测试",
"use" : "使用 ",
"use" : "切换使用",
"digit_pin" : "位 PIN",
@ -175,6 +175,7 @@
"restore_bitcoin_title_from_keys" : "从WIF还原",
"restore_from_date_or_blockheight" : "请输入您创建这个钱包前几天的日期。或者如果您知道区块高度,请输入区块高度",
"seed_reminder" : "请记下这些内容,以防丟失或数据损坏",
"seed_title" : "种子",
"seed_share" : "分享种子",
@ -198,7 +199,7 @@
"send_your_wallet" : "你的钱包",
"send_address" : "${cryptoCurrency} 地址",
"send_payment_id" : "付款编号 (可选的)",
"all" : "所有",
"all" : "全部",
"send_error_minimum_value" : "最小金额为0.01",
"send_error_currency" : "货币只能包含数字",
"send_estimated_fee" : "预估费用:",
@ -230,7 +231,7 @@
"settings_transactions" : "交易情况",
"settings_trades" : "交易",
"settings_display_on_dashboard_list" : "显示在仪表板上",
"settings_all" : "所有",
"settings_all" : "全部",
"settings_only_trades" : "只交易",
"settings_only_transactions" : "仅交易",
"settings_none" : "没有",
@ -282,7 +283,7 @@
"transaction_details_height" : "区块高度",
"transaction_details_amount" : "金额",
"transaction_details_fee" : "手续费",
"transaction_details_copied" : "${title} 复制到剪板",
"transaction_details_copied" : "${title} 复制到剪板",
"transaction_details_recipient_address" : "收件人地址",
@ -396,7 +397,7 @@
"placeholder_contacts" : "您的联系人将显示在这里",
"template" : "模板",
"confirm_delete_template" : "此操作将刪除此模板。 确定吗?",
"confirm_delete_template" : "此操作将刪除此模板。确定吗?",
"confirm_delete_wallet" : "此操作将刪除此钱包。确定吗?",
"picker_description" : "要选择ChangeNOW或MorphToken请先更改您的交易币",
@ -425,13 +426,13 @@
"use_ssl" : "使用SSL",
"color_theme" : "主",
"color_theme" : "主",
"light_theme" : "艳丽",
"bright_theme" : "明亮",
"dark_theme" : "黑暗",
"enter_your_note" : "输入您的笔记...",
"note_optional" : "注(可选)",
"note_tap_to_change" : "注(轻按即可更改)",
"note_optional" : "注(可选)",
"note_tap_to_change" : "注(轻按即可更改)",
"transaction_key" : "交易密码",
"confirmations" : "确认",
"recipient_address" : "收件人地址",
@ -470,11 +471,20 @@
"submit_request" : "提交请求",
"buy_alert_content" : "目前,我們僅支持購買比特幣。 要購買比特幣,請創建或切換到您的比特幣錢包",
"outdated_electrum_wallet_desceription" : "New Bitcoin wallets created in Cake now have a 24-word seed. It is mandatory that you create a new Bitcoin wallet and transfer all of your funds to the new 24-word wallet, and stop using wallets with a 12-word seed. Please do this immediately to secure your funds.",
"understand" : "I understand",
"buy_alert_content" : "目前,我们仅支持购买比特币。要购买比特币,请创建或切换到您的比特币钱包",
"outdated_electrum_wallet_description" : "在Cake创建的新比特币钱包现在有一个24字的种子。你必须创建一个新的比特币钱包并将你所有的资金转移到新的24字钱包并停止使用12字种子的钱包。请立即这样做以保证你的资金安全。",
"understand" : "我已知晓",
"address_detected" : "檢測到地址",
"address_from_domain" : "您有以下地址 unstoppable domain ${domain}"
"address_from_domain" : "您有以下地址 unstoppable domain ${domain}",
"apk_update" : "APK更新",
"buy_bitcoin" : "購買比特幣",
"buy_with" : "與一起購買",
"moonpay_alert_text" : "金額的價值必須大於或等於 ${minAmount} ${fiatCurrency}",
"outdated_electrum_wallet_receive_warning": "如果这个钱包有一个 12 字的种子并且是在 Cake 中创建的,不要将比特币存入这个钱包。 任何转移到此钱包的 BTC 都可能丢失。 创建一个新的 24 字钱包(点击右上角的菜单,选择钱包,选择创建新钱包,然后选择比特币)并立即将您的 BTC 移到那里。 Cake 的新24 字BTC 钱包是安全的",
"do_not_show_me": "不要再让我看这个了"
}