From 16c4d3b1287fd7b13f96fb11aedccf682b38f0f9 Mon Sep 17 00:00:00 2001 From: jwinterm Date: Sat, 16 May 2026 19:04:45 -0400 Subject: [PATCH 1/8] Hardcoded appName cake_wallet -> hash_wallet + nuke changelog modal + Wownero up top MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three semi-independent fixes flagged from a user-facing testing pass: 1. cw_core/lib/root_dir.dart had a hardcoded 'cake_wallet' for the Linux app data dir, bypassing the binary name entirely. That's why ~/.config/cake_wallet/ kept being created even after the project rename. Changed appName const to hash_wallet. Also: - CAKE_WALLET_DIR env-var override -> HASH_WALLET_DIR (with the old name kept as a fallback so users migrating from a Cake install via env-var don't lose their path). - linuxSymlinkSharedPreferences kept the legacy ['com.example.cake_wallet','cake_wallet'] paths in the migration array so existing Cake users get auto-migrated into hash_wallet's new home on first launch of the fork. 2. lib/new-ui/new_dashboard.dart: commented out the Future.delayed(300ms).then(_showChangelog) trigger. The changelog content lives under assets/new-ui/changelog/text and describes Cake's v6.1.0 release notes — not ours. The 'View more info' button inside the modal launched blog.cakewallet.com. Re-enable once we write our own changelog content. 3. tool/configure.dart: WalletType.wownero hoisted to the top of the generated availableWalletTypes list. It's the reason this fork exists, so it should be the first choice in create / restore pickers. Monero stays as #2. --- cw_core/lib/root_dir.dart | 14 ++++++++++---- tool/configure.dart | 9 ++++++--- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/cw_core/lib/root_dir.dart b/cw_core/lib/root_dir.dart index 7f75b20f..93293740 100644 --- a/cw_core/lib/root_dir.dart +++ b/cw_core/lib/root_dir.dart @@ -24,7 +24,10 @@ bool get isNonAmnesticTails { bool showNotice = true; void setRootDirFromEnv() => - _rootDirPath = Platform.environment['CAKE_WALLET_DIR']; + // HASH_WALLET_DIR is the canonical override; CAKE_WALLET_DIR kept as a + // fallback so users migrating from a Cake install via env-var override + // don't lose their path. + _rootDirPath = Platform.environment['HASH_WALLET_DIR'] ?? Platform.environment['CAKE_WALLET_DIR']; void copyDirectory(Directory source, Directory destination) { source.listSync(recursive: false).forEach((var entity) { @@ -42,8 +45,11 @@ void copyDirectory(Directory source, Directory destination) { Future linuxSymlinkSharedPreferences() async { if (!Platform.isLinux) return; // nuh-uh final dataHome = Platform.environment["XDG_DATA_HOME"] ?? p.join(Platform.environment["HOME"] ?? "", ".local", "share"); - var cakeNames = ['com.example.cake_wallet', 'cake_wallet']; - for (String name in cakeNames) { + // Names to migrate from on startup. Includes the legacy Cake paths so users + // forking from a previous Cake install get their data automatically + // symlinked into Hash Wallet's new home (~/.local/share/hash_wallet). + var legacyNames = ['com.example.cake_wallet', 'cake_wallet']; + for (String name in legacyNames) { final oldPath = p.join(dataHome, name); final newPath = p.join((await getAppDir()).path, "_local_share"); final oldDir = Directory(oldPath); @@ -70,7 +76,7 @@ Future linuxSymlinkSharedPreferences() async { } Future getAppDir() async { - const String appName = 'cake_wallet'; + const String appName = 'hash_wallet'; Directory dir; if (_rootDirPath != null && _rootDirPath!.isNotEmpty) { diff --git a/tool/configure.dart b/tool/configure.dart index 071796d4..3b265b49 100644 --- a/tool/configure.dart +++ b/tool/configure.dart @@ -1956,6 +1956,11 @@ Future generateWalletTypes({ const outputDefinition = 'final availableWalletTypes = ['; var outputContent = outputHeader + '\n\n' + outputDefinition + '\n'; + // Hash Wallet: Wownero up top — it's the reason this fork exists. + if (hasWownero) { + outputContent += '\tWalletType.wownero,\n'; + } + if (hasMonero) { outputContent += '\tWalletType.monero,\n'; } @@ -2024,9 +2029,7 @@ Future generateWalletTypes({ outputContent += '\tWalletType.banano,\n'; } - if (hasWownero) { - outputContent += '\tWalletType.wownero,\n'; - } + // (Wownero moved to the top of this list — see comment above.) outputContent += '];\n'; await walletTypesFile.writeAsString(outputContent); -- 2.50.1 (Apple Git-155) From 4506b82e30079b7a470b1ee089d98860ef35b6fb Mon Sep 17 00:00:00 2001 From: jwinterm Date: Sat, 16 May 2026 19:05:13 -0400 Subject: [PATCH 2/8] Actually disable changelog modal (prior commit Edit raced the Read) --- lib/new-ui/new_dashboard.dart | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/new-ui/new_dashboard.dart b/lib/new-ui/new_dashboard.dart index f6a657ab..39538602 100644 --- a/lib/new-ui/new_dashboard.dart +++ b/lib/new-ui/new_dashboard.dart @@ -53,7 +53,12 @@ class _NewDashboardState extends State { }); }); - Future.delayed(Duration(milliseconds: 300)).then((_) => _showChangelog(context)); + // Hash Wallet: changelog modal disabled. The Cake-supplied changelog + // text (assets/new-ui/changelog/text) describes Cake's release history + // including v6.1.0 entries that aren't ours, and the 'View more info' + // button linked to blog.cakewallet.com. Re-enable once we have our + // own changelog content + versioning under our control. + // Future.delayed(Duration(milliseconds: 300)).then((_) => _showChangelog(context)); _showVulnerableSeedsPopup(context); } -- 2.50.1 (Apple Git-155) From 9e5593011a365dcbcb07388e6bd4093760115117 Mon Sep 17 00:00:00 2001 From: jwinterm Date: Sat, 16 May 2026 19:41:56 -0400 Subject: [PATCH 3/8] Route error reports + tx-failed support contact to support@such.software Cake's email was hardcoded as the recipient for the 'Send error report' flow in ExceptionHandler and as the contact in the TransactionCommitFailed user-facing message. Anyone tapping Send would have mailed their wallet metadata to Cake's support team. Repointed both to support@such.software. --- lib/utils/exception_handler.dart | 2 +- lib/view_model/send/send_view_model.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/utils/exception_handler.dart b/lib/utils/exception_handler.dart index c050f6aa..24288024 100644 --- a/lib/utils/exception_handler.dart +++ b/lib/utils/exception_handler.dart @@ -90,7 +90,7 @@ class ExceptionHandler { final MailOptions mailOptions = MailOptions( subject: 'Mobile App Issue', - recipients: ['support@cakewallet.com'], + recipients: ['support@such.software'], attachments: [_file!.path], ); diff --git a/lib/view_model/send/send_view_model.dart b/lib/view_model/send/send_view_model.dart index dc22ee8b..e50c083f 100644 --- a/lib/view_model/send/send_view_model.dart +++ b/lib/view_model/send/send_view_model.dart @@ -1511,7 +1511,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor if (error.errorMessage != null && error.errorMessage!.contains("no peers replied")) { return S.current.tx_commit_failed_no_peers; } - return "${S.current.tx_commit_failed}\nsupport@cakewallet.com${error.errorMessage != null ? "\n\n${error.errorMessage}" : ""}"; + return "${S.current.tx_commit_failed}\nsupport@such.software${error.errorMessage != null ? "\n\n${error.errorMessage}" : ""}"; } if (error is TransactionCommitFailedDustChange) { return S.current.tx_rejected_dust_change; -- 2.50.1 (Apple Git-155) From 9296e071f5336be1d4fbd011dc76fa57b1090609 Mon Sep 17 00:00:00 2001 From: jwinterm Date: Sat, 16 May 2026 19:55:53 -0400 Subject: [PATCH 4/8] Strip remaining cakewallet.com endpoints + delete Monerocom assets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Stub dashboard bulletin (was polling service-api.cakewallet.com); returns empty ServicesResponse until we stand up our own notice service. - Repoint changelog 'View more info' link to hash.boats (modal trigger remains disabled; this is just for when we re-enable it). - Replace exchange-helper.cakewallet.com with exchange-helper.such.software in moonpay/robinhood/onramper providers. Buy providers are still dormant (empty getAvailable*ProviderTypes); URL change is a fail-loudly placeholder to ensure we stand up our own proxy before re-enabling any of them. - Delete Monerocom_Terms_of_Use.txt and Monerocom_Release_Notes.txt — these were Cake's Monero.com brand variant, never used by Hash Wallet. Collapse the isMoneroOnly branch in disclaimer_page.dart to always load Terms_of_Use.txt. - Add docs/links.md (gitignored) inventorying all public-facing URLs and emails shipped in the binary. --- .gitignore | 3 + assets/text/Monerocom_Release_Notes.txt | 1 - assets/text/Monerocom_Terms_of_Use.txt | 188 ------------------ lib/buy/moonpay/moonpay_provider.dart | 2 +- lib/buy/onramper/onramper_buy_provider.dart | 2 +- lib/buy/robinhood/robinhood_buy_provider.dart | 2 +- lib/new-ui/widgets/changelog_modal.dart | 2 +- .../screens/disclaimer/disclaimer_page.dart | 4 +- .../dashboard/dashboard_view_model.dart | 45 +---- 9 files changed, 17 insertions(+), 232 deletions(-) delete mode 100644 assets/text/Monerocom_Release_Notes.txt delete mode 100644 assets/text/Monerocom_Terms_of_Use.txt diff --git a/.gitignore b/.gitignore index ab914993..5625711b 100644 --- a/.gitignore +++ b/.gitignore @@ -229,3 +229,6 @@ scripts/zcash_lib scripts/android/yttrium scripts/bitbox_flutter scripts/reown_flutter + +# Hash Wallet: untracked notes +docs/links.md diff --git a/assets/text/Monerocom_Release_Notes.txt b/assets/text/Monerocom_Release_Notes.txt deleted file mode 100644 index 67726850..00000000 --- a/assets/text/Monerocom_Release_Notes.txt +++ /dev/null @@ -1 +0,0 @@ -Bug fixes \ No newline at end of file diff --git a/assets/text/Monerocom_Terms_of_Use.txt b/assets/text/Monerocom_Terms_of_Use.txt deleted file mode 100644 index 7e4bf50e..00000000 --- a/assets/text/Monerocom_Terms_of_Use.txt +++ /dev/null @@ -1,188 +0,0 @@ -Last Modified: January 3, 2022 - -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 Monero.com app, including any content, functionality, and services offered on or through the Monero.com 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. - -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 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 Monero.com 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. - -Trademarks -========== - - The Company name, the term Monero.com, 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. - -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. - -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. - -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. - -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. - -Risks Related to the use of the App -=================================== - - The App, the Company and the Company’s owners, partners, employees, contributors, and any affiliates will not be responsible for any losses, damages or claims arising from: - - - Mistakes made by the user of any Monero-related and/or Bitcoin-related 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 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 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, 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, 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. - -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. - -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. - -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. - -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. - -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. - -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. - -Your Comments and Concerns -========================== - - This App is operated by Cake Technologies Inc. - All feedback, comments, and other communications relating to the App should be directed to info@cakewallet.com. All requests for technical support should be directed to support@cakewallet.com. diff --git a/lib/buy/moonpay/moonpay_provider.dart b/lib/buy/moonpay/moonpay_provider.dart index de9e634a..8ec89ffb 100644 --- a/lib/buy/moonpay/moonpay_provider.dart +++ b/lib/buy/moonpay/moonpay_provider.dart @@ -48,7 +48,7 @@ class MoonPayProvider extends BuyProvider { static const _baseSellProductUrl = 'sell.moonpay.com'; static const _baseBuyTestUrl = 'buy-staging.moonpay.com'; static const _baseBuyProductUrl = 'buy.moonpay.com'; - static const _cIdBaseUrl = 'exchange-helper.cakewallet.com'; + static const _cIdBaseUrl = 'exchange-helper.such.software'; static const _apiUrl = 'https://api.moonpay.com'; static const _baseUrl = 'api.moonpay.com'; static const _currenciesPath = '/v3/currencies'; diff --git a/lib/buy/onramper/onramper_buy_provider.dart b/lib/buy/onramper/onramper_buy_provider.dart index 006e2305..0ad38d57 100644 --- a/lib/buy/onramper/onramper_buy_provider.dart +++ b/lib/buy/onramper/onramper_buy_provider.dart @@ -28,7 +28,7 @@ class OnRamperBuyProvider extends BuyProvider { static const _baseUrl = 'buy.onramper.com'; static const _baseApiUrl = 'api.onramper.com'; - static const _cIdBaseUrl = 'exchange-helper.cakewallet.com'; + static const _cIdBaseUrl = 'exchange-helper.such.software'; static const quotes = '/quotes'; static const paymentTypes = '/payment-types'; static const supported = '/supported'; diff --git a/lib/buy/robinhood/robinhood_buy_provider.dart b/lib/buy/robinhood/robinhood_buy_provider.dart index 8b905632..ebc5eb75 100644 --- a/lib/buy/robinhood/robinhood_buy_provider.dart +++ b/lib/buy/robinhood/robinhood_buy_provider.dart @@ -37,7 +37,7 @@ class RobinhoodBuyProvider extends BuyProvider { ); static const _baseUrl = 'applink.robinhood.com'; - static const _cIdBaseUrl = 'exchange-helper.cakewallet.com'; + static const _cIdBaseUrl = 'exchange-helper.such.software'; static const _apiBaseUrl = 'api.robinhood.com'; static const _assetsPath = '/catpay/v1/supported_currencies/'; diff --git a/lib/new-ui/widgets/changelog_modal.dart b/lib/new-ui/widgets/changelog_modal.dart index 7f9b7f6d..bfb2dc75 100644 --- a/lib/new-ui/widgets/changelog_modal.dart +++ b/lib/new-ui/widgets/changelog_modal.dart @@ -107,7 +107,7 @@ class _ChangelogModalState extends State { NewPrimaryButton( onPressed: () { try { - launchUrl(Uri.https("blog.cakewallet.com")); + launchUrl(Uri.https("hash.boats")); } catch (_) {} }, text: S.of(context).view_more_info, diff --git a/lib/src/screens/disclaimer/disclaimer_page.dart b/lib/src/screens/disclaimer/disclaimer_page.dart index f2cc98fb..e09e3c4e 100644 --- a/lib/src/screens/disclaimer/disclaimer_page.dart +++ b/lib/src/screens/disclaimer/disclaimer_page.dart @@ -4,7 +4,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:hash_wallet/src/screens/base_page.dart'; import 'package:hash_wallet/src/widgets/primary_button.dart'; -import 'package:hash_wallet/wallet_type_utils.dart'; import 'package:modal_bottom_sheet/modal_bottom_sheet.dart'; class DisclaimerPage extends BasePage { @@ -36,8 +35,7 @@ class DisclaimerBodyState extends State { String _fileText = ''; void getFileLines() { - final fileName = - isMoneroOnly ? 'assets/text/Monerocom_Terms_of_Use.txt' : 'assets/text/Terms_of_Use.txt'; + const fileName = 'assets/text/Terms_of_Use.txt'; rootBundle.loadString(fileName).then((text) => setState(() => _fileText = text)); } diff --git a/lib/view_model/dashboard/dashboard_view_model.dart b/lib/view_model/dashboard/dashboard_view_model.dart index 23802952..04d6997d 100644 --- a/lib/view_model/dashboard/dashboard_view_model.dart +++ b/lib/view_model/dashboard/dashboard_view_model.dart @@ -1466,42 +1466,15 @@ abstract class DashboardViewModelBase with Store { } Future _getServicesStatus() async { - try { - if (isEnabledBulletinAction) { - final res = await ProxyWrapper().get( - clearnetUri: Uri.https( - "service-api.cakewallet.com", - "/v1/active-notices", - {'key': secrets.fiatApiKey}, - ), - onionUri: Uri.http( - "jpirgl4lrwzjgdqj2nsv3g7twhp2efzty5d3cnypktyczzqfc5qcwwyd.onion", - "/v1/active-notices", - {'key': secrets.fiatApiKey}, - ), - ); - if (res.statusCode < 200 || res.statusCode >= 300) { - throw res.body; - } - - final oldSha = sharedPreferences.getString(PreferencesKey.serviceStatusShaKey); - - final hash = await Cryptography.instance.sha256().hash(utf8.encode(res.body)); - final currentSha = bytesToHex(hash.bytes); - - final hasUpdates = oldSha != currentSha; - - return ServicesResponse.fromJson( - json.decode(res.body) as Map, - hasUpdates, - currentSha, - ); - } else { - return ServicesResponse([], false, ''); - } - } catch (e) { - return ServicesResponse([], false, ''); - } + // Hash Wallet: bulletin endpoint stubbed. The original implementation + // polled Cake's service-api.cakewallet.com/v1/active-notices (gated by + // the Cake-issued fiatApiKey) to surface push notices to all wallets. + // We don't run our own bulletin service yet. To restore: stand up an + // equivalent endpoint (likely under hash.boats or such.software) that + // returns the same JSON shape as service_status.dart expects, and put + // the network call back in place. Keep the user-facing toggle alive + // for forward-compat with the settings UI. + return ServicesResponse([], false, ''); } String getTransactionType(TransactionInfo tx) { -- 2.50.1 (Apple Git-155) From 8ba790b3183cb3519147b11b7c5c598ba1a3b46d Mon Sep 17 00:00:00 2001 From: jwinterm Date: Sat, 16 May 2026 20:07:15 -0400 Subject: [PATCH 5/8] Flip Cake nodes out of the default slot in node YAMLs Cake's nodes are kept in the available list (their public infra is fine, and users may want to opt in) but no longer the freshest-install default for XMR, BTC, or LTC. XMR: node.sethforprivacy.com:443 (matches newCakeWalletMoneroUri migration target, so existing users and fresh installs converge on the same node). BTC: electrum.blockstream.info:50002 (matches newCakeWalletBitcoinUri). LTC: electrum-ltc.bysh.me:50002 (matches cakeWalletLitecoinElectrumUri). --- assets/bitcoin_electrum_server_list.yml | 11 ++++++----- assets/litecoin_electrum_server_list.yml | 10 ++++++---- assets/node_list.yml | 12 ++++++------ 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/assets/bitcoin_electrum_server_list.yml b/assets/bitcoin_electrum_server_list.yml index 44b35fcf..37e038cf 100644 --- a/assets/bitcoin_electrum_server_list.yml +++ b/assets/bitcoin_electrum_server_list.yml @@ -1,7 +1,12 @@ +- + uri: electrum.blockstream.info:50002 + useSSL: true + isDefault: true + isEnabledForAutoSwitching: true - uri: btc-electrum.cakewallet.com:50002 useSSL: true - isDefault: true + isDefault: false isEnabledForAutoSwitching: true - uri: electrs.cakewallet.com:50001 @@ -17,10 +22,6 @@ uri: bitcoin.stackwallet.com:50002 useSSL: true isEnabledForAutoSwitching: true -- - uri: electrum.blockstream.info:50002 - useSSL: true - isEnabledForAutoSwitching: true - uri: electrum.emzy.de:50002 useSSL: true diff --git a/assets/litecoin_electrum_server_list.yml b/assets/litecoin_electrum_server_list.yml index 5a79149c..f9c0efd0 100644 --- a/assets/litecoin_electrum_server_list.yml +++ b/assets/litecoin_electrum_server_list.yml @@ -1,15 +1,17 @@ +- + uri: electrum-ltc.bysh.me:50002 + useSSL: true + isDefault: true + isEnabledForAutoSwitching: true - uri: ltc-electrum.cakewallet.com:50002 useSSL: true - isDefault: true + isDefault: false isEnabledForAutoSwitching: true - uri: litecoin.stackwallet.com:20063 useSSL: true isEnabledForAutoSwitching: true -- - uri: electrum-ltc.bysh.me:50002 - useSSL: true - uri: lightweight.fiatfaucet.com:50002 useSSL: true diff --git a/assets/node_list.yml b/assets/node_list.yml index 46e6d5f0..e1c2528f 100644 --- a/assets/node_list.yml +++ b/assets/node_list.yml @@ -1,17 +1,17 @@ +- + uri: node.sethforprivacy.com:443 + is_default: true + useSSL: true + isEnabledForAutoSwitching: true - uri: xmr-node.cakewallet.com:18081 - is_default: true + is_default: false trusted: true useSSL: true isEnabledForAutoSwitching: true - uri: cakexmrl7bonq7ovjka5kuwuyd3f7qnkz6z6s6dmsy3uckwra7bvggyd.onion:18081 is_default: false -- - uri: node.sethforprivacy.com:443 - useSSL: true - is_default: false - isEnabledForAutoSwitching: true - uri: node.monerodevs.org:18089 useSSL: true -- 2.50.1 (Apple Git-155) From 4eb7db0b72b0a4f84ad091c4df6bba25c4e06bdb Mon Sep 17 00:00:00 2001 From: jwinterm Date: Sun, 17 May 2026 08:01:29 -0400 Subject: [PATCH 6/8] Delete cw_zano / cw_tron / cw_solana / cw_decred packages + all references These chains were already disabled in availableWalletTypes (none of them were getting created), but the source dirs and the codegen scaffolding for them still lived in tree (~20K lines of dead Dart). Surgery: - Delete cw_decred/ cw_solana/ cw_tron/ cw_zano/ source trees - Strip 5 generate*() function bodies from tool/configure.dart (generateSolana, generateTron, generateZano, generateDecred, generateZcash) plus their top-level imports, args, calls, signatures, and conditional pubspec/walletTypes injection blocks. configure.dart shrinks from 2134 to 1561 lines and dart analyze is clean. - Strip solana/tron secrets config + output paths from tool/import_secrets_config.dart - Delete scripts/{android,ios,macos}/build_decred.sh, scripts/ios/build_zano{,_all}.sh - Patch scripts/{android,ios,macos}/build_all.sh, scripts/android/copy_monero_deps.sh, scripts/ios/setup.sh, scripts/ios/gen_framework.sh to drop decred/zano steps - Patch scripts/android/docker/build.sh + Dockerfile.final to drop the decred Docker stage; delete scripts/android/docker/Dockerfile.decred - Update .github/workflows/build-linux.yml comments to reflect the remaining cw_* module list (evm, nano, bitcoin) Note: WalletType.{solana,tron,zano,decred,zcash} enum values still live in cw_core/lib/wallet_type.dart and there are dead switch cases in lib/di.dart and lib/new-ui/pages/*.dart that reference them. Those paths are unreachable (the enum values never get assigned to any wallet) but cleaning them up is a separate hygiene pass. --- .github/workflows/build-linux.yml | 9 +- cw_decred/.gitignore | 39 - cw_decred/.metadata | 36 - cw_decred/CHANGELOG.md | 3 - cw_decred/LICENSE | 1 - cw_decred/README.md | 47 - cw_decred/analysis_options.yaml | 4 - cw_decred/android/.gitignore | 9 - cw_decred/android/build.gradle | 59 - cw_decred/android/settings.gradle | 1 - .../android/src/main/AndroidManifest.xml | 4 - .../cakewallet/cw_decred/CwDecredPlugin.kt | 35 - cw_decred/devtools_options.yaml | 3 - cw_decred/ios/.gitignore | 38 - cw_decred/ios/Assets/.gitkeep | 0 cw_decred/ios/Classes/CwDecredPlugin.swift | 19 - cw_decred/ios/cw_decred.podspec | 22 - cw_decred/lib/amount_format.dart | 26 - cw_decred/lib/api/libdcrwallet.dart | 702 ------ cw_decred/lib/api/util.dart | 64 - cw_decred/lib/balance.dart | 26 - cw_decred/lib/mnemonic.dart | 2050 ---------------- cw_decred/lib/pending_transaction.dart | 42 - cw_decred/lib/transaction_credentials.dart | 10 - cw_decred/lib/transaction_history.dart | 31 - cw_decred/lib/transaction_info.dart | 46 - cw_decred/lib/transaction_priority.dart | 73 - cw_decred/lib/wallet.dart | 770 ------ cw_decred/lib/wallet_addresses.dart | 153 -- .../lib/wallet_creation_credentials.dart | 40 - cw_decred/lib/wallet_service.dart | 261 --- cw_decred/macos/Classes/CwDecredPlugin.swift | 19 - cw_decred/macos/cw_decred.podspec | 22 - cw_decred/pubspec.lock | 950 -------- cw_decred/pubspec.yaml | 83 - cw_solana/.gitignore | 30 - cw_solana/.metadata | 10 - cw_solana/CHANGELOG.md | 3 - cw_solana/LICENSE | 1 - cw_solana/README.md | 63 - cw_solana/analysis_options.yaml | 4 - cw_solana/lib/cw_solana.dart | 7 - cw_solana/lib/default_spl_tokens.dart | 703 ------ cw_solana/lib/pending_solana_transaction.dart | 51 - cw_solana/lib/solana_balance.dart | 44 - cw_solana/lib/solana_client.dart | 1946 ---------------- cw_solana/lib/solana_exceptions.dart | 38 - cw_solana/lib/solana_mnemonics.dart | 2058 ----------------- .../lib/solana_transaction_credentials.dart | 12 - cw_solana/lib/solana_transaction_history.dart | 84 - cw_solana/lib/solana_transaction_info.dart | 77 - cw_solana/lib/solana_transaction_model.dart | 47 - cw_solana/lib/solana_wallet.dart | 845 ------- cw_solana/lib/solana_wallet_addresses.dart | 41 - .../solana_wallet_creation_credentials.dart | 46 - cw_solana/lib/solana_wallet_service.dart | 169 -- cw_solana/pubspec.yaml | 46 - cw_solana/test/cw_solana_test.dart | 12 - cw_tron/.gitignore | 30 - cw_tron/.metadata | 10 - cw_tron/CHANGELOG.md | 3 - cw_tron/LICENSE | 1 - cw_tron/README.md | 63 - cw_tron/analysis_options.yaml | 4 - cw_tron/lib/cw_tron.dart | 7 - cw_tron/lib/default_tron_tokens.dart | 107 - cw_tron/lib/pending_tron_transaction.dart | 41 - cw_tron/lib/tron_abi.dart | 436 ---- cw_tron/lib/tron_balance.dart | 25 - cw_tron/lib/tron_client.dart | 568 ----- cw_tron/lib/tron_exception.dart | 16 - cw_tron/lib/tron_http_provider.dart | 46 - cw_tron/lib/tron_transaction_credentials.dart | 12 - cw_tron/lib/tron_transaction_history.dart | 85 - cw_tron/lib/tron_transaction_info.dart | 93 - cw_tron/lib/tron_transaction_model.dart | 205 -- cw_tron/lib/tron_wallet.dart | 676 ------ cw_tron/lib/tron_wallet_addresses.dart | 43 - .../lib/tron_wallet_creation_credentials.dart | 47 - cw_tron/lib/tron_wallet_service.dart | 180 -- cw_tron/pubspec.yaml | 39 - cw_tron/test/cw_tron_test.dart | 12 - cw_zano/.gitignore | 7 - cw_zano/.metadata | 10 - cw_zano/CHANGELOG.md | 3 - cw_zano/LICENSE | 1 - cw_zano/README.md | 23 - cw_zano/lib/api/consts.dart | 6 - cw_zano/lib/api/model/asset_id_params.dart | 9 - cw_zano/lib/api/model/balance.dart | 32 - .../lib/api/model/create_wallet_result.dart | 52 - cw_zano/lib/api/model/destination.dart | 20 - cw_zano/lib/api/model/employed_entries.dart | 18 - .../api/model/get_address_info_result.dart | 16 - .../model/get_recent_txs_and_info_params.dart | 14 - .../model/get_recent_txs_and_info_result.dart | 12 - .../lib/api/model/get_wallet_info_result.dart | 14 - .../api/model/get_wallet_status_result.dart | 26 - .../lib/api/model/proxy_to_daemon_params.dart | 13 - .../lib/api/model/proxy_to_daemon_result.dart | 13 - cw_zano/lib/api/model/receive.dart | 15 - cw_zano/lib/api/model/recent_history.dart | 20 - cw_zano/lib/api/model/store_result.dart | 9 - cw_zano/lib/api/model/subtransfer.dart | 16 - cw_zano/lib/api/model/transfer.dart | 133 -- cw_zano/lib/api/model/transfer_params.dart | 41 - cw_zano/lib/api/model/transfer_result.dart | 13 - cw_zano/lib/api/model/wi.dart | 32 - cw_zano/lib/api/model/wi_extended.dart | 21 - cw_zano/lib/mnemonics/english.dart | 1630 ------------- .../lib/model/pending_zano_transaction.dart | 55 - cw_zano/lib/model/zano_asset.dart | 0 cw_zano/lib/model/zano_balance.dart | 17 - .../zano_transaction_creation_exception.dart | 8 - .../model/zano_transaction_credentials.dart | 11 - cw_zano/lib/model/zano_transaction_info.dart | 81 - cw_zano/lib/model/zano_wallet_keys.dart | 12 - cw_zano/lib/zano_formatter.dart | 79 - cw_zano/lib/zano_transaction_history.dart | 27 - cw_zano/lib/zano_utils.dart | 17 - cw_zano/lib/zano_wallet.dart | 587 ----- cw_zano/lib/zano_wallet_addresses.dart | 44 - cw_zano/lib/zano_wallet_api.dart | 548 ----- cw_zano/lib/zano_wallet_exceptions.dart | 21 - cw_zano/lib/zano_wallet_service.dart | 131 -- cw_zano/pubspec.lock | 956 -------- cw_zano/pubspec.yaml | 79 - scripts/android/.gitignore | 3 +- scripts/android/build_all.sh | 3 +- scripts/android/build_decred.sh | 85 - scripts/android/copy_monero_deps.sh | 2 - scripts/android/docker/Dockerfile.decred | 17 - scripts/android/docker/Dockerfile.final | 3 - scripts/android/docker/build.sh | 8 +- scripts/ios/build_all.sh | 2 +- scripts/ios/build_decred.sh | 35 - scripts/ios/build_zano.sh | 106 - scripts/ios/build_zano_all.sh | 7 - scripts/ios/gen_framework.sh | 4 +- scripts/ios/setup.sh | 10 - scripts/macos/build_all.sh | 2 +- scripts/macos/build_decred.sh | 34 - tool/configure.dart | 573 ----- tool/import_secrets_config.dart | 29 - 144 files changed, 12 insertions(+), 20586 deletions(-) delete mode 100644 cw_decred/.gitignore delete mode 100644 cw_decred/.metadata delete mode 100644 cw_decred/CHANGELOG.md delete mode 100644 cw_decred/LICENSE delete mode 100644 cw_decred/README.md delete mode 100644 cw_decred/analysis_options.yaml delete mode 100644 cw_decred/android/.gitignore delete mode 100644 cw_decred/android/build.gradle delete mode 100644 cw_decred/android/settings.gradle delete mode 100644 cw_decred/android/src/main/AndroidManifest.xml delete mode 100644 cw_decred/android/src/main/kotlin/com/cakewallet/cw_decred/CwDecredPlugin.kt delete mode 100644 cw_decred/devtools_options.yaml delete mode 100644 cw_decred/ios/.gitignore delete mode 100644 cw_decred/ios/Assets/.gitkeep delete mode 100644 cw_decred/ios/Classes/CwDecredPlugin.swift delete mode 100644 cw_decred/ios/cw_decred.podspec delete mode 100644 cw_decred/lib/amount_format.dart delete mode 100644 cw_decred/lib/api/libdcrwallet.dart delete mode 100644 cw_decred/lib/api/util.dart delete mode 100644 cw_decred/lib/balance.dart delete mode 100644 cw_decred/lib/mnemonic.dart delete mode 100644 cw_decred/lib/pending_transaction.dart delete mode 100644 cw_decred/lib/transaction_credentials.dart delete mode 100644 cw_decred/lib/transaction_history.dart delete mode 100644 cw_decred/lib/transaction_info.dart delete mode 100644 cw_decred/lib/transaction_priority.dart delete mode 100644 cw_decred/lib/wallet.dart delete mode 100644 cw_decred/lib/wallet_addresses.dart delete mode 100644 cw_decred/lib/wallet_creation_credentials.dart delete mode 100644 cw_decred/lib/wallet_service.dart delete mode 100644 cw_decred/macos/Classes/CwDecredPlugin.swift delete mode 100644 cw_decred/macos/cw_decred.podspec delete mode 100644 cw_decred/pubspec.lock delete mode 100644 cw_decred/pubspec.yaml delete mode 100644 cw_solana/.gitignore delete mode 100644 cw_solana/.metadata delete mode 100644 cw_solana/CHANGELOG.md delete mode 100644 cw_solana/LICENSE delete mode 100644 cw_solana/README.md delete mode 100644 cw_solana/analysis_options.yaml delete mode 100644 cw_solana/lib/cw_solana.dart delete mode 100644 cw_solana/lib/default_spl_tokens.dart delete mode 100644 cw_solana/lib/pending_solana_transaction.dart delete mode 100644 cw_solana/lib/solana_balance.dart delete mode 100644 cw_solana/lib/solana_client.dart delete mode 100644 cw_solana/lib/solana_exceptions.dart delete mode 100644 cw_solana/lib/solana_mnemonics.dart delete mode 100644 cw_solana/lib/solana_transaction_credentials.dart delete mode 100644 cw_solana/lib/solana_transaction_history.dart delete mode 100644 cw_solana/lib/solana_transaction_info.dart delete mode 100644 cw_solana/lib/solana_transaction_model.dart delete mode 100644 cw_solana/lib/solana_wallet.dart delete mode 100644 cw_solana/lib/solana_wallet_addresses.dart delete mode 100644 cw_solana/lib/solana_wallet_creation_credentials.dart delete mode 100644 cw_solana/lib/solana_wallet_service.dart delete mode 100644 cw_solana/pubspec.yaml delete mode 100644 cw_solana/test/cw_solana_test.dart delete mode 100644 cw_tron/.gitignore delete mode 100644 cw_tron/.metadata delete mode 100644 cw_tron/CHANGELOG.md delete mode 100644 cw_tron/LICENSE delete mode 100644 cw_tron/README.md delete mode 100644 cw_tron/analysis_options.yaml delete mode 100644 cw_tron/lib/cw_tron.dart delete mode 100644 cw_tron/lib/default_tron_tokens.dart delete mode 100644 cw_tron/lib/pending_tron_transaction.dart delete mode 100644 cw_tron/lib/tron_abi.dart delete mode 100644 cw_tron/lib/tron_balance.dart delete mode 100644 cw_tron/lib/tron_client.dart delete mode 100644 cw_tron/lib/tron_exception.dart delete mode 100644 cw_tron/lib/tron_http_provider.dart delete mode 100644 cw_tron/lib/tron_transaction_credentials.dart delete mode 100644 cw_tron/lib/tron_transaction_history.dart delete mode 100644 cw_tron/lib/tron_transaction_info.dart delete mode 100644 cw_tron/lib/tron_transaction_model.dart delete mode 100644 cw_tron/lib/tron_wallet.dart delete mode 100644 cw_tron/lib/tron_wallet_addresses.dart delete mode 100644 cw_tron/lib/tron_wallet_creation_credentials.dart delete mode 100644 cw_tron/lib/tron_wallet_service.dart delete mode 100644 cw_tron/pubspec.yaml delete mode 100644 cw_tron/test/cw_tron_test.dart delete mode 100644 cw_zano/.gitignore delete mode 100644 cw_zano/.metadata delete mode 100644 cw_zano/CHANGELOG.md delete mode 100644 cw_zano/LICENSE delete mode 100644 cw_zano/README.md delete mode 100644 cw_zano/lib/api/consts.dart delete mode 100644 cw_zano/lib/api/model/asset_id_params.dart delete mode 100644 cw_zano/lib/api/model/balance.dart delete mode 100644 cw_zano/lib/api/model/create_wallet_result.dart delete mode 100644 cw_zano/lib/api/model/destination.dart delete mode 100644 cw_zano/lib/api/model/employed_entries.dart delete mode 100644 cw_zano/lib/api/model/get_address_info_result.dart delete mode 100644 cw_zano/lib/api/model/get_recent_txs_and_info_params.dart delete mode 100644 cw_zano/lib/api/model/get_recent_txs_and_info_result.dart delete mode 100644 cw_zano/lib/api/model/get_wallet_info_result.dart delete mode 100644 cw_zano/lib/api/model/get_wallet_status_result.dart delete mode 100644 cw_zano/lib/api/model/proxy_to_daemon_params.dart delete mode 100644 cw_zano/lib/api/model/proxy_to_daemon_result.dart delete mode 100644 cw_zano/lib/api/model/receive.dart delete mode 100644 cw_zano/lib/api/model/recent_history.dart delete mode 100644 cw_zano/lib/api/model/store_result.dart delete mode 100644 cw_zano/lib/api/model/subtransfer.dart delete mode 100644 cw_zano/lib/api/model/transfer.dart delete mode 100644 cw_zano/lib/api/model/transfer_params.dart delete mode 100644 cw_zano/lib/api/model/transfer_result.dart delete mode 100644 cw_zano/lib/api/model/wi.dart delete mode 100644 cw_zano/lib/api/model/wi_extended.dart delete mode 100644 cw_zano/lib/mnemonics/english.dart delete mode 100644 cw_zano/lib/model/pending_zano_transaction.dart delete mode 100644 cw_zano/lib/model/zano_asset.dart delete mode 100644 cw_zano/lib/model/zano_balance.dart delete mode 100644 cw_zano/lib/model/zano_transaction_creation_exception.dart delete mode 100644 cw_zano/lib/model/zano_transaction_credentials.dart delete mode 100644 cw_zano/lib/model/zano_transaction_info.dart delete mode 100644 cw_zano/lib/model/zano_wallet_keys.dart delete mode 100644 cw_zano/lib/zano_formatter.dart delete mode 100644 cw_zano/lib/zano_transaction_history.dart delete mode 100644 cw_zano/lib/zano_utils.dart delete mode 100644 cw_zano/lib/zano_wallet.dart delete mode 100644 cw_zano/lib/zano_wallet_addresses.dart delete mode 100644 cw_zano/lib/zano_wallet_api.dart delete mode 100644 cw_zano/lib/zano_wallet_exceptions.dart delete mode 100644 cw_zano/lib/zano_wallet_service.dart delete mode 100644 cw_zano/pubspec.lock delete mode 100644 cw_zano/pubspec.yaml delete mode 100755 scripts/android/build_decred.sh delete mode 100644 scripts/android/docker/Dockerfile.decred delete mode 100755 scripts/ios/build_decred.sh delete mode 100755 scripts/ios/build_zano.sh delete mode 100755 scripts/ios/build_zano_all.sh delete mode 100755 scripts/macos/build_decred.sh diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 7ed9efb6..047d3abd 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -50,9 +50,9 @@ jobs: # IMPORTANT: don't pre-write any of the tool/.*secrets-config.json # files. The generator at tool/generate_secrets_config.dart has an # early-return if tool/.secrets-config.json already exists (lines - # 57-63), which then ALSO skips creating the per-module configs (evm, - # solana, nano, tron, bitcoin) — every cw_* module then fails to - # compile with "Undefined name secrets.xxx" for dozens of keys. + # 57-63), which then ALSO skips creating the per-module configs + # (evm, nano, bitcoin) — every cw_* module then fails to compile + # with "Undefined name secrets.xxx" for dozens of keys. # # Instead: run the generator first so it creates all configs from the # full SecretKey list (with empty defaults), then sed-inject Trocador @@ -93,7 +93,8 @@ jobs: # ---- Native crypto cores (monero_c prebuilt bundle) ------------------ # Skips the full simplybs toolchain bootstrap. The bundle has libmonero, # libwownero, AND libzano .so files; CMake only installs the ones we - # ship (monero + wownero). + # ship (monero + wownero) — libzano is dropped at install time even + # though monero_c builds it. - name: Fetch prebuilt monero_c .so bundle run: | set -x -e diff --git a/cw_decred/.gitignore b/cw_decred/.gitignore deleted file mode 100644 index d8452de5..00000000 --- a/cw_decred/.gitignore +++ /dev/null @@ -1,39 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ -migrate_working_dir/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. -/pubspec.lock -**/doc/api/ -.dart_tool/ -.packages -build/ - -android/.externalNativeBuild/ -android/.cxx/ -android/libs -ios/External/ -macos/External/ - -*libdcrwallet.h -libdcrwallet_bindings.dart diff --git a/cw_decred/.metadata b/cw_decred/.metadata deleted file mode 100644 index fa060de4..00000000 --- a/cw_decred/.metadata +++ /dev/null @@ -1,36 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled. - -version: - revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - channel: unknown - -project_type: plugin - -# Tracks metadata for the flutter migrate command -migration: - platforms: - - platform: root - create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - - platform: android - create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - - platform: ios - create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - - platform: macos - create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - - # User provided section - - # List of Local paths (relative to this file) that should be - # ignored by the migrate tool. - # - # Files that are not part of the templates will be ignored by default. - unmanaged_files: - - 'lib/main.dart' - - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/cw_decred/CHANGELOG.md b/cw_decred/CHANGELOG.md deleted file mode 100644 index ac071598..00000000 --- a/cw_decred/CHANGELOG.md +++ /dev/null @@ -1,3 +0,0 @@ -## [0.0.1] - TODO: Add release date. - -* TODO: Describe initial release. diff --git a/cw_decred/LICENSE b/cw_decred/LICENSE deleted file mode 100644 index ba75c69f..00000000 --- a/cw_decred/LICENSE +++ /dev/null @@ -1 +0,0 @@ -TODO: Add your license here. diff --git a/cw_decred/README.md b/cw_decred/README.md deleted file mode 100644 index c43032f7..00000000 --- a/cw_decred/README.md +++ /dev/null @@ -1,47 +0,0 @@ -# cw_decred - -Decred wallet module that bridges to the native `libdcrwallet` via FFI. Provides high‑level methods to create/load wallets, sync, query balances/transactions, build and broadcast transactions, and sign/verify messages. - -## Features - -- FFI bindings to `libdcrwallet` with an isolate‑based request/response model. -- Initialize, create, load, close wallets; watch‑only creation. -- Start sync with optional peer list; query sync status and best block. -- Query balances, list transactions and unspents, rescan from height. -- Create signed transactions and broadcast raw transactions. -- Export wallet seed; change wallet password. -- Address management (new external address, default pubkey, address lists). -- Message signing and verification. - -## Getting started - -Ensure the platform library is available: - -- Android/Linux: `libdcrwallet.so` -- Apple: embedded `cw_decred.framework/cw_decred` - -Initialize and load a wallet: - -```dart -final lib = await Libwallet.spawn(); -await lib.initLibdcrwallet('', 'info'); -await lib.loadWallet(jsonEncode({ /* libdcrwallet config */ })); -await lib.startSync('wallet.db', ''); -final status = await lib.syncStatus('wallet.db'); -``` - -## Usage - -Create, sign, and broadcast a transaction: - -```dart -final signed = await lib.createSignedTransaction('wallet.db', jsonEncode({ - // inputs/outputs and policy for libdcrwallet -})); -final txid = await lib.sendRawTransaction('wallet.db', signed); -``` - -## Additional information - -- See `lib/api/` for the isolate wrapper (`libdcrwallet.dart`) and low‑level bindings. -- Errors are surfaced via the `PayloadResult` struct; some calls support `throwOnError` in higher‑level wrappers. diff --git a/cw_decred/analysis_options.yaml b/cw_decred/analysis_options.yaml deleted file mode 100644 index a5744c1c..00000000 --- a/cw_decred/analysis_options.yaml +++ /dev/null @@ -1,4 +0,0 @@ -include: package:flutter_lints/flutter.yaml - -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options diff --git a/cw_decred/android/.gitignore b/cw_decred/android/.gitignore deleted file mode 100644 index 161bdcda..00000000 --- a/cw_decred/android/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -*.iml -.gradle -/local.properties -/.idea/workspace.xml -/.idea/libraries -.DS_Store -/build -/captures -.cxx diff --git a/cw_decred/android/build.gradle b/cw_decred/android/build.gradle deleted file mode 100644 index 0fb2f3cb..00000000 --- a/cw_decred/android/build.gradle +++ /dev/null @@ -1,59 +0,0 @@ -group 'com.cakewallet.cw_decred' -version '1.0-SNAPSHOT' - -buildscript { - ext.kotlin_version = '2.0.21' - repositories { - google() - mavenCentral() - } - - dependencies { - classpath 'com.android.tools.build:gradle:8.7.1' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -rootProject.allprojects { - repositories { - google() - mavenCentral() - } -} - -apply plugin: 'com.android.library' -apply plugin: 'kotlin-android' - -android { - compileSdkVersion 33 - - if (project.android.hasProperty("namespace")) { - namespace 'com.cakewallet.cw_decred' - } - - compileOptions { - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 - } - - kotlinOptions { - jvmTarget = '17' - } - sourceSets { - main { - java.srcDirs += 'src/main/kotlin' - jniLibs.srcDirs 'libs' // contains libdcrwallet.so shared libraries - } - } - defaultConfig { - minSdkVersion 21 - } - externalNativeBuild { - cmake { - } - } -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" -} diff --git a/cw_decred/android/settings.gradle b/cw_decred/android/settings.gradle deleted file mode 100644 index 1c81706a..00000000 --- a/cw_decred/android/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'cw_decred' diff --git a/cw_decred/android/src/main/AndroidManifest.xml b/cw_decred/android/src/main/AndroidManifest.xml deleted file mode 100644 index ea58d3c7..00000000 --- a/cw_decred/android/src/main/AndroidManifest.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - diff --git a/cw_decred/android/src/main/kotlin/com/cakewallet/cw_decred/CwDecredPlugin.kt b/cw_decred/android/src/main/kotlin/com/cakewallet/cw_decred/CwDecredPlugin.kt deleted file mode 100644 index 4bd6f339..00000000 --- a/cw_decred/android/src/main/kotlin/com/cakewallet/cw_decred/CwDecredPlugin.kt +++ /dev/null @@ -1,35 +0,0 @@ -package com.cakewallet.cw_decred - -import androidx.annotation.NonNull - -import io.flutter.embedding.engine.plugins.FlutterPlugin -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel -import io.flutter.plugin.common.MethodChannel.MethodCallHandler -import io.flutter.plugin.common.MethodChannel.Result - -/** CwDecredPlugin */ -class CwDecredPlugin: FlutterPlugin, MethodCallHandler { - /// The MethodChannel that will the communication between Flutter and native Android - /// - /// This local reference serves to register the plugin with the Flutter Engine and unregister it - /// when the Flutter Engine is detached from the Activity - private lateinit var channel : MethodChannel - - override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { - channel = MethodChannel(flutterPluginBinding.binaryMessenger, "cw_decred") - channel.setMethodCallHandler(this) - } - - override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { - if (call.method == "getPlatformVersion") { - result.success("Android ${android.os.Build.VERSION.RELEASE}") - } else { - result.notImplemented() - } - } - - override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { - channel.setMethodCallHandler(null) - } -} diff --git a/cw_decred/devtools_options.yaml b/cw_decred/devtools_options.yaml deleted file mode 100644 index fa0b357c..00000000 --- a/cw_decred/devtools_options.yaml +++ /dev/null @@ -1,3 +0,0 @@ -description: This file stores settings for Dart & Flutter DevTools. -documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states -extensions: diff --git a/cw_decred/ios/.gitignore b/cw_decred/ios/.gitignore deleted file mode 100644 index 0c885071..00000000 --- a/cw_decred/ios/.gitignore +++ /dev/null @@ -1,38 +0,0 @@ -.idea/ -.vagrant/ -.sconsign.dblite -.svn/ - -.DS_Store -*.swp -profile - -DerivedData/ -build/ -GeneratedPluginRegistrant.h -GeneratedPluginRegistrant.m - -.generated/ - -*.pbxuser -*.mode1v3 -*.mode2v3 -*.perspectivev3 - -!default.pbxuser -!default.mode1v3 -!default.mode2v3 -!default.perspectivev3 - -xcuserdata - -*.moved-aside - -*.pyc -*sync/ -Icon? -.tags* - -/Flutter/Generated.xcconfig -/Flutter/ephemeral/ -/Flutter/flutter_export_environment.sh \ No newline at end of file diff --git a/cw_decred/ios/Assets/.gitkeep b/cw_decred/ios/Assets/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/cw_decred/ios/Classes/CwDecredPlugin.swift b/cw_decred/ios/Classes/CwDecredPlugin.swift deleted file mode 100644 index c38d1551..00000000 --- a/cw_decred/ios/Classes/CwDecredPlugin.swift +++ /dev/null @@ -1,19 +0,0 @@ -import Flutter -import UIKit - -public class CwDecredPlugin: NSObject, FlutterPlugin { - public static func register(with registrar: FlutterPluginRegistrar) { - let channel = FlutterMethodChannel(name: "cw_decred", binaryMessenger: registrar.messenger()) - let instance = CwDecredPlugin() - registrar.addMethodCallDelegate(instance, channel: channel) - } - - public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - switch call.method { - case "getPlatformVersion": - result("iOS " + UIDevice.current.systemVersion) - default: - result(FlutterMethodNotImplemented) - } - } -} diff --git a/cw_decred/ios/cw_decred.podspec b/cw_decred/ios/cw_decred.podspec deleted file mode 100644 index b36789e0..00000000 --- a/cw_decred/ios/cw_decred.podspec +++ /dev/null @@ -1,22 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. -# Run `pod lib lint cw_decred.podspec` to validate before publishing. -# -Pod::Spec.new do |s| - s.name = 'cw_decred' - s.version = '0.0.1' - s.summary = 'Cake Wallet Decred' - s.description = 'Cake Wallet wrapper over Decred project' - s.homepage = 'http://cakewallet.com' - s.license = { :file => '../LICENSE' } - s.author = { 'Cake Wallet' => 'support@cakewallet.com' } - s.source = { :path => '.' } - s.source_files = 'Classes/**/*' - s.dependency 'Flutter' - s.platform = :ios, '11.0' - - s.vendored_libraries = 'External/lib/libdcrwallet.a' - # Flutter.framework does not contain a i386 slice. - s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386', "OTHER_LDFLAGS" => "-force_load $(PODS_TARGET_SRCROOT)/External/lib/libdcrwallet.a -lstdc++" } - s.swift_version = '5.0' -end diff --git a/cw_decred/lib/amount_format.dart b/cw_decred/lib/amount_format.dart deleted file mode 100644 index c09f76b3..00000000 --- a/cw_decred/lib/amount_format.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'package:intl/intl.dart'; -import 'package:cw_core/crypto_amount_format.dart'; - -const decredAmountLength = 8; -const decredAmountDivider = 100000000; -final decredAmountFormat = NumberFormat() - ..maximumFractionDigits = decredAmountLength - ..minimumFractionDigits = 1; - -String decredAmountToString({required int amount}) => - decredAmountFormat.format(cryptoAmountToDouble(amount: amount, divider: decredAmountDivider)); - -double decredAmountToDouble({required int amount}) => - cryptoAmountToDouble(amount: amount, divider: decredAmountDivider); - -int stringDoubleToDecredAmount(String amount) { - int result = 0; - - try { - result = (double.parse(amount) * decredAmountDivider).round(); - } catch (e) { - result = 0; - } - - return result; -} diff --git a/cw_decred/lib/api/libdcrwallet.dart b/cw_decred/lib/api/libdcrwallet.dart deleted file mode 100644 index a6d1e101..00000000 --- a/cw_decred/lib/api/libdcrwallet.dart +++ /dev/null @@ -1,702 +0,0 @@ -import 'dart:convert'; -import 'dart:ffi'; -import 'dart:io'; -import 'dart:async'; -import 'dart:isolate'; -import 'package:cw_core/utils/print_verbose.dart'; -import 'package:cw_decred/api/libdcrwallet_bindings.dart'; -import 'package:cw_decred/api/util.dart'; - -final int ErrCodeNotSynced = 1; - -final String libraryName = Platform.isAndroid || Platform.isLinux // TODO: Linux. - ? 'libdcrwallet.so' - : 'cw_decred.framework/cw_decred'; - -class Libwallet { - final SendPort _commands; - final ReceivePort _responses; - final Map> _activeRequests = {}; - int _idCounter = 0; - bool _closed = false; - - static Future spawn() async { - // Create a receive port and add its initial message handler. - final initPort = RawReceivePort(); - final connection = Completer<(ReceivePort, SendPort)>.sync(); - initPort.handler = (initialMessage) { - final commandPort = initialMessage as SendPort; - connection.complete(( - ReceivePort.fromRawReceivePort(initPort), - commandPort, - )); - }; - // Spawn the isolate. - try { - await Isolate.spawn(_startRemoteIsolate, (initPort.sendPort)); - } on Object { - initPort.close(); - rethrow; - } - - final (ReceivePort receivePort, SendPort sendPort) = await connection.future; - - return Libwallet._(receivePort, sendPort); - } - - Libwallet._(this._responses, this._commands) { - _responses.listen(_handleResponsesFromIsolate); - } - - void _handleResponsesFromIsolate(dynamic message) { - final (int id, Object? response) = message as (int, Object?); - final completer = _activeRequests.remove(id)!; - - if (response is RemoteError) { - completer.completeError(response); - } else { - completer.complete(response); - } - - if (_closed && _activeRequests.isEmpty) _responses.close(); - } - - static void _handleCommandsToIsolate( - ReceivePort receivePort, - SendPort sendPort, - ) { - final dcrwalletApi = libdcrwallet(DynamicLibrary.open(libraryName)); - receivePort.listen((message) { - if (message == 'shutdown') { - receivePort.close(); - return; - } - final (int id, Map args) = message as (int, Map); - var res = PayloadResult("", "", 0); - final method = args["method"] ?? ""; - try { - switch (method) { - case "initlibdcrwallet": - final logDir = args["logdir"] ?? ""; - final level = args["level"] ?? ""; - final cLogDir = logDir.toCString(); - final cLevel = level.toCString(); - executePayloadFn( - fn: () => dcrwalletApi.initialize(cLogDir, cLevel), - ptrsToFree: [cLogDir, cLevel], - ); - break; - case "createwallet": - final config = args["config"] ?? ""; - final cConfig = config.toCString(); - executePayloadFn( - fn: () => dcrwalletApi.createWallet(cConfig), - ptrsToFree: [cConfig], - ); - break; - case "createwatchonlywallet": - final config = args["config"] ?? ""; - final cConfig = config.toCString(); - executePayloadFn( - fn: () => dcrwalletApi.createWatchOnlyWallet(cConfig), - ptrsToFree: [cConfig], - ); - break; - case "loadwallet": - final config = args["config"] ?? ""; - final cConfig = config.toCString(); - executePayloadFn( - fn: () => dcrwalletApi.loadWallet(cConfig), - ptrsToFree: [cConfig], - ); - break; - case "startsync": - final name = args["name"] ?? ""; - final peers = args["peers"] ?? ""; - final cName = name.toCString(); - final cPeers = peers.toCString(); - executePayloadFn( - fn: () => dcrwalletApi.syncWallet(cName, cPeers), - ptrsToFree: [cName, cPeers], - ); - break; - case "closewallet": - final name = args["name"] ?? ""; - final cName = name.toCString(); - executePayloadFn( - fn: () => dcrwalletApi.closeWallet(cName), - ptrsToFree: [cName], - ); - break; - case "changewalletpassword": - final name = args["name"] ?? ""; - final oldPass = args["oldpass"] ?? ""; - final newPass = args["newpass"] ?? ""; - final cName = name.toCString(); - final cOldPass = oldPass.toCString(); - final cNewPass = newPass.toCString(); - res = executePayloadFn( - fn: () => dcrwalletApi.changePassphrase(cName, cOldPass, cNewPass), - ptrsToFree: [cName, cOldPass, cNewPass], - ); - break; - case "walletseed": - final name = args["name"] ?? ""; - final pass = args["pass"] ?? ""; - final cName = name.toCString(); - final cPass = pass.toCString(); - res = executePayloadFn( - fn: () => dcrwalletApi.walletSeed(cName, cPass), - ptrsToFree: [cName, cPass], - ); - break; - case "syncstatus": - final name = args["name"] ?? ""; - final cName = name.toCString(); - res = executePayloadFn( - fn: () => dcrwalletApi.syncWalletStatus(cName), - ptrsToFree: [cName], - ); - break; - case "balance": - final name = args["name"] ?? ""; - final cName = name.toCString(); - res = executePayloadFn( - fn: () => dcrwalletApi.walletBalance(cName), - ptrsToFree: [cName], - ); - break; - case "estimatefee": - final name = args["name"] ?? ""; - final numBlocks = args["numblocks"] ?? ""; - final cName = name.toCString(); - final cNumBlocks = numBlocks.toCString(); - res = executePayloadFn( - fn: () => dcrwalletApi.estimateFee(cName, cNumBlocks), - ptrsToFree: [cName, cNumBlocks], - ); - break; - case "createsignedtransaction": - final name = args["name"] ?? ""; - final signReq = args["signreq"] ?? ""; - final cName = name.toCString(); - final cSignReq = signReq.toCString(); - res = executePayloadFn( - fn: () => dcrwalletApi.createSignedTransaction(cName, cSignReq), - ptrsToFree: [cName, cSignReq], - ); - break; - case "sendrawtransaction": - final name = args["name"] ?? ""; - final txHex = args["txhex"] ?? ""; - final cName = name.toCString(); - final cTxHex = txHex.toCString(); - res = executePayloadFn( - fn: () => dcrwalletApi.sendRawTransaction(cName, cTxHex), - ptrsToFree: [cName, cTxHex], - ); - break; - case "listtransactions": - final name = args["name"] ?? ""; - final from = args["from"] ?? ""; - final count = args["count"] ?? ""; - final cName = name.toCString(); - final cFrom = from.toCString(); - final cCount = count.toCString(); - res = executePayloadFn( - fn: () => dcrwalletApi.listTransactions(cName, cFrom, cCount), - ptrsToFree: [cName, cFrom, cCount], - ); - break; - case "bestblock": - final name = args["name"] ?? ""; - final cName = name.toCString(); - res = executePayloadFn( - fn: () => dcrwalletApi.bestBlock(cName), - ptrsToFree: [cName], - ); - break; - case "listunspents": - final name = args["name"] ?? ""; - final cName = name.toCString(); - res = executePayloadFn( - fn: () => dcrwalletApi.listUnspents(cName), - ptrsToFree: [cName], - ); - break; - case "rescanfromheight": - final name = args["name"] ?? ""; - final height = args["height"] ?? ""; - final cName = name.toCString(); - final cHeight = height.toCString(); - res = executePayloadFn( - fn: () => dcrwalletApi.rescanFromHeight(cName, cHeight), - ptrsToFree: [cName, cHeight], - ); - break; - case "signmessage": - final name = args["name"] ?? ""; - final message = args["message"] ?? ""; - final address = args["address"] ?? ""; - final pass = args["pass"] ?? ""; - final cName = name.toCString(); - final cMessage = message.toCString(); - final cAddress = address.toCString(); - final cPass = pass.toCString(); - res = executePayloadFn( - fn: () => dcrwalletApi.signMessage(cName, cMessage, cAddress, cPass), - ptrsToFree: [cName, cMessage, cAddress, cPass], - ); - break; - case "verifymessage": - final name = args["name"] ?? ""; - final message = args["message"] ?? ""; - final address = args["address"] ?? ""; - final sig = args["sig"] ?? ""; - final cName = name.toCString(); - final cMessage = message.toCString(); - final cAddress = address.toCString(); - final cSig = sig.toCString(); - res = executePayloadFn( - fn: () => dcrwalletApi.verifyMessage(cName, cMessage, cAddress, cSig), - ptrsToFree: [cName, cMessage, cAddress, cSig], - ); - break; - case "newexternaladdress": - final name = args["name"] ?? ""; - final cName = name.toCString(); - res = executePayloadFn( - fn: () => dcrwalletApi.newExternalAddress(cName), - ptrsToFree: [cName], - skipErrorCheck: true, - ); - break; - case "defaultpubkey": - final name = args["name"] ?? ""; - final cName = name.toCString(); - res = executePayloadFn( - fn: () => dcrwalletApi.defaultPubkey(cName), - ptrsToFree: [cName], - ); - break; - case "addresses": - final name = args["name"] ?? ""; - final nUsed = args["nused"] ?? ""; - final nUnused = args["nunused"] ?? ""; - final cName = name.toCString(); - final cNUsed = nUsed.toCString(); - final cNUnused = nUnused.toCString(); - res = executePayloadFn( - fn: () => dcrwalletApi.addresses(cName, cNUsed, cNUnused), - ptrsToFree: [cName, cNUsed, cNUnused], - ); - break; - case "birthstate": - final name = args["name"] ?? ""; - final cName = name.toCString(); - res = executePayloadFn( - fn: () => dcrwalletApi.birthState(cName), - ptrsToFree: [cName], - ); - break; - case "shutdown": - final name = args["name"] ?? ""; - // final cName = name.toCString(); - executePayloadFn( - fn: () => dcrwalletApi.shutdown(), - ptrsToFree: [], - ); - break; - default: - res = PayloadResult("", "unknown libwallet method ${method}", 0); - } - sendPort.send((id, res)); - } catch (e) { - final errMsg = e.toString(); - printV("decred libwallet returned an error for method ${method}: ${errMsg}"); - sendPort.send((id, PayloadResult("", errMsg, 0))); - } - }); - } - - static void _startRemoteIsolate(SendPort sendPort) { - final receivePort = ReceivePort(); - sendPort.send(receivePort.sendPort); - _handleCommandsToIsolate(receivePort, sendPort); - } - - // initLibdcrwallet initializes libdcrwallet using the provided logDir and gets - // it ready for use. This must be done before attempting to create, load or use - // a wallet. An empty string can be used to log to stdout and create no log files. - Future initLibdcrwallet(String logDir, String level) async { - if (_closed) throw StateError('Closed'); - final completer = Completer.sync(); - final id = _idCounter++; - _activeRequests[id] = completer; - final req = { - "method": "initlibdcrwallet", - "logdir": logDir, - "level": level, - }; - _commands.send((id, req)); - await completer.future; - } - - Future createWallet(String config) async { - if (_closed) throw StateError('Closed'); - final completer = Completer.sync(); - final id = _idCounter++; - _activeRequests[id] = completer; - final req = { - "method": "createwallet", - "config": config, - }; - _commands.send((id, req)); - await completer.future; - } - - Future createWatchOnlyWallet(String config) async { - if (_closed) throw StateError('Closed'); - final completer = Completer.sync(); - final id = _idCounter++; - _activeRequests[id] = completer; - final req = { - "method": "createwatchonlywallet", - "config": config, - }; - _commands.send((id, req)); - await completer.future; - } - - Future loadWallet(String config) async { - if (_closed) throw StateError('Closed'); - final completer = Completer.sync(); - final id = _idCounter++; - _activeRequests[id] = completer; - final req = { - "method": "loadwallet", - "config": config, - }; - _commands.send((id, req)); - await completer.future; - } - - Future startSync(String walletName, String peers) async { - if (_closed) throw StateError('Closed'); - final completer = Completer.sync(); - final id = _idCounter++; - _activeRequests[id] = completer; - final req = { - "method": "startsync", - "name": walletName, - "peers": peers, - }; - _commands.send((id, req)); - await completer.future; - } - - Future closeWallet(String walletName) async { - if (_closed) throw StateError('Closed'); - final completer = Completer.sync(); - final id = _idCounter++; - _activeRequests[id] = completer; - final req = { - "method": "closewallet", - "name": walletName, - }; - _commands.send((id, req)); - await completer.future; - } - - Future changeWalletPassword( - String walletName, String currentPassword, String newPassword) async { - if (_closed) throw StateError('Closed'); - final completer = Completer.sync(); - final id = _idCounter++; - _activeRequests[id] = completer; - final req = { - "method": "changewalletpassword", - "name": walletName, - "oldpass": currentPassword, - "newpass": newPassword - }; - _commands.send((id, req)); - final res = await completer.future as PayloadResult; - return res.payload; - } - - Future walletSeed(String walletName, String walletPassword) async { - if (_closed) throw StateError('Closed'); - final completer = Completer.sync(); - final id = _idCounter++; - _activeRequests[id] = completer; - final req = { - "method": "walletseed", - "name": walletName, - "pass": walletPassword, - }; - _commands.send((id, req)); - final res = await completer.future as PayloadResult; - return res.payload; - } - - Future syncStatus(String walletName) async { - if (_closed) throw StateError('Closed'); - final completer = Completer.sync(); - final id = _idCounter++; - _activeRequests[id] = completer; - final req = { - "method": "syncstatus", - "name": walletName, - }; - _commands.send((id, req)); - final res = await completer.future as PayloadResult; - return res.payload; - } - - Future balance(String walletName, {bool throwOnError = false}) async { - if (_closed) throw StateError('Closed'); - final completer = Completer.sync(); - final id = _idCounter++; - _activeRequests[id] = completer; - final req = { - "method": "balance", - "name": walletName, - }; - _commands.send((id, req)); - final res = await completer.future as PayloadResult; - try { - return jsonDecode(res.payload); - } catch (_) { - if (throwOnError) { - rethrow; - } - return {}; - } - } - - Future estimateFee(String walletName, int numBlocks) async { - if (_closed) throw StateError('Closed'); - final completer = Completer.sync(); - final id = _idCounter++; - _activeRequests[id] = completer; - final req = { - "method": "estimatefee", - "name": walletName, - "numblocks": numBlocks.toString(), - }; - _commands.send((id, req)); - final res = await completer.future as PayloadResult; - return res.payload; - } - - Future createSignedTransaction( - String walletName, String createSignedTransactionReq) async { - if (_closed) throw StateError('Closed'); - final completer = Completer.sync(); - final id = _idCounter++; - _activeRequests[id] = completer; - final req = { - "method": "createsignedtransaction", - "name": walletName, - "signreq": createSignedTransactionReq, - }; - _commands.send((id, req)); - final res = await completer.future as PayloadResult; - return res.payload; - } - - Future sendRawTransaction(String walletName, String txHex) async { - if (_closed) throw StateError('Closed'); - final completer = Completer.sync(); - final id = _idCounter++; - _activeRequests[id] = completer; - final req = { - "method": "sendrawtransaction", - "name": walletName, - "txhex": txHex, - }; - _commands.send((id, req)); - final res = await completer.future as PayloadResult; - return res.payload; - } - - Future listTransactions(String walletName, String from, String count) async { - if (_closed) throw StateError('Closed'); - final completer = Completer.sync(); - final id = _idCounter++; - _activeRequests[id] = completer; - final req = { - "method": "listtransactions", - "name": walletName, - "from": from, - "count": count, - }; - _commands.send((id, req)); - final res = await completer.future as PayloadResult; - return res.payload; - } - - Future bestBlock(String walletName) async { - if (_closed) throw StateError('Closed'); - final completer = Completer.sync(); - final id = _idCounter++; - _activeRequests[id] = completer; - final req = { - "method": "bestblock", - "name": walletName, - }; - _commands.send((id, req)); - final res = await completer.future as PayloadResult; - return res.payload; - } - - Future listUnspents(String walletName) async { - if (_closed) throw StateError('Closed'); - final completer = Completer.sync(); - final id = _idCounter++; - _activeRequests[id] = completer; - final req = { - "method": "listunspents", - "name": walletName, - }; - _commands.send((id, req)); - final res = await completer.future as PayloadResult; - return res.payload; - } - - Future rescanFromHeight(String walletName, String height) async { - if (_closed) throw StateError('Closed'); - final completer = Completer.sync(); - final id = _idCounter++; - _activeRequests[id] = completer; - final req = { - "method": "rescanfromheight", - "name": walletName, - "height": height, - }; - _commands.send((id, req)); - final res = await completer.future as PayloadResult; - return res.payload; - } - - Future signMessage( - String walletName, String message, String address, String walletPass) async { - if (_closed) throw StateError('Closed'); - final completer = Completer.sync(); - final id = _idCounter++; - _activeRequests[id] = completer; - final req = { - "method": "signmessage", - "name": walletName, - "message": message, - "address": address, - "pass": walletPass, - }; - _commands.send((id, req)); - final res = await completer.future as PayloadResult; - return res.payload; - } - - Future verifyMessage( - String walletName, String message, String address, String sig) async { - if (_closed) throw StateError('Closed'); - final completer = Completer.sync(); - final id = _idCounter++; - _activeRequests[id] = completer; - final req = { - "method": "verifymessage", - "name": walletName, - "message": message, - "address": address, - "sig": sig, - }; - _commands.send((id, req)); - final res = await completer.future as PayloadResult; - return res.payload; - } - - Future newExternalAddress(String walletName) async { - if (_closed) throw StateError('Closed'); - final completer = Completer.sync(); - final id = _idCounter++; - _activeRequests[id] = completer; - final req = { - "method": "newexternaladdress", - "name": walletName, - }; - _commands.send((id, req)); - final res = await completer.future as PayloadResult; - if (res.errCode == ErrCodeNotSynced) { - // Wallet is not synced. We do not want to give out a used address so give - // nothing. - return null; - } - checkErr(res.err); - return res.payload; - } - - Future defaultPubkey(String walletName) async { - if (_closed) throw StateError('Closed'); - final completer = Completer.sync(); - final id = _idCounter++; - _activeRequests[id] = completer; - final req = { - "method": "defaultpubkey", - "name": walletName, - }; - _commands.send((id, req)); - final res = await completer.future as PayloadResult; - return res.payload; - } - - Future addresses(String walletName, String nUsed, String nUnused) async { - if (_closed) throw StateError('Closed'); - final completer = Completer.sync(); - final id = _idCounter++; - _activeRequests[id] = completer; - final req = { - "method": "addresses", - "name": walletName, - "nused": nUsed, - "nunused": nUnused, - }; - _commands.send((id, req)); - final res = await completer.future as PayloadResult; - return res.payload; - } - - Future birthState(String walletName) async { - if (_closed) throw StateError('Closed'); - final completer = Completer.sync(); - final id = _idCounter++; - _activeRequests[id] = completer; - final req = { - "method": "birthstate", - "name": walletName, - }; - _commands.send((id, req)); - final res = await completer.future as PayloadResult; - return res.payload; - } - - Future shutdown() async { - if (_closed) throw StateError('Closed'); - final completer = Completer.sync(); - final id = _idCounter++; - _activeRequests[id] = completer; - final req = { - "method": "shutdown", - }; - _commands.send((id, req)); - await completer.future as PayloadResult; - } - - void close() { - if (!_closed) { - _closed = true; - _commands.send('shutdown'); - if (_activeRequests.isEmpty) _responses.close(); - } - } -} diff --git a/cw_decred/lib/api/util.dart b/cw_decred/lib/api/util.dart deleted file mode 100644 index 42c3def7..00000000 --- a/cw_decred/lib/api/util.dart +++ /dev/null @@ -1,64 +0,0 @@ -import 'dart:ffi'; -import 'package:ffi/ffi.dart'; -import 'dart:convert'; - -class PayloadResult { - final String payload; - final String err; - final int errCode; - - const PayloadResult(this.payload, this.err, this.errCode); -} - -// Executes the provided fn and converts the string response to a PayloadResult. -// Returns payload, error code, and error. -PayloadResult executePayloadFn({ - required Pointer fn(), - required List ptrsToFree, - bool skipErrorCheck = false, -}) { - final jsonStr = fn().toDartString(); - freePointers(ptrsToFree); - if (jsonStr == null) throw Exception("no json return from wallet library"); - final decoded = json.decode(jsonStr); - - final err = decoded["error"] ?? ""; - if (!skipErrorCheck) { - checkErr(err); - } - - final payload = decoded["payload"] ?? ""; - final errCode = decoded["errorcode"] ?? -1; - return new PayloadResult(payload, err, errCode); -} - -void freePointers(List ptrsToFree) { - for (final ptr in ptrsToFree) { - malloc.free(ptr); - } -} - -void checkErr(String err) { - if (err == "") return; - throw Exception(err); -} - -extension StringUtil on String { - Pointer toCString() => toNativeUtf8().cast(); -} - -extension CStringUtil on Pointer { - bool get isNull => address == nullptr.address; - - free() { - malloc.free(this); - } - - String? toDartString() { - if (isNull) return null; - - final str = cast().toDartString(); - free(); - return str; - } -} diff --git a/cw_decred/lib/balance.dart b/cw_decred/lib/balance.dart deleted file mode 100644 index 97889c9a..00000000 --- a/cw_decred/lib/balance.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'package:cw_decred/amount_format.dart'; -import 'package:cw_core/balance.dart'; - -class DecredBalance extends Balance { - DecredBalance({required this.confirmed, required this.unconfirmed, required int frozen}) - : _frozen = frozen, super.fromInt(confirmed, unconfirmed); - - factory DecredBalance.zero() => DecredBalance(confirmed: 0, unconfirmed: 0, frozen: 0); - - final int confirmed; - final int unconfirmed; - final int _frozen; - BigInt get frozen => BigInt.from(_frozen); - - @override - String get formattedAvailableBalance => decredAmountToString(amount: confirmed - _frozen); - - @override - String get formattedAdditionalBalance => decredAmountToString(amount: unconfirmed); - - @override - String get formattedUnAvailableBalance { - final frozenFormatted = decredAmountToString(amount: _frozen); - return frozenFormatted == '0.0' ? '' : frozenFormatted; - } -} diff --git a/cw_decred/lib/mnemonic.dart b/cw_decred/lib/mnemonic.dart deleted file mode 100644 index bd39e2a1..00000000 --- a/cw_decred/lib/mnemonic.dart +++ /dev/null @@ -1,2050 +0,0 @@ -final wordlist = [ - "abandon", - "ability", - "able", - "about", - "above", - "absent", - "absorb", - "abstract", - "absurd", - "abuse", - "access", - "accident", - "account", - "accuse", - "achieve", - "acid", - "acoustic", - "acquire", - "across", - "act", - "action", - "actor", - "actress", - "actual", - "adapt", - "add", - "addict", - "address", - "adjust", - "admit", - "adult", - "advance", - "advice", - "aerobic", - "affair", - "afford", - "afraid", - "again", - "age", - "agent", - "agree", - "ahead", - "aim", - "air", - "airport", - "aisle", - "alarm", - "album", - "alcohol", - "alert", - "alien", - "all", - "alley", - "allow", - "almost", - "alone", - "alpha", - "already", - "also", - "alter", - "always", - "amateur", - "amazing", - "among", - "amount", - "amused", - "analyst", - "anchor", - "ancient", - "anger", - "angle", - "angry", - "animal", - "ankle", - "announce", - "annual", - "another", - "answer", - "antenna", - "antique", - "anxiety", - "any", - "apart", - "apology", - "appear", - "apple", - "approve", - "april", - "arch", - "arctic", - "area", - "arena", - "argue", - "arm", - "armed", - "armor", - "army", - "around", - "arrange", - "arrest", - "arrive", - "arrow", - "art", - "artefact", - "artist", - "artwork", - "ask", - "aspect", - "assault", - "asset", - "assist", - "assume", - "asthma", - "athlete", - "atom", - "attack", - "attend", - "attitude", - "attract", - "auction", - "audit", - "august", - "aunt", - "author", - "auto", - "autumn", - "average", - "avocado", - "avoid", - "awake", - "aware", - "away", - "awesome", - "awful", - "awkward", - "axis", - "baby", - "bachelor", - "bacon", - "badge", - "bag", - "balance", - "balcony", - "ball", - "bamboo", - "banana", - "banner", - "bar", - "barely", - "bargain", - "barrel", - "base", - "basic", - "basket", - "battle", - "beach", - "bean", - "beauty", - "because", - "become", - "beef", - "before", - "begin", - "behave", - "behind", - "believe", - "below", - "belt", - "bench", - "benefit", - "best", - "betray", - "better", - "between", - "beyond", - "bicycle", - "bid", - "bike", - "bind", - "biology", - "bird", - "birth", - "bitter", - "black", - "blade", - "blame", - "blanket", - "blast", - "bleak", - "bless", - "blind", - "blood", - "blossom", - "blouse", - "blue", - "blur", - "blush", - "board", - "boat", - "body", - "boil", - "bomb", - "bone", - "bonus", - "book", - "boost", - "border", - "boring", - "borrow", - "boss", - "bottom", - "bounce", - "box", - "boy", - "bracket", - "brain", - "brand", - "brass", - "brave", - "bread", - "breeze", - "brick", - "bridge", - "brief", - "bright", - "bring", - "brisk", - "broccoli", - "broken", - "bronze", - "broom", - "brother", - "brown", - "brush", - "bubble", - "buddy", - "budget", - "buffalo", - "build", - "bulb", - "bulk", - "bullet", - "bundle", - "bunker", - "burden", - "burger", - "burst", - "bus", - "business", - "busy", - "butter", - "buyer", - "buzz", - "cabbage", - "cabin", - "cable", - "cactus", - "cage", - "cake", - "call", - "calm", - "camera", - "camp", - "can", - "canal", - "cancel", - "candy", - "cannon", - "canoe", - "canvas", - "canyon", - "capable", - "capital", - "captain", - "car", - "carbon", - "card", - "cargo", - "carpet", - "carry", - "cart", - "case", - "cash", - "casino", - "castle", - "casual", - "cat", - "catalog", - "catch", - "category", - "cattle", - "caught", - "cause", - "caution", - "cave", - "ceiling", - "celery", - "cement", - "census", - "century", - "cereal", - "certain", - "chair", - "chalk", - "champion", - "change", - "chaos", - "chapter", - "charge", - "chase", - "chat", - "cheap", - "check", - "cheese", - "chef", - "cherry", - "chest", - "chicken", - "chief", - "child", - "chimney", - "choice", - "choose", - "chronic", - "chuckle", - "chunk", - "churn", - "cigar", - "cinnamon", - "circle", - "citizen", - "city", - "civil", - "claim", - "clap", - "clarify", - "claw", - "clay", - "clean", - "clerk", - "clever", - "click", - "client", - "cliff", - "climb", - "clinic", - "clip", - "clock", - "clog", - "close", - "cloth", - "cloud", - "clown", - "club", - "clump", - "cluster", - "clutch", - "coach", - "coast", - "coconut", - "code", - "coffee", - "coil", - "coin", - "collect", - "color", - "column", - "combine", - "come", - "comfort", - "comic", - "common", - "company", - "concert", - "conduct", - "confirm", - "congress", - "connect", - "consider", - "control", - "convince", - "cook", - "cool", - "copper", - "copy", - "coral", - "core", - "corn", - "correct", - "cost", - "cotton", - "couch", - "country", - "couple", - "course", - "cousin", - "cover", - "coyote", - "crack", - "cradle", - "craft", - "cram", - "crane", - "crash", - "crater", - "crawl", - "crazy", - "cream", - "credit", - "creek", - "crew", - "cricket", - "crime", - "crisp", - "critic", - "crop", - "cross", - "crouch", - "crowd", - "crucial", - "cruel", - "cruise", - "crumble", - "crunch", - "crush", - "cry", - "crystal", - "cube", - "culture", - "cup", - "cupboard", - "curious", - "current", - "curtain", - "curve", - "cushion", - "custom", - "cute", - "cycle", - "dad", - "damage", - "damp", - "dance", - "danger", - "daring", - "dash", - "daughter", - "dawn", - "day", - "deal", - "debate", - "debris", - "decade", - "december", - "decide", - "decline", - "decorate", - "decrease", - "deer", - "defense", - "define", - "defy", - "degree", - "delay", - "deliver", - "demand", - "demise", - "denial", - "dentist", - "deny", - "depart", - "depend", - "deposit", - "depth", - "deputy", - "derive", - "describe", - "desert", - "design", - "desk", - "despair", - "destroy", - "detail", - "detect", - "develop", - "device", - "devote", - "diagram", - "dial", - "diamond", - "diary", - "dice", - "diesel", - "diet", - "differ", - "digital", - "dignity", - "dilemma", - "dinner", - "dinosaur", - "direct", - "dirt", - "disagree", - "discover", - "disease", - "dish", - "dismiss", - "disorder", - "display", - "distance", - "divert", - "divide", - "divorce", - "dizzy", - "doctor", - "document", - "dog", - "doll", - "dolphin", - "domain", - "donate", - "donkey", - "donor", - "door", - "dose", - "double", - "dove", - "draft", - "dragon", - "drama", - "drastic", - "draw", - "dream", - "dress", - "drift", - "drill", - "drink", - "drip", - "drive", - "drop", - "drum", - "dry", - "duck", - "dumb", - "dune", - "during", - "dust", - "dutch", - "duty", - "dwarf", - "dynamic", - "eager", - "eagle", - "early", - "earn", - "earth", - "easily", - "east", - "easy", - "echo", - "ecology", - "economy", - "edge", - "edit", - "educate", - "effort", - "egg", - "eight", - "either", - "elbow", - "elder", - "electric", - "elegant", - "element", - "elephant", - "elevator", - "elite", - "else", - "embark", - "embody", - "embrace", - "emerge", - "emotion", - "employ", - "empower", - "empty", - "enable", - "enact", - "end", - "endless", - "endorse", - "enemy", - "energy", - "enforce", - "engage", - "engine", - "enhance", - "enjoy", - "enlist", - "enough", - "enrich", - "enroll", - "ensure", - "enter", - "entire", - "entry", - "envelope", - "episode", - "equal", - "equip", - "era", - "erase", - "erode", - "erosion", - "error", - "erupt", - "escape", - "essay", - "essence", - "estate", - "eternal", - "ethics", - "evidence", - "evil", - "evoke", - "evolve", - "exact", - "example", - "excess", - "exchange", - "excite", - "exclude", - "excuse", - "execute", - "exercise", - "exhaust", - "exhibit", - "exile", - "exist", - "exit", - "exotic", - "expand", - "expect", - "expire", - "explain", - "expose", - "express", - "extend", - "extra", - "eye", - "eyebrow", - "fabric", - "face", - "faculty", - "fade", - "faint", - "faith", - "fall", - "false", - "fame", - "family", - "famous", - "fan", - "fancy", - "fantasy", - "farm", - "fashion", - "fat", - "fatal", - "father", - "fatigue", - "fault", - "favorite", - "feature", - "february", - "federal", - "fee", - "feed", - "feel", - "female", - "fence", - "festival", - "fetch", - "fever", - "few", - "fiber", - "fiction", - "field", - "figure", - "file", - "film", - "filter", - "final", - "find", - "fine", - "finger", - "finish", - "fire", - "firm", - "first", - "fiscal", - "fish", - "fit", - "fitness", - "fix", - "flag", - "flame", - "flash", - "flat", - "flavor", - "flee", - "flight", - "flip", - "float", - "flock", - "floor", - "flower", - "fluid", - "flush", - "fly", - "foam", - "focus", - "fog", - "foil", - "fold", - "follow", - "food", - "foot", - "force", - "forest", - "forget", - "fork", - "fortune", - "forum", - "forward", - "fossil", - "foster", - "found", - "fox", - "fragile", - "frame", - "frequent", - "fresh", - "friend", - "fringe", - "frog", - "front", - "frost", - "frown", - "frozen", - "fruit", - "fuel", - "fun", - "funny", - "furnace", - "fury", - "future", - "gadget", - "gain", - "galaxy", - "gallery", - "game", - "gap", - "garage", - "garbage", - "garden", - "garlic", - "garment", - "gas", - "gasp", - "gate", - "gather", - "gauge", - "gaze", - "general", - "genius", - "genre", - "gentle", - "genuine", - "gesture", - "ghost", - "giant", - "gift", - "giggle", - "ginger", - "giraffe", - "girl", - "give", - "glad", - "glance", - "glare", - "glass", - "glide", - "glimpse", - "globe", - "gloom", - "glory", - "glove", - "glow", - "glue", - "goat", - "goddess", - "gold", - "good", - "goose", - "gorilla", - "gospel", - "gossip", - "govern", - "gown", - "grab", - "grace", - "grain", - "grant", - "grape", - "grass", - "gravity", - "great", - "green", - "grid", - "grief", - "grit", - "grocery", - "group", - "grow", - "grunt", - "guard", - "guess", - "guide", - "guilt", - "guitar", - "gun", - "gym", - "habit", - "hair", - "half", - "hammer", - "hamster", - "hand", - "happy", - "harbor", - "hard", - "harsh", - "harvest", - "hat", - "have", - "hawk", - "hazard", - "head", - "health", - "heart", - "heavy", - "hedgehog", - "height", - "hello", - "helmet", - "help", - "hen", - "hero", - "hidden", - "high", - "hill", - "hint", - "hip", - "hire", - "history", - "hobby", - "hockey", - "hold", - "hole", - "holiday", - "hollow", - "home", - "honey", - "hood", - "hope", - "horn", - "horror", - "horse", - "hospital", - "host", - "hotel", - "hour", - "hover", - "hub", - "huge", - "human", - "humble", - "humor", - "hundred", - "hungry", - "hunt", - "hurdle", - "hurry", - "hurt", - "husband", - "hybrid", - "ice", - "icon", - "idea", - "identify", - "idle", - "ignore", - "ill", - "illegal", - "illness", - "image", - "imitate", - "immense", - "immune", - "impact", - "impose", - "improve", - "impulse", - "inch", - "include", - "income", - "increase", - "index", - "indicate", - "indoor", - "industry", - "infant", - "inflict", - "inform", - "inhale", - "inherit", - "initial", - "inject", - "injury", - "inmate", - "inner", - "innocent", - "input", - "inquiry", - "insane", - "insect", - "inside", - "inspire", - "install", - "intact", - "interest", - "into", - "invest", - "invite", - "involve", - "iron", - "island", - "isolate", - "issue", - "item", - "ivory", - "jacket", - "jaguar", - "jar", - "jazz", - "jealous", - "jeans", - "jelly", - "jewel", - "job", - "join", - "joke", - "journey", - "joy", - "judge", - "juice", - "jump", - "jungle", - "junior", - "junk", - "just", - "kangaroo", - "keen", - "keep", - "ketchup", - "key", - "kick", - "kid", - "kidney", - "kind", - "kingdom", - "kiss", - "kit", - "kitchen", - "kite", - "kitten", - "kiwi", - "knee", - "knife", - "knock", - "know", - "lab", - "label", - "labor", - "ladder", - "lady", - "lake", - "lamp", - "language", - "laptop", - "large", - "later", - "latin", - "laugh", - "laundry", - "lava", - "law", - "lawn", - "lawsuit", - "layer", - "lazy", - "leader", - "leaf", - "learn", - "leave", - "lecture", - "left", - "leg", - "legal", - "legend", - "leisure", - "lemon", - "lend", - "length", - "lens", - "leopard", - "lesson", - "letter", - "level", - "liar", - "liberty", - "library", - "license", - "life", - "lift", - "light", - "like", - "limb", - "limit", - "link", - "lion", - "liquid", - "list", - "little", - "live", - "lizard", - "load", - "loan", - "lobster", - "local", - "lock", - "logic", - "lonely", - "long", - "loop", - "lottery", - "loud", - "lounge", - "love", - "loyal", - "lucky", - "luggage", - "lumber", - "lunar", - "lunch", - "luxury", - "lyrics", - "machine", - "mad", - "magic", - "magnet", - "maid", - "mail", - "main", - "major", - "make", - "mammal", - "man", - "manage", - "mandate", - "mango", - "mansion", - "manual", - "maple", - "marble", - "march", - "margin", - "marine", - "market", - "marriage", - "mask", - "mass", - "master", - "match", - "material", - "math", - "matrix", - "matter", - "maximum", - "maze", - "meadow", - "mean", - "measure", - "meat", - "mechanic", - "medal", - "media", - "melody", - "melt", - "member", - "memory", - "mention", - "menu", - "mercy", - "merge", - "merit", - "merry", - "mesh", - "message", - "metal", - "method", - "middle", - "midnight", - "milk", - "million", - "mimic", - "mind", - "minimum", - "minor", - "minute", - "miracle", - "mirror", - "misery", - "miss", - "mistake", - "mix", - "mixed", - "mixture", - "mobile", - "model", - "modify", - "mom", - "moment", - "monitor", - "monkey", - "monster", - "month", - "moon", - "moral", - "more", - "morning", - "mosquito", - "mother", - "motion", - "motor", - "mountain", - "mouse", - "move", - "movie", - "much", - "muffin", - "mule", - "multiply", - "muscle", - "museum", - "mushroom", - "music", - "must", - "mutual", - "myself", - "mystery", - "myth", - "naive", - "name", - "napkin", - "narrow", - "nasty", - "nation", - "nature", - "near", - "neck", - "need", - "negative", - "neglect", - "neither", - "nephew", - "nerve", - "nest", - "net", - "network", - "neutral", - "never", - "news", - "next", - "nice", - "night", - "noble", - "noise", - "nominee", - "noodle", - "normal", - "north", - "nose", - "notable", - "note", - "nothing", - "notice", - "novel", - "now", - "nuclear", - "number", - "nurse", - "nut", - "oak", - "obey", - "object", - "oblige", - "obscure", - "observe", - "obtain", - "obvious", - "occur", - "ocean", - "october", - "odor", - "off", - "offer", - "office", - "often", - "oil", - "okay", - "old", - "olive", - "olympic", - "omit", - "once", - "one", - "onion", - "online", - "only", - "open", - "opera", - "opinion", - "oppose", - "option", - "orange", - "orbit", - "orchard", - "order", - "ordinary", - "organ", - "orient", - "original", - "orphan", - "ostrich", - "other", - "outdoor", - "outer", - "output", - "outside", - "oval", - "oven", - "over", - "own", - "owner", - "oxygen", - "oyster", - "ozone", - "pact", - "paddle", - "page", - "pair", - "palace", - "palm", - "panda", - "panel", - "panic", - "panther", - "paper", - "parade", - "parent", - "park", - "parrot", - "party", - "pass", - "patch", - "path", - "patient", - "patrol", - "pattern", - "pause", - "pave", - "payment", - "peace", - "peanut", - "pear", - "peasant", - "pelican", - "pen", - "penalty", - "pencil", - "people", - "pepper", - "perfect", - "permit", - "person", - "pet", - "phone", - "photo", - "phrase", - "physical", - "piano", - "picnic", - "picture", - "piece", - "pig", - "pigeon", - "pill", - "pilot", - "pink", - "pioneer", - "pipe", - "pistol", - "pitch", - "pizza", - "place", - "planet", - "plastic", - "plate", - "play", - "please", - "pledge", - "pluck", - "plug", - "plunge", - "poem", - "poet", - "point", - "polar", - "pole", - "police", - "pond", - "pony", - "pool", - "popular", - "portion", - "position", - "possible", - "post", - "potato", - "pottery", - "poverty", - "powder", - "power", - "practice", - "praise", - "predict", - "prefer", - "prepare", - "present", - "pretty", - "prevent", - "price", - "pride", - "primary", - "print", - "priority", - "prison", - "private", - "prize", - "problem", - "process", - "produce", - "profit", - "program", - "project", - "promote", - "proof", - "property", - "prosper", - "protect", - "proud", - "provide", - "public", - "pudding", - "pull", - "pulp", - "pulse", - "pumpkin", - "punch", - "pupil", - "puppy", - "purchase", - "purity", - "purpose", - "purse", - "push", - "put", - "puzzle", - "pyramid", - "quality", - "quantum", - "quarter", - "question", - "quick", - "quit", - "quiz", - "quote", - "rabbit", - "raccoon", - "race", - "rack", - "radar", - "radio", - "rail", - "rain", - "raise", - "rally", - "ramp", - "ranch", - "random", - "range", - "rapid", - "rare", - "rate", - "rather", - "raven", - "raw", - "razor", - "ready", - "real", - "reason", - "rebel", - "rebuild", - "recall", - "receive", - "recipe", - "record", - "recycle", - "reduce", - "reflect", - "reform", - "refuse", - "region", - "regret", - "regular", - "reject", - "relax", - "release", - "relief", - "rely", - "remain", - "remember", - "remind", - "remove", - "render", - "renew", - "rent", - "reopen", - "repair", - "repeat", - "replace", - "report", - "require", - "rescue", - "resemble", - "resist", - "resource", - "response", - "result", - "retire", - "retreat", - "return", - "reunion", - "reveal", - "review", - "reward", - "rhythm", - "rib", - "ribbon", - "rice", - "rich", - "ride", - "ridge", - "rifle", - "right", - "rigid", - "ring", - "riot", - "ripple", - "risk", - "ritual", - "rival", - "river", - "road", - "roast", - "robot", - "robust", - "rocket", - "romance", - "roof", - "rookie", - "room", - "rose", - "rotate", - "rough", - "round", - "route", - "royal", - "rubber", - "rude", - "rug", - "rule", - "run", - "runway", - "rural", - "sad", - "saddle", - "sadness", - "safe", - "sail", - "salad", - "salmon", - "salon", - "salt", - "salute", - "same", - "sample", - "sand", - "satisfy", - "satoshi", - "sauce", - "sausage", - "save", - "say", - "scale", - "scan", - "scare", - "scatter", - "scene", - "scheme", - "school", - "science", - "scissors", - "scorpion", - "scout", - "scrap", - "screen", - "script", - "scrub", - "sea", - "search", - "season", - "seat", - "second", - "secret", - "section", - "security", - "seed", - "seek", - "segment", - "select", - "sell", - "seminar", - "senior", - "sense", - "sentence", - "series", - "service", - "session", - "settle", - "setup", - "seven", - "shadow", - "shaft", - "shallow", - "share", - "shed", - "shell", - "sheriff", - "shield", - "shift", - "shine", - "ship", - "shiver", - "shock", - "shoe", - "shoot", - "shop", - "short", - "shoulder", - "shove", - "shrimp", - "shrug", - "shuffle", - "shy", - "sibling", - "sick", - "side", - "siege", - "sight", - "sign", - "silent", - "silk", - "silly", - "silver", - "similar", - "simple", - "since", - "sing", - "siren", - "sister", - "situate", - "six", - "size", - "skate", - "sketch", - "ski", - "skill", - "skin", - "skirt", - "skull", - "slab", - "slam", - "sleep", - "slender", - "slice", - "slide", - "slight", - "slim", - "slogan", - "slot", - "slow", - "slush", - "small", - "smart", - "smile", - "smoke", - "smooth", - "snack", - "snake", - "snap", - "sniff", - "snow", - "soap", - "soccer", - "social", - "sock", - "soda", - "soft", - "solar", - "soldier", - "solid", - "solution", - "solve", - "someone", - "song", - "soon", - "sorry", - "sort", - "soul", - "sound", - "soup", - "source", - "south", - "space", - "spare", - "spatial", - "spawn", - "speak", - "special", - "speed", - "spell", - "spend", - "sphere", - "spice", - "spider", - "spike", - "spin", - "spirit", - "split", - "spoil", - "sponsor", - "spoon", - "sport", - "spot", - "spray", - "spread", - "spring", - "spy", - "square", - "squeeze", - "squirrel", - "stable", - "stadium", - "staff", - "stage", - "stairs", - "stamp", - "stand", - "start", - "state", - "stay", - "steak", - "steel", - "stem", - "step", - "stereo", - "stick", - "still", - "sting", - "stock", - "stomach", - "stone", - "stool", - "story", - "stove", - "strategy", - "street", - "strike", - "strong", - "struggle", - "student", - "stuff", - "stumble", - "style", - "subject", - "submit", - "subway", - "success", - "such", - "sudden", - "suffer", - "sugar", - "suggest", - "suit", - "summer", - "sun", - "sunny", - "sunset", - "super", - "supply", - "supreme", - "sure", - "surface", - "surge", - "surprise", - "surround", - "survey", - "suspect", - "sustain", - "swallow", - "swamp", - "swap", - "swarm", - "swear", - "sweet", - "swift", - "swim", - "swing", - "switch", - "sword", - "symbol", - "symptom", - "syrup", - "system", - "table", - "tackle", - "tag", - "tail", - "talent", - "talk", - "tank", - "tape", - "target", - "task", - "taste", - "tattoo", - "taxi", - "teach", - "team", - "tell", - "ten", - "tenant", - "tennis", - "tent", - "term", - "test", - "text", - "thank", - "that", - "theme", - "then", - "theory", - "there", - "they", - "thing", - "this", - "thought", - "three", - "thrive", - "throw", - "thumb", - "thunder", - "ticket", - "tide", - "tiger", - "tilt", - "timber", - "time", - "tiny", - "tip", - "tired", - "tissue", - "title", - "toast", - "tobacco", - "today", - "toddler", - "toe", - "together", - "toilet", - "token", - "tomato", - "tomorrow", - "tone", - "tongue", - "tonight", - "tool", - "tooth", - "top", - "topic", - "topple", - "torch", - "tornado", - "tortoise", - "toss", - "total", - "tourist", - "toward", - "tower", - "town", - "toy", - "track", - "trade", - "traffic", - "tragic", - "train", - "transfer", - "trap", - "trash", - "travel", - "tray", - "treat", - "tree", - "trend", - "trial", - "tribe", - "trick", - "trigger", - "trim", - "trip", - "trophy", - "trouble", - "truck", - "true", - "truly", - "trumpet", - "trust", - "truth", - "try", - "tube", - "tuition", - "tumble", - "tuna", - "tunnel", - "turkey", - "turn", - "turtle", - "twelve", - "twenty", - "twice", - "twin", - "twist", - "two", - "type", - "typical", - "ugly", - "umbrella", - "unable", - "unaware", - "uncle", - "uncover", - "under", - "undo", - "unfair", - "unfold", - "unhappy", - "uniform", - "unique", - "unit", - "universe", - "unknown", - "unlock", - "until", - "unusual", - "unveil", - "update", - "upgrade", - "uphold", - "upon", - "upper", - "upset", - "urban", - "urge", - "usage", - "use", - "used", - "useful", - "useless", - "usual", - "utility", - "vacant", - "vacuum", - "vague", - "valid", - "valley", - "valve", - "van", - "vanish", - "vapor", - "various", - "vast", - "vault", - "vehicle", - "velvet", - "vendor", - "venture", - "venue", - "verb", - "verify", - "version", - "very", - "vessel", - "veteran", - "viable", - "vibrant", - "vicious", - "victory", - "video", - "view", - "village", - "vintage", - "violin", - "virtual", - "virus", - "visa", - "visit", - "visual", - "vital", - "vivid", - "vocal", - "voice", - "void", - "volcano", - "volume", - "vote", - "voyage", - "wage", - "wagon", - "wait", - "walk", - "wall", - "walnut", - "want", - "warfare", - "warm", - "warrior", - "wash", - "wasp", - "waste", - "water", - "wave", - "way", - "wealth", - "weapon", - "wear", - "weasel", - "weather", - "web", - "wedding", - "weekend", - "weird", - "welcome", - "west", - "wet", - "whale", - "what", - "wheat", - "wheel", - "when", - "where", - "whip", - "whisper", - "wide", - "width", - "wife", - "wild", - "will", - "win", - "window", - "wine", - "wing", - "wink", - "winner", - "winter", - "wire", - "wisdom", - "wise", - "wish", - "witness", - "wolf", - "woman", - "wonder", - "wood", - "wool", - "word", - "work", - "world", - "worry", - "worth", - "wrap", - "wreck", - "wrestle", - "wrist", - "write", - "wrong", - "yard", - "year", - "yellow", - "you", - "young", - "youth", - "zebra", - "zero", - "zone", - "zoo", -]; diff --git a/cw_decred/lib/pending_transaction.dart b/cw_decred/lib/pending_transaction.dart deleted file mode 100644 index 23c76920..00000000 --- a/cw_decred/lib/pending_transaction.dart +++ /dev/null @@ -1,42 +0,0 @@ -import 'package:cw_core/pending_transaction.dart'; -import 'package:cw_decred/amount_format.dart'; - -class DecredPendingTransaction with PendingTransaction { - DecredPendingTransaction( - {required this.txid, - required this.amount, - required this.fee, - required this.rawHex, - required this.send}); - - final int amount; - final int fee; - final String txid; - final String rawHex; - final Future Function() send; - - @override - String get id => txid; - - @override - String get amountFormatted => decredAmountToString(amount: amount); - - @override - String get feeFormatted => "$feeFormattedValue DCR"; - - @override - String get feeFormattedValue => decredAmountToString(amount: fee); - - @override - String get hex => rawHex; - - @override - Future commit() async { - return send(); - } - - @override - Future> commitUR() { - throw UnimplementedError(); - } -} diff --git a/cw_decred/lib/transaction_credentials.dart b/cw_decred/lib/transaction_credentials.dart deleted file mode 100644 index 5ace384f..00000000 --- a/cw_decred/lib/transaction_credentials.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'package:cw_decred/transaction_priority.dart'; -import 'package:cw_core/output_info.dart'; - -class DecredTransactionCredentials { - DecredTransactionCredentials(this.outputs, {required this.priority, this.feeRate}); - - final List outputs; - final DecredTransactionPriority? priority; - final int? feeRate; -} diff --git a/cw_decred/lib/transaction_history.dart b/cw_decred/lib/transaction_history.dart deleted file mode 100644 index 02227aa9..00000000 --- a/cw_decred/lib/transaction_history.dart +++ /dev/null @@ -1,31 +0,0 @@ -import 'package:mobx/mobx.dart'; -import 'package:cw_core/transaction_info.dart'; -import 'package:cw_core/transaction_history.dart'; - -class DecredTransactionHistory extends TransactionHistoryBase { - DecredTransactionHistory() { - transactions = ObservableMap(); - } - - @override - void addOne(TransactionInfo transaction) => transactions[transaction.id] = transaction; - - @override - void addMany(Map transactions) => this.transactions.addAll(transactions); - - @override - Future save() async {} - - // update returns true if a known transaction that is not pending was found. - bool update(Map txs) { - var foundOldTx = false; - txs.forEach((_, tx) { - if (!this.transactions.containsKey(tx.id) || this.transactions[tx.id]!.isPending) { - this.transactions[tx.id] = tx; - } else { - foundOldTx = true; - } - }); - return foundOldTx; - } -} diff --git a/cw_decred/lib/transaction_info.dart b/cw_decred/lib/transaction_info.dart deleted file mode 100644 index 18913175..00000000 --- a/cw_decred/lib/transaction_info.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'package:cw_core/currency_for_wallet_type.dart'; -import 'package:cw_core/transaction_direction.dart'; -import 'package:cw_core/transaction_info.dart'; -import 'package:cw_core/format_amount.dart'; -import 'package:cw_core/wallet_type.dart'; -import 'package:cw_decred/amount_format.dart'; - -class DecredTransactionInfo extends TransactionInfo { - DecredTransactionInfo({ - required String id, - required int amount, - required int fee, - required TransactionDirection direction, - required bool isPending, - required DateTime date, - required int height, - required int confirmations, - required String to, - }) { - this.id = id; - this.amount = amount; - this.fee = fee; - this.height = height; - this.direction = direction; - this.date = date; - this.isPending = isPending; - this.confirmations = confirmations; - this.to = to; - } - - String? _fiatAmount; - - @override - String amountFormatted() => - '${formatAmount(decredAmountToString(amount: amount))} ${walletTypeToCryptoCurrency(WalletType.decred).title}'; - - @override - String? feeFormatted() => - '${formatAmount(decredAmountToString(amount: fee ?? 0))} ${walletTypeToCryptoCurrency(WalletType.decred).title}'; - - @override - String fiatAmount() => _fiatAmount ?? ''; - - @override - void changeFiatAmount(String amount) => _fiatAmount = formatAmount(amount); -} diff --git a/cw_decred/lib/transaction_priority.dart b/cw_decred/lib/transaction_priority.dart deleted file mode 100644 index 735d0b47..00000000 --- a/cw_decred/lib/transaction_priority.dart +++ /dev/null @@ -1,73 +0,0 @@ -import 'package:cw_core/transaction_priority.dart'; -import 'package:flutter/foundation.dart'; - -class DecredTransactionPriority extends TransactionPriority { - const DecredTransactionPriority({required String title, required int raw}) - : super(title: title, raw: raw); - - static const List all = [fast, medium, slow]; - static const DecredTransactionPriority slow = DecredTransactionPriority(title: 'Slow', raw: 0); - static const DecredTransactionPriority medium = - DecredTransactionPriority(title: 'Medium', raw: 1); - static const DecredTransactionPriority fast = DecredTransactionPriority(title: 'Fast', raw: 2); - - static DecredTransactionPriority deserialize({required int raw}) { - switch (raw) { - case 0: - return slow; - case 1: - return medium; - case 2: - return fast; - default: - if (kDebugMode) { - throw Exception('Unexpected token: $raw for DecredTransactionPriority deserialize'); - } - return medium; - } - } - - String get units => 'atom'; - - @override - String toString() { - var label = ''; - - switch (this) { - case DecredTransactionPriority.slow: - label = 'Slow ~24hrs'; // '${S.current.transaction_priority_slow} ~24hrs'; - break; - case DecredTransactionPriority.medium: - label = 'Medium'; // S.current.transaction_priority_medium; - break; - case DecredTransactionPriority.fast: - label = 'Fast'; // S.current.transaction_priority_fast; - break; - default: - break; - } - - return label; - } - - String labelWithRate(int rate) => '${toString()} ($rate ${units}/byte)'; -} - -class FeeCache { - int _feeRate; - DateTime stamp; - FeeCache(this._feeRate) : this.stamp = DateTime(0, 0, 0, 0, 0, 0, 0, 0); - - bool isOld() { - return this.stamp.add(const Duration(minutes: 30)).isBefore(DateTime.now()); - } - - void update(int feeRate) { - this._feeRate = feeRate; - this.stamp = DateTime.now(); - } - - int feeRate() { - return this._feeRate; - } -} diff --git a/cw_decred/lib/wallet.dart b/cw_decred/lib/wallet.dart deleted file mode 100644 index 97c11833..00000000 --- a/cw_decred/lib/wallet.dart +++ /dev/null @@ -1,770 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; -import 'package:path/path.dart' as p; -import 'package:cw_core/exceptions.dart'; -import 'package:cw_core/transaction_direction.dart'; -import 'package:cw_core/utils/print_verbose.dart'; -import 'package:cw_core/pathForWallet.dart'; -import 'package:cw_core/wallet_type.dart'; -import 'package:cw_decred/amount_format.dart'; -import 'package:cw_decred/pending_transaction.dart'; -import 'package:cw_decred/transaction_credentials.dart'; -import 'package:flutter/foundation.dart'; -import 'package:mobx/mobx.dart'; -import 'package:hive/hive.dart'; - -import 'package:cw_decred/api/libdcrwallet.dart'; -import 'package:cw_decred/transaction_history.dart'; -import 'package:cw_decred/wallet_addresses.dart'; -import 'package:cw_decred/transaction_priority.dart'; -import 'package:cw_decred/wallet_service.dart'; -import 'package:cw_decred/balance.dart'; -import 'package:cw_decred/transaction_info.dart'; -import 'package:cw_core/crypto_currency.dart'; -import 'package:cw_core/wallet_info.dart'; -import 'package:cw_core/wallet_base.dart'; -import 'package:cw_core/transaction_priority.dart'; -import 'package:cw_core/pending_transaction.dart'; -import 'package:cw_core/sync_status.dart'; -import 'package:cw_core/node.dart'; -import 'package:cw_core/unspent_coins_info.dart'; -import 'package:cw_core/unspent_transaction_output.dart'; - -part 'wallet.g.dart'; - -class DecredWallet = DecredWalletBase with _$DecredWallet; - -abstract class DecredWalletBase - extends WalletBase with Store { - DecredWalletBase(WalletInfo walletInfo, DerivationInfo derivationInfo, String password, Box unspentCoinsInfo, - Libwallet libwallet, Function() closeLibwallet) - : _password = password, - _libwallet = libwallet, - _closeLibwallet = closeLibwallet, - this.syncStatus = NotConnectedSyncStatus(), - this.unspentCoinsInfo = unspentCoinsInfo, - this.watchingOnly = - derivationInfo.derivationPath == DecredWalletService.pubkeyRestorePath || - derivationInfo.derivationPath == - DecredWalletService.pubkeyRestorePathTestnet, - this.balance = ObservableMap.of({CryptoCurrency.dcr: DecredBalance.zero()}), - this.isTestnet = derivationInfo.derivationPath == - DecredWalletService.seedRestorePathTestnet || - derivationInfo.derivationPath == - DecredWalletService.pubkeyRestorePathTestnet, - super(walletInfo, derivationInfo) { - walletAddresses = DecredWalletAddresses(walletInfo, libwallet, isTestnet); - transactionHistory = DecredTransactionHistory(); - - reaction((_) => isEnabledAutoGenerateSubaddress, (bool enabled) { - this.walletAddresses.isEnabledAutoGenerateSubaddress = enabled; - }); - } - - // NOTE: Hitting this max fee would be unexpected with current on chain use - // but this may need to be updated in the future. - final maxFeeRate = 100000; - - // syncIntervalSyncing is used up until synced, then transactions are checked - // every syncIntervalSynced. - final syncIntervalSyncing = 5; // seconds - final syncIntervalSynced = 30; // seconds - static final defaultFeeRate = 10000; - final String _password; - final Libwallet _libwallet; - final Function() _closeLibwallet; - final idPrefix = "decred_"; - - // TODO: Encrypt this. - var _seed = ""; - var _pubkey = ""; - var _unspents = []; - - // synced is used to set the syncTimer interval. - bool synced = false; - bool watchingOnly; - bool connecting = false; - String persistantPeer = "default-spv-nodes"; - FeeCache feeRateFast = FeeCache(defaultFeeRate); - FeeCache feeRateMedium = FeeCache(defaultFeeRate); - FeeCache feeRateSlow = FeeCache(defaultFeeRate); - Timer? syncTimer; - Box unspentCoinsInfo; - - @override - @observable - bool isEnabledAutoGenerateSubaddress = true; - - @override - @observable - SyncStatus syncStatus; - - @override - @observable - late ObservableMap balance; - - @override - late DecredWalletAddresses walletAddresses; - - @override - String? get seed { - if (watchingOnly) { - return null; - } - return _seed; - } - - @override - Object get keys => {}; - - @override - bool isTestnet; - - String get pubkey { - return _pubkey; - } - - @override - String formatCryptoAmount(String amount) => decredAmountToString(amount: int.parse(amount)); - - Future init() async { - final getSeed = () async { - if (!watchingOnly) { - _seed = await _libwallet.walletSeed(walletInfo.name, _password) ?? ""; - } - _pubkey = await _libwallet.defaultPubkey(walletInfo.name); - }; - await Future.wait([ - updateBalance(), - updateTransactionHistory(), - walletAddresses.init(), - fetchTransactions(), - updateFees(), - fetchUnspents(), - getSeed(), - ]); - } - - Future performBackgroundTasks() async { - if (!await checkSync()) { - if (synced == true) { - synced = false; - if (syncTimer != null) { - syncTimer!.cancel(); - } - syncTimer = Timer.periodic( - Duration(seconds: syncIntervalSyncing), (Timer t) => performBackgroundTasks()); - } - return; - } - // Set sync check interval lower since we are synced. - if (synced == false) { - synced = true; - if (syncTimer != null) { - syncTimer!.cancel(); - } - syncTimer = Timer.periodic( - Duration(seconds: syncIntervalSynced), (Timer t) => performBackgroundTasks()); - } - await Future.wait([ - updateTransactionHistory(), - updateFees(), - fetchUnspents(), - updateBalance(), - walletAddresses.updateAddressesInBox(), - ]); - } - - Future updateFees() async { - final feeForNb = (int nb) async { - try { - final feeStr = await _libwallet.estimateFee(walletInfo.name, nb); - var fee = int.parse(feeStr); - if (fee > maxFeeRate) { - throw "dcr fee returned from estimate fee was over max"; - } else if (fee <= 0) { - throw "dcr fee returned from estimate fee was zero"; - } - return fee; - } catch (e) { - printV(e); - return defaultFeeRate; - } - }; - if (feeRateSlow.isOld()) { - feeRateSlow.update(await feeForNb(4)); - } - if (feeRateMedium.isOld()) { - feeRateMedium.update(await feeForNb(2)); - } - if (feeRateFast.isOld()) { - feeRateFast.update(await feeForNb(1)); - } - } - - Future updateTransactionHistory() async { - // from is the number of transactions skipped from most recent, not block - // height. - var from = 0; - while (true) { - // Transactions are returned from newest to oldest. Loop fetching 5 txn - // at a time until we find a batch with txn that no longer need to be - // updated. - final txs = await this.fetchFiveTransactions(from); - if (txs.length == 0) { - return; - } - if (this.transactionHistory.update(txs)) { - return; - } - from += 5; - } - } - - Future checkSync() async { - final syncStatusJSON = await _libwallet.syncStatus(walletInfo.name); - final decoded = json.decode(syncStatusJSON.isEmpty ? "{}" : syncStatusJSON); - - final syncStatusCode = decoded["syncstatuscode"] ?? 0; - // final syncStatusStr = decoded["syncstatus"] ?? ""; - final targetHeight = decoded["targetheight"] ?? 1; - final numPeers = decoded["numpeers"] ?? 0; - // final cFiltersHeight = decoded["cfiltersheight"] ?? 0; - final headersHeight = decoded["headersheight"] ?? 0; - final rescanHeight = decoded["rescanheight"] ?? 0; - - if (numPeers == 0) { - syncStatus = NotConnectedSyncStatus(); - return false; - } - - // Sync codes: - // NotStarted = 0 - // FetchingCFilters = 1 - // FetchingHeaders = 2 - // DiscoveringAddrs = 3 - // Rescanning = 4 - // Complete = 5 - - if (syncStatusCode > 4) { - syncStatus = SyncedSyncStatus(); - return true; - } - - if (syncStatusCode == 0) { - syncStatus = ConnectedSyncStatus(); - return false; - } - - if (syncStatusCode == 1) { - syncStatus = SyncingSyncStatus(targetHeight, 0.0); - return false; - } - - if (syncStatusCode == 2) { - final headersProg = headersHeight / targetHeight; - // Only allow headers progress to go up half way. - syncStatus = SyncingSyncStatus(targetHeight - headersHeight, headersProg); - return false; - } - - // TODO: This step takes a while so should really get more info to the UI - // that we are discovering addresses. - if (syncStatusCode == 3) { - // Hover at half. - syncStatus = ProcessingSyncStatus(); - return false; - } - - if (syncStatusCode == 4) { - // Start at 75%. - final rescanProg = rescanHeight / targetHeight / 4; - syncStatus = SyncingSyncStatus(targetHeight - rescanHeight, .75 + rescanProg); - return false; - } - return false; - } - - @action - @override - Future connectToNode({required Node node}) async { - if (connecting) { - return; - } - connecting = true; - String addr = "default-spv-nodes"; - if (node.uri.host != addr) { - addr = node.uri.host; - if (node.uri.port != "") { - addr += ":" + node.uri.port.toString(); - } - } - if (addr != persistantPeer) { - if (syncTimer != null) { - syncTimer!.cancel(); - syncTimer = null; - } - persistantPeer = addr; - await _libwallet.closeWallet(walletInfo.name); - final network = isTestnet ? "testnet" : "mainnet"; - final dirPath = await pathForWalletDir(name: walletInfo.name, type: WalletType.decred); - final config = { - "name": walletInfo.name, - "datadir": dirPath, - "net": network, - "unsyncedaddrs": true, - }; - await _libwallet.loadWallet(jsonEncode(config)); - } - await this._startSync(); - connecting = false; - } - - @action - @override - Future startSync() async { - if (connecting) { - return; - } - connecting = true; - await this._startSync(); - connecting = false; - } - - Future _startSync() async { - if (syncTimer != null) { - return; - } - try { - syncStatus = ConnectingSyncStatus(); - await _libwallet.startSync( - walletInfo.name, - persistantPeer == "default-spv-nodes" ? "" : persistantPeer, - ); - syncTimer = Timer.periodic( - Duration(seconds: syncIntervalSyncing), (Timer t) => performBackgroundTasks()); - } catch (e) { - printV(e.toString()); - syncStatus = FailedSyncStatus(); - } - } - - @override - Future createTransaction(Object credentials) async { - if (watchingOnly) { - return DecredPendingTransaction( - txid: "", - amount: 0, - fee: 0, - rawHex: "", - send: () async { - throw "unable to send with watching only wallet"; - }); - } - var totalIn = 0; - final ignoreInputs = []; - this.unspentCoinsInfo.values.forEach((unspent) { - if (unspent.isFrozen || !unspent.isSending) { - final input = {"txid": unspent.hash, "vout": unspent.vout}; - ignoreInputs.add(input); - return; - } - totalIn += unspent.value; - }); - - final creds = credentials as DecredTransactionCredentials; - var totalAmt = 0; - var sendAll = false; - final outputs = []; - for (final out in creds.outputs) { - var amt = 0; - if (out.sendAll) { - if (creds.outputs.length != 1) { - throw "can only send all to one output"; - } - sendAll = true; - totalAmt = totalIn; - } else if (out.cryptoAmount != null) { - final coins = double.parse(out.cryptoAmount!); - amt = (coins * 1e8).round(); - } - totalAmt += amt; - final o = { - "address": out.isParsedAddress ? out.extractedAddress! : out.address, - "amount": amt - }; - outputs.add(o); - } - - // throw exception if no selected coins under coin control - // or if the total coins selected, is less than the amount the user wants to spend - if (ignoreInputs.length == unspentCoinsInfo.values.length || totalIn < totalAmt) { - throw TransactionNoInputsException(); - } - - // The inputs are always used. Currently we don't have use for this - // argument. sendall ingores output value and sends everything. - final signReq = { - // "inputs": inputs, - "ignoreInputs": ignoreInputs, - "outputs": outputs, - "feerate": creds.feeRate ?? defaultFeeRate, - "password": _password, - "sendall": sendAll, - }; - final res = await _libwallet.createSignedTransaction(walletInfo.name, jsonEncode(signReq)); - final decoded = json.decode(res); - final signedHex = decoded["signedhex"]; - final send = () async { - await _libwallet.sendRawTransaction(walletInfo.name, signedHex); - await updateBalance(); - }; - final fee = decoded["fee"] ?? 0; - if (sendAll) { - totalAmt = (totalAmt - fee).round(); - } - return DecredPendingTransaction( - txid: decoded["txid"] ?? "", amount: totalAmt, fee: fee, rawHex: signedHex, send: send); - } - - int feeRate(TransactionPriority priority) { - if (!(priority is DecredTransactionPriority)) { - return defaultFeeRate; - } - final p = priority; - switch (p) { - case DecredTransactionPriority.slow: - return feeRateSlow.feeRate(); - case DecredTransactionPriority.medium: - return feeRateMedium.feeRate(); - case DecredTransactionPriority.fast: - return feeRateFast.feeRate(); - } - return defaultFeeRate; - } - - @override - int calculateEstimatedFee(TransactionPriority priority, int? amount) { - if (priority is DecredTransactionPriority) { - final P2PKHOutputSize = - 36; // 8 bytes value + 2 bytes version + at least 1 byte varint script size + P2PKHPkScriptSize - // MsgTxOverhead is 4 bytes version (lower 2 bytes for the real transaction - // version and upper 2 bytes for the serialization type) + 4 bytes locktime - // + 4 bytes expiry + 3 bytes of varints for the number of transaction - // inputs (x2 for witness and prefix) and outputs - final MsgTxOverhead = 15; - // TxInOverhead is the overhead for a wire.TxIn with a scriptSig length < - // 254. prefix (41 bytes) + ValueIn (8 bytes) + BlockHeight (4 bytes) + - // BlockIndex (4 bytes) + sig script var int (at least 1 byte) - final TxInOverhead = 57; - final P2PKHInputSize = - TxInOverhead + 109; // TxInOverhead (57) + var int (1) + P2PKHSigScriptSize (108) - - int inputsCount = 1; - if (amount != null) { - inputsCount += _unspents.where((e) { - amount = (amount!) - e.value; - return (amount!) > 0; - }).length; - } - - // Estimate using a transaction consuming inoutsCount and paying to one address with change. - return (this.feeRate(priority) / 1000).round() * - (MsgTxOverhead + P2PKHInputSize * inputsCount + P2PKHOutputSize * 2); - } - return 0; - } - - @override - Future> fetchTransactions() async { - return this.fetchFiveTransactions(0); - } - - Future> fetchFiveTransactions(int from) async { - try { - final res = await _libwallet.listTransactions(walletInfo.name, from.toString(), "5"); - final decoded = json.decode(res); - var txs = {}; - for (final d in decoded) { - final txid = uniqueTxID(d["txid"] ?? "", d["vout"] ?? 0); - var direction = TransactionDirection.outgoing; - if (d["category"] == "receive") { - direction = TransactionDirection.incoming; - } - final amountDouble = d["amount"] ?? 0.0; - final amount = (amountDouble * 1e8).round().abs(); - final feeDouble = d["fee"] ?? 0.0; - final fee = (feeDouble * 1e8).round().abs(); - final confs = d["confirmations"] ?? 0; - final sendTime = d["time"] ?? 0; - final height = d["height"] ?? 0; - final txInfo = DecredTransactionInfo( - id: txid, - amount: amount, - fee: fee, - direction: direction, - isPending: confs == 0, - date: DateTime.fromMillisecondsSinceEpoch(sendTime * 1000, isUtc: false), - height: height, - confirmations: confs, - to: d["address"] ?? "", - ); - txs[txid] = txInfo; - } - return txs; - } catch (e) { - printV(e); - return {}; - } - } - - // uniqueTxID combines the tx id and vout to create a unique id. - String uniqueTxID(String id, int vout) { - return id + ":" + vout.toString(); - } - - @override - Future save() async {} - - @override - bool get hasRescan => walletBirthdayBlockHeight() != -1; - - @override - Future rescan({required int height}) async { - // The required height is not used. A birthday time is recorded in the - // mnemonic. As long as not private data is imported into the wallet, we - // can always rescan from there. - var rescanHeight = 0; - if (!watchingOnly) { - rescanHeight = await walletBirthdayBlockHeight(); - // Sync has not yet reached the birthday block. - if (rescanHeight == -1) { - return; - } - } - await _libwallet.rescanFromHeight(walletInfo.name, rescanHeight.toString()); - } - - @override - Future close({bool shouldCleanup = false}) async { - if (syncTimer != null) { - syncTimer!.cancel(); - syncTimer = null; - } - await _libwallet.closeWallet(walletInfo.name); - if (shouldCleanup) { - await _libwallet.shutdown(); - _closeLibwallet(); - } - } - - @override - Future changePassword(String password) async { - if (watchingOnly) { - return; - } - return () async { - await _libwallet.changeWalletPassword(walletInfo.name, _password, password); - }(); - } - - @override - Future updateBalance() async { - final balanceMap = await _libwallet.balance(walletInfo.name); - - var totalFrozen = 0; - - unspentCoinsInfo.values.forEach((info) { - _unspents.forEach((element) { - if (element.hash == info.hash && - element.vout == info.vout && - info.isFrozen && - element.value == info.value) { - totalFrozen += element.value; - } - }); - }); - - balance[CryptoCurrency.dcr] = DecredBalance( - confirmed: balanceMap["confirmed"] ?? 0, - unconfirmed: balanceMap["unconfirmed"] ?? 0, - frozen: totalFrozen, - ); - } - - @override - Future checkNodeHealth() async => await checkSync(); - - @override - void setExceptionHandler(void Function(FlutterErrorDetails) onError) => onError; - - Future renameWalletFiles(String newWalletName) async { - final currentDirPath = await pathForWalletDir(name: walletInfo.name, type: type); - - final newDirPath = await pathForWalletDir(name: newWalletName, type: type); - - if (File(newDirPath).existsSync()) { - throw "wallet already exists at $newDirPath"; - } - - final sourceDir = Directory(currentDirPath); - final targetDir = Directory(newDirPath); - - if (!targetDir.existsSync()) { - await targetDir.create(recursive: true); - } - - await for (final entity in sourceDir.list(recursive: true)) { - final relativePath = entity.path.substring(sourceDir.path.length + 1); - final targetPath = p.join(targetDir.path, relativePath); - - if (entity is File) { - await entity.rename(targetPath); - } else if (entity is Directory) { - await Directory(targetPath).create(recursive: true); - } - } - - await sourceDir.delete(recursive: true); - } - - @override - Future signMessage(String message, {String? address = null}) async { - if (watchingOnly) { - throw "a watching only wallet cannot sign"; - } - var addr = address; - if (addr == null) { - addr = walletAddresses.address; - } - if (addr == "") { - throw "unable to get an address from unsynced wallet"; - } - return await _libwallet.signMessage(walletInfo.name, message, addr, _password); - } - - Future fetchUnspents() async { - try { - final res = await _libwallet.listUnspents(walletInfo.name); - final decoded = json.decode(res); - var unspents = []; - for (final d in decoded) { - final spendable = d["spendable"] ?? false; - if (!spendable) { - continue; - } - final amountDouble = d["amount"] ?? 0.0; - final amount = (amountDouble * 1e8).round().abs(); - final utxo = Unspent(d["address"] ?? "", d["txid"] ?? "", amount, d["vout"] ?? 0, null); - utxo.isChange = d["ischange"] ?? false; - unspents.add(utxo); - } - _unspents = unspents; - } catch (e) { - printV(e); - } - } - - List unspents() { - this.updateUnspents(_unspents); - return _unspents; - } - - void updateUnspents(List unspentCoins) { - if (this.unspentCoinsInfo.isEmpty) { - unspentCoins.forEach((coin) => this.addCoinInfo(coin)); - return; - } - - if (unspentCoins.isEmpty) { - this.unspentCoinsInfo.clear(); - return; - } - - final walletID = idPrefix + walletInfo.name; - if (unspentCoins.isNotEmpty) { - unspentCoins.forEach((coin) { - final coinInfoList = this.unspentCoinsInfo.values.where((element) => - element.walletId == walletID && element.hash == coin.hash && element.vout == coin.vout); - - if (coinInfoList.isEmpty) { - this.addCoinInfo(coin); - } else { - final coinInfo = coinInfoList.first; - - coin.isFrozen = coinInfo.isFrozen; - coin.isSending = coinInfo.isSending; - coin.note = coinInfo.note; - } - }); - } - - final List keys = []; - this.unspentCoinsInfo.values.forEach((element) { - final existUnspentCoins = unspentCoins.where((coin) => element.hash.contains(coin.hash)); - - if (existUnspentCoins.isEmpty) { - keys.add(element.key); - } - }); - - if (keys.isNotEmpty) { - unspentCoinsInfo.deleteAll(keys); - } - } - - void addCoinInfo(Unspent coin) { - final newInfo = UnspentCoinsInfo( - walletId: idPrefix + walletInfo.name, - hash: coin.hash, - isFrozen: false, - isSending: coin.isSending, - noteRaw: "", - address: coin.address, - value: coin.value, - vout: coin.vout, - isChange: coin.isChange, - keyImage: coin.keyImage, - ); - - unspentCoinsInfo.add(newInfo); - } - - // walletBirthdayBlockHeight checks if the wallet birthday is set and returns - // it. Returns -1 if not. - Future walletBirthdayBlockHeight() async { - try { - final res = await _libwallet.birthState(walletInfo.name); - final decoded = json.decode(res); - // Having these values set indicates that sync has not reached the birthday - // yet, so no birthday is set. - if (decoded["setfromheight"] == true || decoded["setfromtime"] == true) { - return -1; - } - return decoded["height"] ?? 0; - } on FormatException catch (_) { - return 0; - } - } - - Future verifyMessage(String message, String signature, {String? address = null}) async { - var addr = address; - if (addr == null) { - throw "an address is required to verify message"; - } - return () async { - final verified = await _libwallet.verifyMessage(walletInfo.name, message, addr, signature); - if (verified == "true") { - return true; - } - return false; - }(); - } - - @override - String get password => _password; - - @override - bool canSend() => seed != null; -} diff --git a/cw_decred/lib/wallet_addresses.dart b/cw_decred/lib/wallet_addresses.dart deleted file mode 100644 index 7bdff8e7..00000000 --- a/cw_decred/lib/wallet_addresses.dart +++ /dev/null @@ -1,153 +0,0 @@ -import 'dart:convert'; -import 'package:cw_core/payment_uris.dart'; -import 'package:cw_core/receive_page_option.dart'; -import 'package:cw_core/utils/print_verbose.dart'; -import 'package:mobx/mobx.dart'; - -import 'package:cw_core/wallet_addresses.dart'; -import 'package:cw_core/wallet_info.dart'; -import 'package:cw_decred/api/libdcrwallet.dart'; - -part 'wallet_addresses.g.dart'; - -class DecredWalletAddresses = DecredWalletAddressesBase with _$DecredWalletAddresses; - -abstract class DecredWalletAddressesBase extends WalletAddresses with Store { - DecredWalletAddressesBase(super.walletInfo, this._libwallet, super.isTestnet); - - final Libwallet _libwallet; - String _currentAddr = ''; - - @observable - bool isEnabledAutoGenerateSubaddress = true; - - @observable - String selectedAddr = ''; - - @override - @computed - String get address => selectedAddr; - - @override - set address(value) => selectedAddr = value; - - @override - Future init() async { - addressesMap = await walletInfo.getAddresses(); - addressInfos = await walletInfo.getAddressInfos(); - usedAddresses = await walletInfo.getUsedAddresses(); - manualAddresses = await walletInfo.getManualAddresses(); - hiddenAddresses = await walletInfo.getHiddenAddresses(); - await updateAddressesInBox(); - } - - @override - Future updateAddressesInBox() async { - final addrs = await _libAddresses(); - final allAddrs = List.from(addrs.usedAddrs)..addAll(addrs.unusedAddrs); - - // Add all addresses. - allAddrs.forEach((addr) { - if (addressesMap.containsKey(addr)) return; - - addressesMap[addr] = ""; - addressInfos[0] ??= []; - addressInfos[0]?.add( - WalletInfoAddressInfo( - walletInfoId: walletInfo.internalId, - mapKey: 0, - address: addr, - label: "", - accountIndex: 0, - ), - ); - }); - - // Add used addresses. - addrs.usedAddrs.forEach((addr) { - if (!usedAddresses.contains(addr)) usedAddresses.add(addr); - }); - - if (addrs.unusedAddrs.length > 0 && addrs.unusedAddrs[0] != _currentAddr) { - _currentAddr = addrs.unusedAddrs[0]; - selectedAddr = _currentAddr; - } - - await saveAddressesInBox(); - } - - List getAddressInfos() { - if (addressInfos.containsKey(0)) return addressInfos[0]!; - - return []; - } - - Future updateAddress(String address, String label) async { - if (!addressInfos.containsKey(0)) return; - - addressInfos[0]!.forEach((info) { - if (info.address == address) info.label = label; - }); - await saveAddressesInBox(); - } - - Future<_LibAddresses> _libAddresses() async { - final nUsed = "10"; - var nUnused = "1"; - if (this.isEnabledAutoGenerateSubaddress) nUnused = "3"; - - try { - final res = await _libwallet.addresses(walletInfo.name, nUsed, nUnused); - final decoded = json.decode(res); - final usedAddrs = List.from(decoded["used"] ?? []); - final unusedAddrs = List.from(decoded["unused"] ?? []); - // index is the index of the first unused address. - final index = decoded["index"] ?? 0; - return _LibAddresses(usedAddrs, unusedAddrs, index); - } catch (e) { - printV(e); - return _LibAddresses([], [], 0); - } - } - - Future generateNewAddress(String label) async { - // NOTE: This will ignore the gap limit and may cause problems when restoring from seed if too - // many addresses are taken and not used. - final addr = await _libwallet.newExternalAddress(walletInfo.name) ?? ''; - if (addr == "") return; - - if (!addressesMap.containsKey(addr)) { - addressesMap[addr] = ""; - addressInfos[0] ??= []; - addressInfos[0]?.add( - WalletInfoAddressInfo( - walletInfoId: walletInfo.internalId, - mapKey: 0, - address: addr, - label: label, - accountIndex: 0, - ), - ); - } - selectedAddr = addr; - await saveAddressesInBox(); - } - - @override - List get receivePageOptions => isTestnet - ? [ - ReceivePageOption.testnet, - ...ReceivePageOptions.where((element) => element != ReceivePageOption.mainnet) - ] - : ReceivePageOptions; - - @override - PaymentURI getPaymentUri(String amount) => DecredURI(address: address, amount: amount); -} - -class _LibAddresses { - final List usedAddrs, unusedAddrs; - final int firstUnusedAddrIndex; - - _LibAddresses(this.usedAddrs, this.unusedAddrs, this.firstUnusedAddrIndex); -} diff --git a/cw_decred/lib/wallet_creation_credentials.dart b/cw_decred/lib/wallet_creation_credentials.dart deleted file mode 100644 index ca045144..00000000 --- a/cw_decred/lib/wallet_creation_credentials.dart +++ /dev/null @@ -1,40 +0,0 @@ -import 'package:cw_core/wallet_credentials.dart'; -import 'package:cw_core/wallet_info.dart'; -import 'package:cw_core/hardware/hardware_account_data.dart'; - -class DecredNewWalletCredentials extends WalletCredentials { - DecredNewWalletCredentials({required String name, WalletInfo? walletInfo}) - : super(name: name, walletInfo: walletInfo); -} - -class DecredRestoreWalletFromSeedCredentials extends WalletCredentials { - DecredRestoreWalletFromSeedCredentials( - {required String name, - required String password, - required this.mnemonic, - WalletInfo? walletInfo}) - : super(name: name, password: password, walletInfo: walletInfo); - - final String mnemonic; -} - -class DecredRestoreWalletFromPubkeyCredentials extends WalletCredentials { - DecredRestoreWalletFromPubkeyCredentials( - {required String name, - required String password, - required String this.pubkey, - WalletInfo? walletInfo}) - : super(name: name, password: password, walletInfo: walletInfo); - - final String pubkey; -} - -class DecredRestoreWalletFromHardwareCredentials extends WalletCredentials { - DecredRestoreWalletFromHardwareCredentials( - {required String name, required this.hwAccountData, WalletInfo? walletInfo}) - : t = throw UnimplementedError(), - super(name: name, walletInfo: walletInfo); - - final HardwareAccountData hwAccountData; - final void t; -} diff --git a/cw_decred/lib/wallet_service.dart b/cw_decred/lib/wallet_service.dart deleted file mode 100644 index afcf6d5d..00000000 --- a/cw_decred/lib/wallet_service.dart +++ /dev/null @@ -1,261 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; -import 'package:cw_decred/api/libdcrwallet.dart'; -import 'package:cw_decred/wallet_creation_credentials.dart'; -import 'package:cw_decred/wallet.dart'; -import 'package:cw_core/wallet_base.dart'; -import 'package:cw_core/wallet_service.dart'; -import 'package:cw_core/pathForWallet.dart'; -import 'package:cw_core/wallet_info.dart'; -import 'package:cw_core/wallet_type.dart'; -import 'package:path/path.dart'; -import 'package:hive/hive.dart'; -import 'package:collection/collection.dart'; -import 'package:cw_core/unspent_coins_info.dart'; - -class DecredWalletService extends WalletService< - DecredNewWalletCredentials, - DecredRestoreWalletFromSeedCredentials, - DecredRestoreWalletFromPubkeyCredentials, - DecredRestoreWalletFromHardwareCredentials> { - DecredWalletService(this.unspentCoinsInfoSource); - - final Box unspentCoinsInfoSource; - final seedRestorePath = "m/44'/42'"; - static final seedRestorePathTestnet = "m/44'/1'"; - static final pubkeyRestorePath = "m/44'/42'/0'"; - static final pubkeyRestorePathTestnet = "m/44'/1'/0'"; - final mainnet = "mainnet"; - final testnet = "testnet"; - static Libwallet? libwallet; - - Future init() async { - if (libwallet != null) { - return; - } - libwallet = await Libwallet.spawn(); - // Init logging with no directory to force printing to stdout and only - // print ERROR level logs. - libwallet!.initLibdcrwallet("", "err"); - } - - void closeLibwallet() { - if (libwallet == null) { - return; - } - libwallet!.close(); - libwallet = null; - } - - @override - WalletType getType() => WalletType.decred; - - @override - Future isWalletExit(String name) async => - File(await pathForWallet(name: name, type: getType())).existsSync(); - - @override - Future create(DecredNewWalletCredentials credentials, {bool? isTestnet}) async { - await this.init(); - final dirPath = await pathForWalletDir(name: credentials.walletInfo!.name, type: getType()); - final network = isTestnet == true ? testnet : mainnet; - final config = { - "name": credentials.walletInfo!.name, - "datadir": dirPath, - "pass": credentials.password!, - "net": network, - "unsyncedaddrs": true, - }; - await libwallet!.createWallet(jsonEncode(config)); - final di = await credentials.walletInfo!.getDerivationInfo(); - di.derivationPath = isTestnet == true ? seedRestorePathTestnet : seedRestorePath; - await di.save(); - credentials.walletInfo!.save(); - credentials.walletInfo!.network = network; - // ios will move our wallet directory when updating. Since we must - // recalculate the new path every time we open the wallet, ensure this path - // is not used. An older wallet will have a directory here which is a - // condition for moving the wallet when opening, so this must be kept blank - // going forward. - credentials.walletInfo!.dirPath = ""; - credentials.walletInfo!.path = ""; - final wallet = DecredWallet(credentials.walletInfo!, di, credentials.password!, - this.unspentCoinsInfoSource, libwallet!, closeLibwallet); - await wallet.init(); - return wallet; - } - - void copyDirectorySync(Directory source, Directory destination) { - /// create destination folder if not exist - if (!destination.existsSync()) { - destination.createSync(recursive: true); - } - - /// get all files from source (recursive: false is important here) - source.listSync(recursive: false).forEach((entity) { - final newPath = destination.path + Platform.pathSeparator + basename(entity.path); - if (entity is File) { - entity.rename(newPath); - } else if (entity is Directory) { - copyDirectorySync(entity, Directory(newPath)); - } - }); - } - - Future moveWallet(String fromPath, String toPath) async { - final oldWalletDir = new Directory(fromPath); - final newWalletDir = new Directory(toPath); - copyDirectorySync(oldWalletDir, newWalletDir); - // It would be ideal to delete the old directory here, but ios will error - // sometimes with "OS Error: No such file or directory, errno = 2" even - // after checking if it exists. - } - - @override - Future openWallet(String name, String password) async { - final walletInfo = await WalletInfo.get(name, getType()); - if (walletInfo == null) { - throw Exception('Wallet not found'); - } - final di = await walletInfo.getDerivationInfo(); - if (walletInfo.network == null || walletInfo.network == "") { - walletInfo.network = di.derivationPath == seedRestorePathTestnet || - di.derivationPath == pubkeyRestorePathTestnet - ? testnet - : mainnet; - walletInfo.save(); - } - - await this.init(); - - // Cake wallet version 4.27.0 and earlier gave a wallet dir that did not - // match the name. Move those to the correct place. - final dirPath = await pathForWalletDir(name: name, type: getType()); - if (walletInfo.path != "") { - // On ios the stored dir no longer exists. We can only trust the basename. - // dirPath may already be updated and lost the basename, so look at path. - final randomBasename = basename(walletInfo.path); - final oldDir = await pathForWalletDir(name: randomBasename, type: getType()); - if (oldDir != dirPath) { - await this.moveWallet(oldDir, dirPath); - } - // Clear the path so this does not trigger again. - walletInfo.dirPath = ""; - walletInfo.path = ""; - await walletInfo.save(); - } - - final config = { - "name": name, - "datadir": dirPath, - "net": walletInfo.network, - "unsyncedaddrs": true, - }; - await libwallet!.loadWallet(jsonEncode(config)); - final wallet = - DecredWallet(walletInfo, di, password, this.unspentCoinsInfoSource, libwallet!, closeLibwallet); - await wallet.init(); - return wallet; - } - - @override - Future remove(String wallet) async { - File(await pathForWalletDir(name: wallet, type: getType())).delete(recursive: true); - final walletInfo = await WalletInfo.get(wallet, getType()); - if (walletInfo == null) { - throw Exception('Wallet not found'); - } - await WalletInfo.delete(walletInfo); - } - - @override - Future rename(String currentName, String password, String newName) async { - final currentWalletInfo = await WalletInfo.get(currentName, getType()); - if (currentWalletInfo == null) { - throw Exception('Wallet not found'); - } - final di = await currentWalletInfo.getDerivationInfo(); - final network = di.derivationPath == seedRestorePathTestnet || - di.derivationPath == pubkeyRestorePathTestnet - ? testnet - : mainnet; - currentWalletInfo.network = network; - currentWalletInfo.save(); - if (libwallet == null) { - libwallet = await Libwallet.spawn(); - libwallet!.initLibdcrwallet("", "err"); - } - final currentWallet = DecredWallet( - currentWalletInfo, di, password, this.unspentCoinsInfoSource, libwallet!, closeLibwallet); - - await currentWallet.renameWalletFiles(newName); - - final newWalletInfo = currentWalletInfo; - newWalletInfo.id = WalletBase.idFor(newName, getType()); - newWalletInfo.name = newName; - newWalletInfo.dirPath = ""; - newWalletInfo.path = ""; - - await newWalletInfo.save(); - } - - @override - Future restoreFromSeed(DecredRestoreWalletFromSeedCredentials credentials, - {bool? isTestnet}) async { - await this.init(); - final network = isTestnet == true ? testnet : mainnet; - final dirPath = await pathForWalletDir(name: credentials.walletInfo!.name, type: getType()); - final config = { - "name": credentials.walletInfo!.name, - "datadir": dirPath, - "pass": credentials.password!, - "mnemonic": credentials.mnemonic, - "net": network, - "unsyncedaddrs": true, - }; - await libwallet!.createWallet(jsonEncode(config)); - final di = await credentials.walletInfo!.getDerivationInfo(); - di.derivationPath = isTestnet == true ? seedRestorePathTestnet : seedRestorePath; - await di.save(); - credentials.walletInfo!.network = network; - credentials.walletInfo!.dirPath = ""; - credentials.walletInfo!.path = ""; - final wallet = DecredWallet(credentials.walletInfo!, di, credentials.password!, - this.unspentCoinsInfoSource, libwallet!, closeLibwallet); - await wallet.init(); - return wallet; - } - - // restoreFromKeys only supports restoring a watch only wallet from an account - // pubkey. - @override - Future restoreFromKeys(DecredRestoreWalletFromPubkeyCredentials credentials, - {bool? isTestnet}) async { - await this.init(); - final network = isTestnet == true ? testnet : mainnet; - final dirPath = await pathForWalletDir(name: credentials.walletInfo!.name, type: getType()); - final config = { - "name": credentials.walletInfo!.name, - "datadir": dirPath, - "pubkey": credentials.pubkey, - "net": network, - "unsyncedaddrs": true, - }; - await libwallet!.createWatchOnlyWallet(jsonEncode(config)); - final di = await credentials.walletInfo!.getDerivationInfo(); - di.derivationPath = isTestnet == true ? pubkeyRestorePathTestnet : pubkeyRestorePath; - await di.save(); - credentials.walletInfo!.network = network; - credentials.walletInfo!.dirPath = ""; - credentials.walletInfo!.path = ""; - final wallet = DecredWallet(credentials.walletInfo!, di, credentials.password!, - this.unspentCoinsInfoSource, libwallet!, closeLibwallet); - await wallet.init(); - return wallet; - } - - @override - Future restoreFromHardwareWallet( - DecredRestoreWalletFromHardwareCredentials credentials) async => - throw UnimplementedError(); -} diff --git a/cw_decred/macos/Classes/CwDecredPlugin.swift b/cw_decred/macos/Classes/CwDecredPlugin.swift deleted file mode 100644 index 72dae36f..00000000 --- a/cw_decred/macos/Classes/CwDecredPlugin.swift +++ /dev/null @@ -1,19 +0,0 @@ -import Cocoa -import FlutterMacOS - -public class CwDecredPlugin: NSObject, FlutterPlugin { - public static func register(with registrar: FlutterPluginRegistrar) { - let channel = FlutterMethodChannel(name: "cw_decred", binaryMessenger: registrar.messenger) - let instance = CwDecredPlugin() - registrar.addMethodCallDelegate(instance, channel: channel) - } - - public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - switch call.method { - case "getPlatformVersion": - result("macOS " + ProcessInfo.processInfo.operatingSystemVersionString) - default: - result(FlutterMethodNotImplemented) - } - } -} diff --git a/cw_decred/macos/cw_decred.podspec b/cw_decred/macos/cw_decred.podspec deleted file mode 100644 index 87d82f23..00000000 --- a/cw_decred/macos/cw_decred.podspec +++ /dev/null @@ -1,22 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. -# Run `pod lib lint cw_decred.podspec` to validate before publishing. -# -Pod::Spec.new do |s| - s.name = 'cw_decred' - s.version = '0.0.1' - s.summary = 'Cake Wallet Decred' - s.description = 'Cake Wallet wrapper over Decred project' - s.homepage = 'http://cakewallet.com' - s.license = { :file => '../LICENSE' } - s.author = { 'Cake Wallet' => 'support@cakewallet.com' } - - s.source = { :path => '.' } - s.source_files = 'Classes/**/*' - s.dependency 'FlutterMacOS' - - s.platform = :osx, '10.11' - s.vendored_libraries = 'External/lib/libdcrwallet.a' - s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', "OTHER_LDFLAGS" => "-force_load $(PODS_TARGET_SRCROOT)/External/lib/libdcrwallet.a -lstdc++" } - s.swift_version = '5.0' -end diff --git a/cw_decred/pubspec.lock b/cw_decred/pubspec.lock deleted file mode 100644 index 6600652b..00000000 --- a/cw_decred/pubspec.lock +++ /dev/null @@ -1,950 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - _fe_analyzer_shared: - dependency: transitive - description: - name: _fe_analyzer_shared - sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab" - url: "https://pub.dev" - source: hosted - version: "76.0.0" - _macros: - dependency: transitive - description: dart - source: sdk - version: "0.3.3" - analyzer: - dependency: transitive - description: - name: analyzer - sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e" - url: "https://pub.dev" - source: hosted - version: "6.11.0" - args: - dependency: transitive - description: - name: args - sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6 - url: "https://pub.dev" - source: hosted - version: "2.6.0" - asn1lib: - dependency: transitive - description: - name: asn1lib - sha256: "4bae5ae63e6d6dd17c4aac8086f3dec26c0236f6a0f03416c6c19d830c367cf5" - url: "https://pub.dev" - source: hosted - version: "1.5.8" - async: - dependency: transitive - description: - name: async - sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" - url: "https://pub.dev" - source: hosted - version: "2.13.0" - bech32: - dependency: transitive - description: - path: "." - ref: HEAD - resolved-ref: "05755063b593aa6cca0a4820a318e0ce17de6192" - url: "https://github.com/cake-tech/bech32.git" - source: git - version: "0.2.2" - blockchain_utils: - dependency: transitive - description: - path: "." - ref: cake-update-v2 - resolved-ref: "59fdf29d72068e0522a96a8953ed7272833a9f57" - url: "https://github.com/cake-tech/blockchain_utils" - source: git - version: "3.3.0" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - build: - dependency: transitive - description: - name: build - sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - build_config: - dependency: transitive - description: - name: build_config - sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 - url: "https://pub.dev" - source: hosted - version: "1.1.1" - build_daemon: - dependency: transitive - description: - name: build_daemon - sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9" - url: "https://pub.dev" - source: hosted - version: "4.0.2" - build_resolvers: - dependency: "direct dev" - description: - name: build_resolvers - sha256: b9e4fda21d846e192628e7a4f6deda6888c36b5b69ba02ff291a01fd529140f0 - url: "https://pub.dev" - source: hosted - version: "2.4.4" - build_runner: - dependency: "direct dev" - description: - name: build_runner - sha256: "058fe9dce1de7d69c4b84fada934df3e0153dd000758c4d65964d0166779aa99" - url: "https://pub.dev" - source: hosted - version: "2.4.15" - build_runner_core: - dependency: transitive - description: - name: build_runner_core - sha256: "22e3aa1c80e0ada3722fe5b63fd43d9c8990759d0a2cf489c8c5d7b2bdebc021" - url: "https://pub.dev" - source: hosted - version: "8.0.0" - built_collection: - dependency: transitive - description: - name: built_collection - sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" - url: "https://pub.dev" - source: hosted - version: "5.1.1" - built_value: - dependency: transitive - description: - name: built_value - sha256: ea90e81dc4a25a043d9bee692d20ed6d1c4a1662a28c03a96417446c093ed6b4 - url: "https://pub.dev" - source: hosted - version: "8.9.5" - cake_backup: - dependency: transitive - description: - path: "." - ref: main - resolved-ref: "3aba867dcab6737f6707782f5db15d71f303db38" - url: "https://github.com/cake-tech/cake_backup.git" - source: git - version: "1.0.0+1" - characters: - dependency: transitive - description: - name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 - url: "https://pub.dev" - source: hosted - version: "1.4.0" - checked_yaml: - dependency: transitive - description: - name: checked_yaml - sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff - url: "https://pub.dev" - source: hosted - version: "2.0.3" - cli_util: - dependency: transitive - description: - name: cli_util - sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c - url: "https://pub.dev" - source: hosted - version: "0.4.2" - clock: - dependency: transitive - description: - name: clock - sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b - url: "https://pub.dev" - source: hosted - version: "1.1.2" - code_builder: - dependency: transitive - description: - name: code_builder - sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e" - url: "https://pub.dev" - source: hosted - version: "4.10.1" - collection: - dependency: transitive - description: - name: collection - sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" - url: "https://pub.dev" - source: hosted - version: "1.19.1" - convert: - dependency: transitive - description: - name: convert - sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 - url: "https://pub.dev" - source: hosted - version: "3.1.2" - crypto: - dependency: transitive - description: - name: crypto - sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" - url: "https://pub.dev" - source: hosted - version: "3.0.6" - cryptography: - dependency: transitive - description: - name: cryptography - sha256: d146b76d33d94548cf035233fbc2f4338c1242fa119013bead807d033fc4ae05 - url: "https://pub.dev" - source: hosted - version: "2.7.0" - cupertino_icons: - dependency: transitive - description: - name: cupertino_icons - sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 - url: "https://pub.dev" - source: hosted - version: "1.0.8" - cw_core: - dependency: "direct main" - description: - path: "../cw_core" - relative: true - source: path - version: "0.0.1" - dart_style: - dependency: transitive - description: - name: dart_style - sha256: "7856d364b589d1f08986e140938578ed36ed948581fbc3bc9aef1805039ac5ab" - url: "https://pub.dev" - source: hosted - version: "2.3.7" - decimal: - dependency: transitive - description: - name: decimal - sha256: "24a261d5d5c87e86c7651c417a5dbdf8bcd7080dd592533910e8d0505a279f21" - url: "https://pub.dev" - source: hosted - version: "2.3.3" - encrypt: - dependency: transitive - description: - name: encrypt - sha256: "62d9aa4670cc2a8798bab89b39fc71b6dfbacf615de6cf5001fb39f7e4a996a2" - url: "https://pub.dev" - source: hosted - version: "5.0.3" - fake_async: - dependency: transitive - description: - name: fake_async - sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" - url: "https://pub.dev" - source: hosted - version: "1.3.3" - ffi: - dependency: transitive - description: - name: ffi - sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" - url: "https://pub.dev" - source: hosted - version: "2.1.3" - ffigen: - dependency: "direct dev" - description: - name: ffigen - sha256: "2119b4fe3aad0db94dc9531b90283c4640a6231070e613c400b426a4da08c704" - url: "https://pub.dev" - source: hosted - version: "16.1.0" - file: - dependency: transitive - description: - name: file - sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 - url: "https://pub.dev" - source: hosted - version: "7.0.1" - fixnum: - dependency: transitive - description: - name: fixnum - sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be - url: "https://pub.dev" - source: hosted - version: "1.1.1" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_mobx: - dependency: transitive - description: - name: flutter_mobx - sha256: ba5e93467866a2991259dc51cffd41ef45f695c667c2b8e7b087bf24118b50fe - url: "https://pub.dev" - source: hosted - version: "2.3.0" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - frontend_server_client: - dependency: transitive - description: - name: frontend_server_client - sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 - url: "https://pub.dev" - source: hosted - version: "4.0.0" - glob: - dependency: transitive - description: - name: glob - sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de - url: "https://pub.dev" - source: hosted - version: "2.1.3" - graphs: - dependency: transitive - description: - name: graphs - sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" - url: "https://pub.dev" - source: hosted - version: "2.3.2" - hive: - dependency: transitive - description: - name: hive - sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941" - url: "https://pub.dev" - source: hosted - version: "2.2.3" - hive_generator: - dependency: "direct dev" - description: - name: hive_generator - sha256: "06cb8f58ace74de61f63500564931f9505368f45f98958bd7a6c35ba24159db4" - url: "https://pub.dev" - source: hosted - version: "2.0.1" - http: - dependency: transitive - description: - name: http - sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f - url: "https://pub.dev" - source: hosted - version: "1.3.0" - http_multi_server: - dependency: transitive - description: - name: http_multi_server - sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8 - url: "https://pub.dev" - source: hosted - version: "3.2.2" - http_parser: - dependency: transitive - description: - name: http_parser - sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" - url: "https://pub.dev" - source: hosted - version: "4.0.2" - intl: - dependency: transitive - description: - name: intl - sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf - url: "https://pub.dev" - source: hosted - version: "0.19.0" - io: - dependency: transitive - description: - name: io - sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b - url: "https://pub.dev" - source: hosted - version: "1.0.5" - js: - dependency: transitive - description: - name: js - sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 - url: "https://pub.dev" - source: hosted - version: "0.6.7" - json_annotation: - dependency: transitive - description: - name: json_annotation - sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" - url: "https://pub.dev" - source: hosted - version: "4.9.0" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" - url: "https://pub.dev" - source: hosted - version: "10.0.9" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 - url: "https://pub.dev" - source: hosted - version: "3.0.9" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" - url: "https://pub.dev" - source: hosted - version: "3.0.1" - logging: - dependency: transitive - description: - name: logging - sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 - url: "https://pub.dev" - source: hosted - version: "1.3.0" - macros: - dependency: transitive - description: - name: macros - sha256: "1d9e801cd66f7ea3663c45fc708450db1fa57f988142c64289142c9b7ee80656" - url: "https://pub.dev" - source: hosted - version: "0.1.3-main.0" - matcher: - dependency: transitive - description: - name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 - url: "https://pub.dev" - source: hosted - version: "0.12.17" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec - url: "https://pub.dev" - source: hosted - version: "0.11.1" - meta: - dependency: transitive - description: - name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c - url: "https://pub.dev" - source: hosted - version: "1.16.0" - mime: - dependency: transitive - description: - name: mime - sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" - url: "https://pub.dev" - source: hosted - version: "2.0.0" - mobx: - dependency: transitive - description: - name: mobx - sha256: bf1a90e5bcfd2851fc6984e20eef69557c65d9e4d0a88f5be4cf72c9819ce6b0 - url: "https://pub.dev" - source: hosted - version: "2.5.0" - mobx_codegen: - dependency: "direct dev" - description: - name: mobx_codegen - sha256: "990da80722f7d7c0017dec92040b31545d625b15d40204c36a1e63d167c73cdc" - url: "https://pub.dev" - source: hosted - version: "2.7.0" - nested: - dependency: transitive - description: - name: nested - sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" - url: "https://pub.dev" - source: hosted - version: "1.0.0" - on_chain: - dependency: transitive - description: - path: "." - ref: "096865a8c6b89c260beadfec04f7e184c40a3273" - resolved-ref: "096865a8c6b89c260beadfec04f7e184c40a3273" - url: "https://github.com/cake-tech/on_chain.git" - source: git - version: "3.7.0" - package_config: - dependency: transitive - description: - name: package_config - sha256: "92d4488434b520a62570293fbd33bb556c7d49230791c1b4bbd973baf6d2dc67" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - path: - dependency: transitive - description: - name: path - sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" - url: "https://pub.dev" - source: hosted - version: "1.9.1" - path_provider: - dependency: transitive - description: - name: path_provider - sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" - url: "https://pub.dev" - source: hosted - version: "2.1.5" - path_provider_android: - dependency: transitive - description: - name: path_provider_android - sha256: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2" - url: "https://pub.dev" - source: hosted - version: "2.2.15" - path_provider_foundation: - dependency: transitive - description: - name: path_provider_foundation - sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - path_provider_linux: - dependency: transitive - description: - name: path_provider_linux - sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 - url: "https://pub.dev" - source: hosted - version: "2.2.1" - path_provider_platform_interface: - dependency: transitive - description: - name: path_provider_platform_interface - sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - path_provider_windows: - dependency: transitive - description: - name: path_provider_windows - sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 - url: "https://pub.dev" - source: hosted - version: "2.3.0" - platform: - dependency: transitive - description: - name: platform - sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" - url: "https://pub.dev" - source: hosted - version: "3.1.6" - plugin_platform_interface: - dependency: transitive - description: - name: plugin_platform_interface - sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" - url: "https://pub.dev" - source: hosted - version: "2.1.8" - pointycastle: - dependency: transitive - description: - name: pointycastle - sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe" - url: "https://pub.dev" - source: hosted - version: "3.9.1" - pool: - dependency: transitive - description: - name: pool - sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" - url: "https://pub.dev" - source: hosted - version: "1.5.1" - provider: - dependency: transitive - description: - name: provider - sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c - url: "https://pub.dev" - source: hosted - version: "6.1.2" - pub_semver: - dependency: transitive - description: - name: pub_semver - sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" - url: "https://pub.dev" - source: hosted - version: "2.2.0" - pubspec_parse: - dependency: transitive - description: - name: pubspec_parse - sha256: "81876843eb50dc2e1e5b151792c9a985c5ed2536914115ed04e9c8528f6647b0" - url: "https://pub.dev" - source: hosted - version: "1.4.0" - quiver: - dependency: transitive - description: - name: quiver - sha256: ea0b925899e64ecdfbf9c7becb60d5b50e706ade44a85b2363be2a22d88117d2 - url: "https://pub.dev" - source: hosted - version: "3.2.2" - rational: - dependency: transitive - description: - name: rational - sha256: cb808fb6f1a839e6fc5f7d8cb3b0a10e1db48b3be102de73938c627f0b636336 - url: "https://pub.dev" - source: hosted - version: "2.2.3" - shelf: - dependency: transitive - description: - name: shelf - sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 - url: "https://pub.dev" - source: hosted - version: "1.4.1" - shelf_web_socket: - dependency: transitive - description: - name: shelf_web_socket - sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67 - url: "https://pub.dev" - source: hosted - version: "2.0.1" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - socks5_proxy: - dependency: transitive - description: - path: "." - ref: "27ad7c2efae8d7460325c74b90f660085cbd0685" - resolved-ref: "27ad7c2efae8d7460325c74b90f660085cbd0685" - url: "https://github.com/LacticWhale/socks_dart" - source: git - version: "2.1.0" - socks_socket: - dependency: transitive - description: - path: "." - ref: e6232c53c1595469931ababa878759a067c02e94 - resolved-ref: e6232c53c1595469931ababa878759a067c02e94 - url: "https://github.com/sneurlax/socks_socket" - source: git - version: "1.1.1" - source_gen: - dependency: transitive - description: - name: source_gen - sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832" - url: "https://pub.dev" - source: hosted - version: "1.5.0" - source_helper: - dependency: transitive - description: - name: source_helper - sha256: "86d247119aedce8e63f4751bd9626fc9613255935558447569ad42f9f5b48b3c" - url: "https://pub.dev" - source: hosted - version: "1.3.5" - source_span: - dependency: transitive - description: - name: source_span - sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" - url: "https://pub.dev" - source: hosted - version: "1.10.1" - sqflite: - dependency: transitive - description: - name: sqflite - sha256: "2d7299468485dca85efeeadf5d38986909c5eb0cd71fd3db2c2f000e6c9454bb" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - sqflite_android: - dependency: transitive - description: - name: sqflite_android - sha256: "78f489aab276260cdd26676d2169446c7ecd3484bbd5fead4ca14f3ed4dd9ee3" - url: "https://pub.dev" - source: hosted - version: "2.4.0" - sqflite_common: - dependency: transitive - description: - name: sqflite_common - sha256: "761b9740ecbd4d3e66b8916d784e581861fd3c3553eda85e167bc49fdb68f709" - url: "https://pub.dev" - source: hosted - version: "2.5.4+6" - sqflite_common_ffi: - dependency: transitive - description: - name: sqflite_common_ffi - sha256: "883dd810b2b49e6e8c3b980df1829ef550a94e3f87deab5d864917d27ca6bf36" - url: "https://pub.dev" - source: hosted - version: "2.3.4+4" - sqflite_darwin: - dependency: transitive - description: - name: sqflite_darwin - sha256: "22adfd9a2c7d634041e96d6241e6e1c8138ca6817018afc5d443fef91dcefa9c" - url: "https://pub.dev" - source: hosted - version: "2.4.1+1" - sqflite_platform_interface: - dependency: transitive - description: - name: sqflite_platform_interface - sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920" - url: "https://pub.dev" - source: hosted - version: "2.4.0" - sqlite3: - dependency: transitive - description: - name: sqlite3 - sha256: f393d92c71bdcc118d6203d07c991b9be0f84b1a6f89dd4f7eed348131329924 - url: "https://pub.dev" - source: hosted - version: "2.9.0" - sqlite3_flutter_libs: - dependency: transitive - description: - name: sqlite3_flutter_libs - sha256: "69c80d812ef2500202ebd22002cbfc1b6565e9ff56b2f971e757fac5d42294df" - url: "https://pub.dev" - source: hosted - version: "0.5.40" - stack_trace: - dependency: transitive - description: - name: stack_trace - sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" - url: "https://pub.dev" - source: hosted - version: "1.12.1" - stream_channel: - dependency: transitive - description: - name: stream_channel - sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - stream_transform: - dependency: transitive - description: - name: stream_transform - sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 - url: "https://pub.dev" - source: hosted - version: "2.1.1" - string_scanner: - dependency: transitive - description: - name: string_scanner - sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" - url: "https://pub.dev" - source: hosted - version: "1.4.1" - synchronized: - dependency: transitive - description: - name: synchronized - sha256: "69fe30f3a8b04a0be0c15ae6490fc859a78ef4c43ae2dd5e8a623d45bfcf9225" - url: "https://pub.dev" - source: hosted - version: "3.3.0+3" - term_glyph: - dependency: transitive - description: - name: term_glyph - sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" - url: "https://pub.dev" - source: hosted - version: "1.2.2" - test_api: - dependency: transitive - description: - name: test_api - sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd - url: "https://pub.dev" - source: hosted - version: "0.7.4" - timing: - dependency: transitive - description: - name: timing - sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" - url: "https://pub.dev" - source: hosted - version: "1.0.2" - torch_dart: - dependency: transitive - description: - path: "../scripts/torch_dart" - relative: true - source: path - version: "0.0.1" - tuple: - dependency: transitive - description: - name: tuple - sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151 - url: "https://pub.dev" - source: hosted - version: "2.0.2" - typed_data: - dependency: transitive - description: - name: typed_data - sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 - url: "https://pub.dev" - source: hosted - version: "1.4.0" - unorm_dart: - dependency: transitive - description: - name: unorm_dart - sha256: "23d8bf65605401a6a32cff99435fed66ef3dab3ddcad3454059165df46496a3b" - url: "https://pub.dev" - source: hosted - version: "0.3.0" - vector_math: - dependency: transitive - description: - name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 - url: "https://pub.dev" - source: hosted - version: "15.0.0" - watcher: - dependency: transitive - description: - name: watcher - sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104" - url: "https://pub.dev" - source: hosted - version: "1.1.1" - web: - dependency: transitive - description: - name: web - sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" - url: "https://pub.dev" - source: hosted - version: "1.1.1" - web_socket: - dependency: transitive - description: - name: web_socket - sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" - url: "https://pub.dev" - source: hosted - version: "0.1.6" - web_socket_channel: - dependency: transitive - description: - name: web_socket_channel - sha256: "0b8e2457400d8a859b7b2030786835a28a8e80836ef64402abef392ff4f1d0e5" - url: "https://pub.dev" - source: hosted - version: "3.0.2" - xdg_directories: - dependency: transitive - description: - name: xdg_directories - sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - yaml: - dependency: transitive - description: - name: yaml - sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce - url: "https://pub.dev" - source: hosted - version: "3.1.3" - yaml_edit: - dependency: transitive - description: - name: yaml_edit - sha256: fb38626579fb345ad00e674e2af3a5c9b0cc4b9bfb8fd7f7ff322c7c9e62aef5 - url: "https://pub.dev" - source: hosted - version: "2.2.2" -sdks: - dart: ">=3.7.0-0 <4.0.0" - flutter: ">=3.24.0" diff --git a/cw_decred/pubspec.yaml b/cw_decred/pubspec.yaml deleted file mode 100644 index 8cfad6cf..00000000 --- a/cw_decred/pubspec.yaml +++ /dev/null @@ -1,83 +0,0 @@ -name: cw_decred -description: A new Flutter plugin project. -version: 0.0.1 -publish_to: none -author: Hash Wallet -homepage: https://github.com/Such-Software/hash-wallet - -environment: - sdk: ">=3.2.0-0 <4.0.0" - flutter: ">=3.19.0" - -dependencies: - flutter: - sdk: flutter - cw_core: - path: ../cw_core - -dev_dependencies: - flutter_test: - sdk: flutter - build_runner: ^2.4.15 - build_resolvers: ^2.4.4 - mobx_codegen: ^2.0.7 - hive_generator: ^2.0.1 - ffigen: ^16.1.0 - -ffigen: - name: libdcrwallet - description: Bindings for dcrwallet go library. - output: "lib/api/libdcrwallet_bindings.dart" - headers: - entry-points: - - "lib/api/libdcrwallet.h" - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter packages. -flutter: - # This section identifies this Flutter project as a plugin project. - # The androidPackage and pluginClass identifiers should not ordinarily - # be modified. They are used by the tooling to maintain consistency when - # adding or updating assets for this project. - plugin: - platforms: - android: - package: com.cakewallet.cw_decred - pluginClass: CwDecredPlugin - ios: - pluginClass: CwDecredPlugin - macos: - pluginClass: CwDecredPlugin - - # To add assets to your plugin package, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - # - # For details regarding assets in packages, see - # https://flutter.dev/assets-and-images/#from-packages - # - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware - - # To add custom fonts to your plugin package, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts in packages, see - # https://flutter.dev/custom-fonts/#from-packages diff --git a/cw_solana/.gitignore b/cw_solana/.gitignore deleted file mode 100644 index 96486fd9..00000000 --- a/cw_solana/.gitignore +++ /dev/null @@ -1,30 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ -migrate_working_dir/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. -/pubspec.lock -**/doc/api/ -.dart_tool/ -.packages -build/ diff --git a/cw_solana/.metadata b/cw_solana/.metadata deleted file mode 100644 index fa347fc6..00000000 --- a/cw_solana/.metadata +++ /dev/null @@ -1,10 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - channel: stable - -project_type: package diff --git a/cw_solana/CHANGELOG.md b/cw_solana/CHANGELOG.md deleted file mode 100644 index 41cc7d81..00000000 --- a/cw_solana/CHANGELOG.md +++ /dev/null @@ -1,3 +0,0 @@ -## 0.0.1 - -* TODO: Describe initial release. diff --git a/cw_solana/LICENSE b/cw_solana/LICENSE deleted file mode 100644 index ba75c69f..00000000 --- a/cw_solana/LICENSE +++ /dev/null @@ -1 +0,0 @@ -TODO: Add your license here. diff --git a/cw_solana/README.md b/cw_solana/README.md deleted file mode 100644 index 541bee62..00000000 --- a/cw_solana/README.md +++ /dev/null @@ -1,63 +0,0 @@ -## cw_solana - -Solana wallet module for Cake Wallet. Provides native SOL and SPL token support built on `on_chain/solana` with high-throughput RPC usage and safe transaction parsing. - -### Features - -- Connect to Solana RPC (Ankr/Chainstack/custom) via `SolanaRPC` over HTTP. -- Fetch SOL balances and aggregate SPL token balances across accounts. -- Parse and stream native and SPL token transactions (filters ATA-only and spam-like micro txs). -- Estimate fees per compiled message and enforce rent-exemption checks. -- Create/sign/broadcast SOL and SPL transfers; auto-create recipient ATA when necessary. -- Manage SPL tokens; fetch on-chain metadata (symbol/name) for unknown mints. -- Sign and verify messages. -- Node health checks for SOL and a known SPL token (USDC). - -### Getting started - -If you use hosted RPC providers, add a secrets file for keys (optional unless using those hosts): - -```dart -// cw_solana/lib/.secrets.g.dart (DO NOT COMMIT) -const String ankrApiKey = 'YOUR_ANKR_KEY'; -const String chainStackApiKey = 'YOUR_CHAINSTACK_KEY'; -``` - -Connect and sync: - -```dart -final service = SolanaWalletService(walletInfoBox, true); -final wallet = await service.create(SolanaNewWalletCredentials(name: 'My SOL', password: 'secret')); -await wallet.connectToNode(node: Node(uriRaw: 'api.mainnet-beta.solana.com', isSSL: true)); -await wallet.startSync(); -final sol = wallet.balance[CryptoCurrency.sol]?.balance; -``` - -### Usage - -Send SOL: - -```dart -final pending = await wallet.createTransaction( - SolanaTransactionCredentials.single( - address: 'SoL...', - cryptoAmount: '0.05', - currency: CryptoCurrency.sol, - ), -); -final sig = await pending.commit(); -``` - -Add an SPL token by mint: - -```dart -final token = await wallet.getSPLToken('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'); // USDC -if (token != null) { - await wallet.addSPLToken(token); -} -``` - -### Additional information - -- When using `rpc.ankr.com` or `solana-mainnet.core.chainstack.com`, the client reads API keys from `.secrets.g.dart`. -- See `lib/` for APIs: `SolanaWalletClient`, `SolanaWallet`, `SolanaWalletService`, and credential types. diff --git a/cw_solana/analysis_options.yaml b/cw_solana/analysis_options.yaml deleted file mode 100644 index a5744c1c..00000000 --- a/cw_solana/analysis_options.yaml +++ /dev/null @@ -1,4 +0,0 @@ -include: package:flutter_lints/flutter.yaml - -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options diff --git a/cw_solana/lib/cw_solana.dart b/cw_solana/lib/cw_solana.dart deleted file mode 100644 index d04069b3..00000000 --- a/cw_solana/lib/cw_solana.dart +++ /dev/null @@ -1,7 +0,0 @@ -library cw_solana; - -/// A Calculator. -class Calculator { - /// Returns [value] plus 1. - int addOne(int value) => value + 1; -} diff --git a/cw_solana/lib/default_spl_tokens.dart b/cw_solana/lib/default_spl_tokens.dart deleted file mode 100644 index 5643117c..00000000 --- a/cw_solana/lib/default_spl_tokens.dart +++ /dev/null @@ -1,703 +0,0 @@ -import 'package:cw_core/crypto_currency.dart'; -import 'package:cw_core/spl_token.dart'; - -class DefaultSPLTokens { - final List _defaultTokens = [ - SPLToken( - name: 'USDT Tether', - symbol: 'USDT', - mintAddress: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB', - decimal: 6, - mint: 'usdtsol', - enabled: true, - ), - SPLToken( - name: 'USD Coin', - symbol: 'USDC', - mintAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', - decimal: 6, - mint: 'usdcsol', - enabled: true, - ), - SPLToken( - name: 'Bonk', - symbol: 'Bonk', - mintAddress: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263', - decimal: 5, - mint: 'Bonk', - iconPath: 'assets/images/bonk_icon.png', - enabled: false, - ), - SPLToken( - name: 'Raydium', - symbol: 'RAY', - mintAddress: '4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R', - decimal: 6, - mint: 'ray', - iconPath: 'assets/images/ray_icon.png', - enabled: false, - ), - SPLToken( - name: 'Wrapped Ethereum (Sollet)', - symbol: 'soETH', - mintAddress: '2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk', - decimal: 6, - mint: 'soEth', - iconPath: 'assets/new-ui/crypto_full_icons/ethereum.svg', - enabled: false, - ), - SPLToken( - name: 'Wrapped SOL', - symbol: 'WSOL', - mintAddress: 'So11111111111111111111111111111111111111112', - decimal: 9, - mint: 'WSOL', - iconPath: 'assets/new-ui/crypto_full_icons/solana.svg', - enabled: false, - ), - SPLToken( - name: 'Wrapped Bitcoin (Sollet)', - symbol: 'BTC', - mintAddress: '9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E', - decimal: 6, - mint: 'btcsol', - iconPath: 'assets/new-ui/crypto_full_icons/bitcoin.svg', - enabled: false, - ), - SPLToken( - name: 'Helium Network Token', - symbol: 'HNT', - mintAddress: 'hntyVP6YFm1Hg25TN9WGLqM12b8TQmcknKrdu1oxWux', - decimal: 8, - mint: 'hnt', - iconPath: 'assets/images/hnt_icon.png', - enabled: false, - ), - SPLToken( - name: 'Pyth Network', - symbol: 'PYTH', - mintAddress: 'HZ1JovNiVvGrGNiiYvEozEVgZ58xaU3RKwX8eACQBCt3', - decimal: 6, - mint: 'pyth', - enabled: false, - ), - SPLToken( - name: 'GMT', - symbol: 'GMT', - mintAddress: '7i5KKsX2weiTkry7jA4ZwSuXGhs5eJBEjY8vVxR4pfRx', - decimal: 6, - mint: 'ray', - iconPath: 'assets/images/gmt_icon.png', - enabled: false, - ), - SPLToken( - name: 'AvocadoCoin', - symbol: 'AVDO', - mintAddress: 'EE5L8cMU4itTsCSuor7NLK6RZx6JhsBe8GGV3oaAHm3P', - decimal: 8, - mint: 'avdo', - iconPath: 'assets/images/avdo_icon.png', - enabled: false, - ), - SPLToken( - name: "Tether Gold", - symbol: "XAUT0", - mintAddress: "AymATz4TCL9sWNEEV9Kvyz45CHVhDZ6kUgjTJPzLpU9P", - decimal: 6, - mint: 'xaut0', - enabled: false, - iconPath: "assets/images/xau_sol.png", - ), - SPLToken( - name: 'Abbott xStock', - symbol: 'ABTx', - mintAddress: 'XsHtf5RpxsQ7jeJ9ivNewouZKJHbPxhPoEy6yYvULr7', - decimal: 8, - mint: 'abtx', - enabled: false, - iconPath: 'assets/images/stocks/abtx.webp', - ), - SPLToken( - name: 'AbbVie xStock', - symbol: 'ABBVx', - mintAddress: 'XswbinNKyPmzTa5CskMbCPvMW6G5CMnZXZEeQSSQoie', - decimal: 8, - mint: 'abbvx', - enabled: false, - iconPath: 'assets/images/stocks/abbv.webp', - ), - SPLToken( - name: 'Accenture xStock', - symbol: 'ACNx', - mintAddress: 'Xs5UJzmCRQ8DWZjskExdSQDnbE6iLkRu2jjrRAB1JSU', - decimal: 8, - mint: 'acnx', - enabled: false, - iconPath: 'assets/images/stocks/acnx.webp', - ), - SPLToken( - name: 'Alphabet xStock', - symbol: 'GOOGLx', - mintAddress: 'XsCPL9dNWBMvFtTmwcCA5v3xWPSMEBCszbQdiLLq6aN', - decimal: 8, - mint: 'googlx', - enabled: false, - iconPath: 'assets/images/stocks/googlx.webp', - ), - SPLToken( - name: 'Amazon xStock', - symbol: 'AMZNx', - mintAddress: 'Xs3eBt7uRfJX8QUs4suhyU8p2M6DoUDrJyWBa8LLZsg', - decimal: 8, - mint: 'amznx', - enabled: false, - iconPath: 'assets/images/stocks/amznx.webp', - ), - SPLToken( - name: 'Amber xStock', - symbol: 'AMBRx', - mintAddress: 'XsaQTCgebC2KPbf27KUhdv5JFvHhQ4GDAPURwrEhAzb', - decimal: 8, - mint: 'ambrx', - enabled: false, - iconPath: 'assets/images/stocks/ambrx.webp', - ), - SPLToken( - name: 'Apple xStock', - symbol: 'AAPLx', - mintAddress: 'XsbEhLAtcf6HdfpFZ5xEMdqW8nfAvcsP5bdudRLJzJp', - decimal: 8, - mint: 'aaplx', - enabled: false, - iconPath: 'assets/images/stocks/apple.webp', - ), - SPLToken( - name: 'AppLovin xStock', - symbol: 'APPx', - mintAddress: 'XsPdAVBi8Zc1xvv53k4JcMrQaEDTgkGqKYeh7AYgPHV', - decimal: 8, - mint: 'appx', - enabled: false, - iconPath: 'assets/images/stocks/appx.webp', - ), - SPLToken( - name: 'AstraZeneca xStock', - symbol: 'AZNx', - mintAddress: 'Xs3ZFkPYT2BN7qBMqf1j1bfTeTm1rFzEFSsQ1z3wAKU', - decimal: 8, - mint: 'aznx', - enabled: false, - iconPath: 'assets/images/stocks/aznx.webp', - ), - SPLToken( - name: 'Bank of America xStock', - symbol: 'BACx', - mintAddress: 'XswsQk4duEQmCbGzfqUUWYmi7pV7xpJ9eEmLHXCaEQP', - decimal: 8, - mint: 'bacx', - enabled: false, - iconPath: 'assets/images/stocks/bacx.webp', - ), - SPLToken( - name: 'Berkshire Hathaway xStock', - symbol: 'BRK.Bx', - mintAddress: 'Xs6B6zawENwAbWVi7w92rjazLuAr5Az59qgWKcNb45x', - decimal: 8, - mint: 'brkbx', - enabled: false, - iconPath: 'assets/images/stocks/brkbx.webp', - ), - SPLToken( - name: 'Broadcom xStock', - symbol: 'AVGOx', - mintAddress: 'XsgSaSvNSqLTtFuyWPBhK9196Xb9Bbdyjj4fH3cPJGo', - decimal: 8, - mint: 'avgox', - enabled: false, - iconPath: 'assets/images/stocks/avgox.webp', - ), - SPLToken( - name: 'Chevron xStock', - symbol: 'CVXx', - mintAddress: 'XsNNMt7WTNA2sV3jrb1NNfNgapxRF5i4i6GcnTRRHts', - decimal: 8, - mint: 'cvxx', - enabled: false, - iconPath: 'assets/images/stocks/cvxx.webp', - ), - SPLToken( - name: 'Circle xStock', - symbol: 'CRCLx', - mintAddress: 'XsueG8BtpquVJX9LVLLEGuViXUungE6WmK5YZ3p3bd1', - decimal: 8, - mint: 'crclx', - enabled: false, - iconPath: 'assets/images/stocks/crclx.webp', - ), - SPLToken( - name: 'Cisco xStock', - symbol: 'CSCOx', - mintAddress: 'Xsr3pdLQyXvDJBFgpR5nexCEZwXvigb8wbPYp4YoNFf', - decimal: 8, - mint: 'cscx', - enabled: false, - iconPath: 'assets/images/stocks/cscox.webp', - ), - SPLToken( - name: 'Coca-Cola xStock', - symbol: 'KOx', - mintAddress: 'XsaBXg8dU5cPM6ehmVctMkVqoiRG2ZjMo1cyBJ3AykQ', - decimal: 8, - mint: 'kox', - enabled: false, - iconPath: 'assets/images/stocks/kox.webp', - ), - SPLToken( - name: 'Coinbase xStock', - symbol: 'COINx', - mintAddress: 'Xs7ZdzSHLU9ftNJsii5fCeJhoRWSC32SQGzGQtePxNu', - decimal: 8, - mint: 'coinx', - enabled: false, - iconPath: 'assets/images/stocks/coinx.webp', - ), - SPLToken( - name: 'Comcast xStock', - symbol: 'CMCSAx', - mintAddress: 'XsvKCaNsxg2GN8jjUmq71qukMJr7Q1c5R2Mk9P8kcS8', - decimal: 8, - mint: 'cmcsax', - enabled: false, - iconPath: 'assets/images/stocks/cmcsax.webp', - ), - SPLToken( - name: 'CrowdStrike xStock', - symbol: 'CRWDx', - mintAddress: 'Xs7xXqkcK7K8urEqGg52SECi79dRp2cEKKuYjUePYDw', - decimal: 8, - mint: 'crwdx', - enabled: false, - iconPath: 'assets/images/stocks/crwdx.webp', - ), - SPLToken( - name: 'Danaher xStock', - symbol: 'DHRx', - mintAddress: 'Xseo8tgCZfkHxWS9xbFYeKFyMSbWEvZGFV1Gh53GtCV', - decimal: 8, - mint: 'dhrx', - enabled: false, - iconPath: 'assets/images/stocks/dhrx.webp', - ), - SPLToken( - name: 'DFDV xStock', - symbol: 'DFDVx', - mintAddress: 'Xs2yquAgsHByNzx68WJC55WHjHBvG9JsMB7CWjTLyPy', - decimal: 8, - mint: 'dfdvx', - enabled: false, - iconPath: 'assets/images/stocks/dfdvx.webp', - ), - SPLToken( - name: 'Eli Lilly xStock', - symbol: 'LLYx', - mintAddress: 'Xsnuv4omNoHozR6EEW5mXkw8Nrny5rB3jVfLqi6gKMH', - decimal: 8, - mint: 'llyx', - enabled: false, - iconPath: 'assets/images/stocks/llyx.webp', - ), - SPLToken( - name: 'Exxon Mobil xStock', - symbol: 'XOMx', - mintAddress: 'XsaHND8sHyfMfsWPj6kSdd5VwvCayZvjYgKmmcNL5qh', - decimal: 8, - mint: 'xomx', - enabled: false, - iconPath: 'assets/images/stocks/xomx.webp', - ), - SPLToken( - name: 'Gamestop xStock', - symbol: 'GMEx', - mintAddress: 'Xsf9mBktVB9BSU5kf4nHxPq5hCBJ2j2ui3ecFGxPRGc', - decimal: 8, - mint: 'gmex', - enabled: false, - iconPath: 'assets/images/stocks/gmex.webp', - ), - SPLToken( - name: 'Gold xStock', - symbol: 'GLDx', - mintAddress: 'Xsv9hRk1z5ystj9MhnA7Lq4vjSsLwzL2nxrwmwtD3re', - decimal: 8, - mint: 'gldx', - enabled: false, - iconPath: 'assets/images/stocks/gldx.webp', - ), - SPLToken( - name: 'Goldman Sachs xStock', - symbol: 'GSx', - mintAddress: 'XsgaUyp4jd1fNBCxgtTKkW64xnnhQcvgaxzsbAq5ZD1', - decimal: 8, - mint: 'gsx', - enabled: false, - iconPath: 'assets/images/stocks/gsx.webp', - ), - SPLToken( - name: 'Home Depot xStock', - symbol: 'HDx', - mintAddress: 'XszjVtyhowGjSC5odCqBpW1CtXXwXjYokymrk7fGKD3', - decimal: 8, - mint: 'hdx', - enabled: false, - iconPath: 'assets/images/stocks/hdx.webp', - ), - SPLToken( - name: 'Honeywell xStock', - symbol: 'HONx', - mintAddress: 'XsRbLZthfABAPAfumWNEJhPyiKDW6TvDVeAeW7oKqA2', - decimal: 8, - mint: 'honx', - enabled: false, - iconPath: 'assets/images/stocks/honx.webp', - ), - SPLToken( - name: 'Intel xStock', - symbol: 'INTCx', - mintAddress: 'XshPgPdXFRWB8tP1j82rebb2Q9rPgGX37RuqzohmArM', - decimal: 8, - mint: 'intcx', - enabled: false, - iconPath: 'assets/images/stocks/intcx.webp', - ), - SPLToken( - name: 'International Business Machines xStock', - symbol: 'IBMx', - mintAddress: 'XspwhyYPdWVM8XBHZnpS9hgyag9MKjLRyE3tVfmCbSr', - decimal: 8, - mint: 'ibmx', - enabled: false, - iconPath: 'assets/images/stocks/ibmx.webp', - ), - SPLToken( - name: 'Johnson & Johnson xStock', - symbol: 'JNJx', - mintAddress: 'XsGVi5eo1Dh2zUpic4qACcjuWGjNv8GCt3dm5XcX6Dn', - decimal: 8, - mint: 'jnjx', - enabled: false, - iconPath: 'assets/images/stocks/jnjx.webp', - ), - SPLToken( - name: 'JPMorgan Chase xStock', - symbol: 'JPMx', - mintAddress: 'XsMAqkcKsUewDrzVkait4e5u4y8REgtyS7jWgCpLV2C', - decimal: 8, - mint: 'jpmx', - enabled: false, - iconPath: 'assets/images/stocks/jpmx.webp', - ), - SPLToken( - name: 'Linde xStock', - symbol: 'LINx', - mintAddress: 'XsSr8anD1hkvNMu8XQiVcmiaTP7XGvYu7Q58LdmtE8Z', - decimal: 8, - mint: 'linx', - enabled: false, - iconPath: 'assets/images/stocks/linx.webp', - ), - SPLToken( - name: 'Marvell xStock', - symbol: 'MRVLx', - mintAddress: 'XsuxRGDzbLjnJ72v74b7p9VY6N66uYgTCyfwwRjVCJA', - decimal: 8, - mint: 'mrvlx', - enabled: false, - iconPath: 'assets/images/stocks/mrvlx.webp', - ), - SPLToken( - name: 'Mastercard xStock', - symbol: 'MAx', - mintAddress: 'XsApJFV9MAktqnAc6jqzsHVujxkGm9xcSUffaBoYLKC', - decimal: 8, - mint: 'max', - enabled: false, - iconPath: 'assets/images/stocks/mastercard.webp', - ), - SPLToken( - name: 'McDonald\'s xStock', - symbol: 'MCDx', - mintAddress: 'XsqE9cRRpzxcGKDXj1BJ7Xmg4GRhZoyY1KpmGSxAWT2', - decimal: 8, - mint: 'mcdx', - enabled: false, - iconPath: 'assets/images/stocks/mcdonalds.webp', - ), - SPLToken( - name: 'Medtronic xStock', - symbol: 'MDTx', - mintAddress: 'XsDgw22qRLTv5Uwuzn6T63cW69exG41T6gwQhEK22u2', - decimal: 8, - mint: 'mdtx', - enabled: false, - iconPath: 'assets/images/stocks/mdtx.webp', - ), - SPLToken( - name: 'Merck xStock', - symbol: 'MRKx', - mintAddress: 'XsnQnU7AdbRZYe2akqqpibDdXjkieGFfSkbkjX1Sd1X', - decimal: 8, - mint: 'mrkx', - enabled: false, - iconPath: 'assets/images/stocks/mrkx.webp', - ), - SPLToken( - name: 'Meta xStock', - symbol: 'METAx', - mintAddress: 'Xsa62P5mvPszXL1krVUnU5ar38bBSVcWAB6fmPCo5Zu', - decimal: 8, - mint: 'metax', - enabled: false, - iconPath: 'assets/images/stocks/metax.webp', - ), - SPLToken( - name: 'Microsoft xStock', - symbol: 'MSFTx', - mintAddress: 'XspzcW1PRtgf6Wj92HCiZdjzKCyFekVD8P5Ueh3dRMX', - decimal: 8, - mint: 'msftx', - enabled: false, - iconPath: 'assets/images/stocks/msftx.webp', - ), - SPLToken( - name: 'MicroStrategy xStock', - symbol: 'MSTRx', - mintAddress: 'XsP7xzNPvEHS1m6qfanPUGjNmdnmsLKEoNAnHjdxxyZ', - decimal: 8, - mint: 'mstrx', - enabled: false, - iconPath: 'assets/images/stocks/mstrx.webp', - ), - SPLToken( - name: 'Nasdaq xStock', - symbol: 'QQQx', - mintAddress: 'Xs8S1uUs1zvS2p7iwtsG3b6fkhpvmwz4GYU3gWAmWHZ', - decimal: 8, - mint: 'qqqx', - enabled: false, - iconPath: 'assets/images/stocks/qqqx.webp', - ), - SPLToken( - name: 'Netflix xStock', - symbol: 'NFLXx', - mintAddress: 'XsEH7wWfJJu2ZT3UCFeVfALnVA6CP5ur7Ee11KmzVpL', - decimal: 8, - mint: 'nflxx', - enabled: false, - iconPath: 'assets/images/stocks/nflxx.webp', - ), - SPLToken( - name: 'Novo Nordisk xStock', - symbol: 'NVOx', - mintAddress: 'XsfAzPzYrYjd4Dpa9BU3cusBsvWfVB9gBcyGC87S57n', - decimal: 8, - mint: 'nvox', - enabled: false, - iconPath: 'assets/images/stocks/nvox.webp', - ), - SPLToken( - name: 'NVIDIA xStock', - symbol: 'NVDAx', - mintAddress: 'Xsc9qvGR1efVDFGLrVsmkzv3qi45LTBjeUKSPmx9qEh', - decimal: 8, - mint: 'nvdax', - enabled: false, - iconPath: 'assets/images/stocks/nvdax.webp', - ), - SPLToken( - name: 'OPEN xStock', - symbol: 'OPENx', - mintAddress: 'XsGtpmjhmC8kyjVSWL4VicGu36ceq9u55PTgF8bhGv6', - decimal: 8, - mint: 'openx', - enabled: false, - iconPath: 'assets/images/stocks/openx.webp', - ), - SPLToken( - name: 'Oracle xStock', - symbol: 'ORCLx', - mintAddress: 'XsjFwUPiLofddX5cWFHW35GCbXcSu1BCUGfxoQAQjeL', - decimal: 8, - mint: 'orclx', - enabled: false, - iconPath: 'assets/images/stocks/orclx.webp', - ), - SPLToken( - name: 'Palantir xStock', - symbol: 'PLTRx', - mintAddress: 'XsoBhf2ufR8fTyNSjqfU71DYGaE6Z3SUGAidpzriAA4', - decimal: 8, - mint: 'pltrx', - enabled: false, - iconPath: 'assets/images/stocks/pltrx.webp', - ), - SPLToken( - name: 'PepsiCo xStock', - symbol: 'PEPx', - mintAddress: 'Xsv99frTRUeornyvCfvhnDesQDWuvns1M852Pez91vF', - decimal: 8, - mint: 'pepx', - enabled: false, - iconPath: 'assets/images/stocks/pepx.webp', - ), - SPLToken( - name: 'Pfizer xStock', - symbol: 'PFEx', - mintAddress: 'XsAtbqkAP1HJxy7hFDeq7ok6yM43DQ9mQ1Rh861X8rw', - decimal: 8, - mint: 'pfex', - enabled: false, - iconPath: 'assets/images/stocks/pfex.webp', - ), - SPLToken( - name: 'Philip Morris xStock', - symbol: 'PMx', - mintAddress: 'Xsba6tUnSjDae2VcopDB6FGGDaxRrewFCDa5hKn5vT3', - decimal: 8, - mint: 'pmx', - enabled: false, - iconPath: 'assets/images/stocks/pmx.webp', - ), - SPLToken( - name: 'Procter & Gamble xStock', - symbol: 'PGx', - mintAddress: 'XsYdjDjNUygZ7yGKfQaB6TxLh2gC6RRjzLtLAGJrhzV', - decimal: 8, - mint: 'pgx', - enabled: false, - iconPath: 'assets/images/stocks/pgx.webp', - ), - SPLToken( - name: 'Robinhood xStock', - symbol: 'HOODx', - mintAddress: 'XsvNBAYkrDRNhA7wPHQfX3ZUXZyZLdnCQDfHZ56bzpg', - decimal: 8, - mint: 'hoodx', - enabled: false, - iconPath: 'assets/images/stocks/hoodx.webp', - ), - SPLToken( - name: 'Salesforce xStock', - symbol: 'CRMx', - mintAddress: 'XsczbcQ3zfcgAEt9qHQES8pxKAVG5rujPSHQEXi4kaN', - decimal: 8, - mint: 'crmx', - enabled: false, - iconPath: 'assets/images/stocks/crmx.webp', - ), - SPLToken( - name: 'SP500 xStock', - symbol: 'SPYx', - mintAddress: 'XsoCS1TfEyfFhfvj8EtZ528L3CaKBDBRqRapnBbDF2W', - decimal: 8, - mint: 'spyx', - enabled: false, - iconPath: 'assets/images/stocks/spyx.webp', - ), - SPLToken( - name: 'TBLL xStock', - symbol: 'TBLLx', - mintAddress: 'XsqBC5tcVQLYt8wqGCHRnAUUecbRYXoJCReD6w7QEKp', - decimal: 8, - mint: 'tbllx', - enabled: false, - iconPath: 'assets/images/stocks/tbllx.webp', - ), - SPLToken( - name: 'Tesla xStock', - symbol: 'TSLAx', - mintAddress: 'XsDoVfqeBukxuZHWhdvWHBhgEHjGNst4MLodqsJHzoB', - decimal: 8, - mint: 'tslax', - enabled: false, - iconPath: 'assets/images/stocks/tslax.webp', - ), - SPLToken( - name: 'Thermo Fisher xStock', - symbol: 'TMOx', - mintAddress: 'Xs8drBWy3Sd5QY3aifG9kt9KFs2K3PGZmx7jWrsrk57', - decimal: 8, - mint: 'tmox', - enabled: false, - iconPath: 'assets/images/stocks/tmox.webp', - ), - SPLToken( - name: 'TON xStock', - symbol: 'TONXx', - mintAddress: 'XscE4GUcsYhcyZu5ATiGUMmhxYa1D5fwbpJw4K6K4dp', - decimal: 8, - mint: 'tonxx', - enabled: false, - iconPath: 'assets/images/stocks/tonxx.webp', - ), - SPLToken( - name: 'TQQQ xStock', - symbol: 'TQQQx', - mintAddress: 'XsjQP3iMAaQ3kQScQKthQpx9ALRbjKAjQtHg6TFomoc', - decimal: 8, - mint: 'tqqqx', - enabled: false, - iconPath: 'assets/images/stocks/tqqqx.webp', - ), - SPLToken( - name: 'UnitedHealth xStock', - symbol: 'UNHx', - mintAddress: 'XszvaiXGPwvk2nwb3o9C1CX4K6zH8sez11E6uyup6fe', - decimal: 8, - mint: 'unhx', - enabled: false, - iconPath: 'assets/images/stocks/unhx.webp', - ), - SPLToken( - name: 'Vanguard xStock', - symbol: 'VTIx', - mintAddress: 'XsssYEQjzxBCFgvYFFNuhJFBeHNdLWYeUSP8F45cDr9', - decimal: 8, - mint: 'vtix', - enabled: false, - iconPath: 'assets/images/stocks/vtix.webp', - ), - SPLToken( - name: 'Visa xStock', - symbol: 'Vx', - mintAddress: 'XsqgsbXwWogGJsNcVZ3TyVouy2MbTkfCFhCGGGcQZ2p', - decimal: 8, - mint: 'vx', - enabled: false, - iconPath: 'assets/images/stocks/vx.webp', - ), - SPLToken( - name: 'Walmart xStock', - symbol: 'WMTx', - mintAddress: 'Xs151QeqTCiuKtinzfRATnUESM2xTU6V9Wy8Vy538ci', - decimal: 8, - mint: 'wmtx', - enabled: false, - iconPath: 'assets/images/stocks/wmtx.webp', - ), - ]; - - List get initialSPLTokens => _defaultTokens.map((token) { - String? iconPath; - if (token.iconPath?.isEmpty ?? true) { - try { - iconPath = CryptoCurrency.all - .firstWhere((element) => element.title.toUpperCase() == token.symbol.toUpperCase()) - .iconPath; - } catch (_) {} - } else { - iconPath = token.iconPath; - } - - return SPLToken.copyWith(token, icon: iconPath, tag: 'SOL'); - }).toList(); -} diff --git a/cw_solana/lib/pending_solana_transaction.dart b/cw_solana/lib/pending_solana_transaction.dart deleted file mode 100644 index ddfcf654..00000000 --- a/cw_solana/lib/pending_solana_transaction.dart +++ /dev/null @@ -1,51 +0,0 @@ -import 'package:cw_core/pending_transaction.dart'; - -class PendingSolanaTransaction with PendingTransaction { - final double amount; - final String serializedTransaction; - final String destinationAddress; - final Function sendTransaction; - final double fee; - String? _sig; - - PendingSolanaTransaction({ - required this.fee, - required this.amount, - required this.serializedTransaction, - required this.destinationAddress, - required this.sendTransaction, - }); - - @override - String get amountFormatted { - String stringifiedAmount = amount.toString(); - - if (stringifiedAmount.toString().length >= 6) { - stringifiedAmount = stringifiedAmount.substring(0, 6); - } - - return stringifiedAmount; - } - - @override - Future commit() async { - _sig = await sendTransaction(); - } - - @override - String get feeFormatted => "$feeFormattedValue SOL"; - - @override - String get feeFormattedValue => fee.toString(); - - @override - String get hex => serializedTransaction; - - @override - String get id => _sig ?? ''; - - @override - Future> commitUR() { - throw UnimplementedError(); - } -} diff --git a/cw_solana/lib/solana_balance.dart b/cw_solana/lib/solana_balance.dart deleted file mode 100644 index 7be967fb..00000000 --- a/cw_solana/lib/solana_balance.dart +++ /dev/null @@ -1,44 +0,0 @@ -import 'dart:convert'; - -import 'package:cw_core/balance.dart'; - -class SolanaBalance extends Balance { - SolanaBalance(this.balance, bool isToken) : super( - BigInt.from(int.tryParse(balance.toStringAsFixed(isToken ? 6 : 9).replaceFirst(".", "")) ?? 0), - BigInt.from(int.tryParse(balance.toStringAsFixed(isToken ? 6 : 9).replaceFirst(".", "")) ?? 0)); - - // Using raw amount from RPC to avoid decimals mismatch for SPL tokens. - SolanaBalance.forToken(BigInt rawAmount, double uiAmount) - : balance = uiAmount, - super(rawAmount, rawAmount); - - final double balance; - - String get formattedAdditionalBalance => _balanceFormatted(); - - String get formattedAvailableBalance => _balanceFormatted(); - - String _balanceFormatted() { - String stringBalance = balance.toString(); - if (stringBalance.toString().length >= 12) { - stringBalance = stringBalance.substring(0, 12); - } - return stringBalance; - } - - static SolanaBalance? fromJSON(String? jsonSource, bool isToken) { - if (jsonSource == null) { - return null; - } - - final decoded = json.decode(jsonSource) as Map; - - try { - return SolanaBalance(decoded['balance'], isToken); - } catch (e) { - return SolanaBalance(0.0, isToken); - } - } - - String toJSON() => json.encode({'balance': balance.toString()}); -} diff --git a/cw_solana/lib/solana_client.dart b/cw_solana/lib/solana_client.dart deleted file mode 100644 index 543e2802..00000000 --- a/cw_solana/lib/solana_client.dart +++ /dev/null @@ -1,1946 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:math' as math; - -import 'package:blockchain_utils/blockchain_utils.dart'; -import 'package:cw_core/crypto_currency.dart'; -import 'package:cw_core/node.dart'; -import 'package:cw_core/utils/proxy_wrapper.dart'; -import 'package:cw_core/solana_rpc_http_service.dart'; -import 'package:cw_core/utils/print_verbose.dart'; -import 'package:cw_solana/pending_solana_transaction.dart'; -import 'package:cw_solana/solana_balance.dart'; -import 'package:cw_solana/solana_exceptions.dart'; -import 'package:cw_solana/solana_transaction_model.dart'; -import 'package:cw_core/spl_token.dart'; -import 'package:on_chain/solana/solana.dart'; -import 'package:on_chain/solana/src/instructions/associated_token_account/constant.dart'; -import 'package:on_chain/solana/src/models/pda/pda.dart'; -import 'package:on_chain/solana/src/rpc/models/models/confirmed_transaction_meta.dart'; -import '.secrets.g.dart' as secrets; - -/// Result object containing both parsed transactions and token mints -class TransactionFetchResult { - final List transactions; - final List tokenMints; - - TransactionFetchResult({ - required this.transactions, - required this.tokenMints, - }); -} - -class SolanaWalletClient { - // Minimum amount in SOL to consider a transaction valid (to filter spam) - static const double minValidAmount = 0.00000003; - late final client = ProxyWrapper().getHttpIOClient(); - SolanaRPC? _provider; - - bool connect(Node node) { - try { - String formattedUrl; - String protocolUsed = node.isSSL ? "https" : "http"; - - if (node.uriRaw == 'rpc.ankr.com') { - String ankrApiKey = secrets.ankrApiKey; - - formattedUrl = '$protocolUsed://${node.uriRaw}/$ankrApiKey'; - } else if (node.uriRaw == 'solana-mainnet.core.chainstack.com') { - String chainStackApiKey = secrets.chainStackApiKey; - - formattedUrl = '$protocolUsed://${node.uriRaw}/$chainStackApiKey'; - } else { - formattedUrl = '$protocolUsed://${node.uriRaw}'; - } - - _provider = SolanaRPC(SolanaRPCHTTPService(url: formattedUrl)); - - return true; - } catch (e) { - return false; - } - } - - Future getBalance(String walletAddress, {bool throwOnError = false}) async { - try { - final balance = await _provider!.requestWithContext( - SolanaRPCGetBalance( - account: SolAddress(walletAddress), - ), - ); - - final balInLamp = balance.result.toDouble(); - - final solBalance = balInLamp / SolanaUtils.lamportsPerSol; - - return solBalance; - } catch (_) { - if (throwOnError) { - rethrow; - } - return 0.0; - } - } - - Future?> getSPLTokenAccounts( - String mintAddress, String publicKey) async { - try { - final result = await _provider!.request( - SolanaRPCGetTokenAccountsByOwner( - account: SolAddress(publicKey), - mint: SolAddress(mintAddress), - commitment: Commitment.confirmed, - encoding: SolanaRPCEncoding.base64, - ), - ); - - return result; - } catch (e) { - return null; - } - } - - Future getSplTokenBalance(String mintAddress, String walletAddress, - {bool throwOnError = false}) async { - try { - // Fetch the token accounts (a token can have multiple accounts for various uses) - final tokenAccounts = await getSPLTokenAccounts(mintAddress, walletAddress); - - // Handle scenario where there is no token account - if (tokenAccounts == null || tokenAccounts.isEmpty) { - return null; - } - - // Sum raw amounts and ui amounts across all token accounts - BigInt totalRaw = BigInt.zero; - double totalUi = 0.0; - - for (var tokenAccount in tokenAccounts) { - final tokenAmountResult = await _provider!.request( - SolanaRPCGetTokenAccountBalance(account: tokenAccount.pubkey), - ); - - final raw = BigInt.tryParse(tokenAmountResult.amount) ?? BigInt.zero; - totalRaw += raw; - - final ui = tokenAmountResult.uiAmount ?? - (double.tryParse(tokenAmountResult.uiAmountString ?? '0') ?? 0.0); - totalUi += ui; - } - - return SolanaBalance.forToken(totalRaw, totalUi); - } catch (_) { - if (throwOnError) { - rethrow; - } - return null; - } - } - - Future getFeeForMessage(String message, Commitment commitment) async { - try { - final feeForMessage = await _provider!.request( - SolanaRPCGetFeeForMessage( - encodedMessage: message, - commitment: commitment, - ), - ); - - final fee = (feeForMessage?.toDouble() ?? 0.0) / SolanaUtils.lamportsPerSol; - return fee; - } catch (_) { - return 0.0; - } - } - - Future getEstimatedFee(SolanaPublicKey publicKey, Commitment commitment) async { - final message = await _getMessageForNativeTransaction( - publicKey: publicKey, - destinationAddress: publicKey.toAddress().address, - lamports: SolanaUtils.lamportsPerSol, - commitment: commitment, - ); - - final estimatedFee = await _getFeeFromCompiledMessage( - message, - commitment, - ); - return estimatedFee; - } - - Future?> parseTransaction({ - VersionedTransactionResponse? txResponse, - required String walletAddress, - String? splTokenSymbol, - }) async { - if (txResponse == null) return null; - - try { - final blockTime = txResponse.blockTime; - final meta = txResponse.meta; - final transaction = txResponse.transaction; - - if (meta == null || transaction == null) return null; - - final int fee = meta.fee; - final feeInSol = fee / SolanaUtils.lamportsPerSol; - - final message = transaction.message; - final instructions = message.compiledInstructions; - - String signature = (txResponse.transaction?.signatures.isEmpty ?? true) - ? "" - : Base58Encoder.encode(txResponse.transaction!.signatures.first); - - // We need to check if this is a swap transaction (both native SOL and SPL token balance changes) - final isSwap = _isSwapTransaction(meta, message, walletAddress); - - if (isSwap) { - // We parse it separately, because we want to extract two separate transactions, the outgoing and incoming side of the swap - final swapTransactions = await _parseSwapTransaction( - message: message, - meta: meta, - fee: fee, - feeInSol: feeInSol, - walletAddress: walletAddress, - signature: signature, - blockTime: blockTime, - instructions: instructions, - splTokenSymbol: splTokenSymbol, - ); - - if (swapTransactions.isNotEmpty) return swapTransactions; - } - - for (final instruction in instructions) { - final programId = message.accountKeys[instruction.programIdIndex]; - - if (programId == SystemProgramConst.programId || - programId == ComputeBudgetConst.programId) { - // For native solana transactions - if (instruction.accounts.length < 2) continue; - - // Get the fee payer index based on transaction type - // For legacy transfers, the first account is usually the fee payer - // For versioned, the first account in instruction is usually the fee payer - final feePayerIndex = - txResponse.version == TransactionType.legacy ? 0 : instruction.accounts[0]; - - final transactionModel = await _parseNativeTransaction( - message: message, - meta: meta, - fee: fee, - feeInSol: feeInSol, - feePayerIndex: feePayerIndex, - walletAddress: walletAddress, - signature: signature, - blockTime: blockTime, - ); - - if (transactionModel != null) { - return [transactionModel]; - } - } else if (programId == SPLTokenProgramConst.tokenProgramId) { - // For SPL Token transactions - if (instruction.accounts.length < 2) continue; - - final transactionModel = await _parseSPLTokenTransaction( - message: message, - meta: meta, - fee: fee, - feeInSol: feeInSol, - instruction: instruction, - walletAddress: walletAddress, - signature: signature, - blockTime: blockTime, - splTokenSymbol: splTokenSymbol, - ); - - if (transactionModel != null) { - return [transactionModel]; - } - } else if (programId == AssociatedTokenAccountProgramConst.associatedTokenProgramId) { - // For ATA program, we need to check if this is a create account transaction - // or if it's part of a normal token transfer - - // We skip this transaction if this is the only instruction (this means that it's a create account transaction) - if (instructions.length == 1) { - return null; - } - - // We look for a token transfer instruction in the same transaction - bool hasTokenTransfer = false; - for (final otherInstruction in instructions) { - final otherProgramId = message.accountKeys[otherInstruction.programIdIndex]; - if (otherProgramId == SPLTokenProgramConst.tokenProgramId) { - hasTokenTransfer = true; - break; - } - } - - // If there's no token transfer instruction, it means this is just an ATA creation transaction - if (!hasTokenTransfer) { - return null; - } - - continue; - } else { - continue; - } - } - } catch (e, s) { - printV("Error parsing transaction: $e\n$s"); - } - - return null; - } - - /// Detects if a transaction is a swap by checking that the wallet both sends one asset and receives another. - /// - /// A simple token transfer is NOT a swap (wallet only sends or receives, not both). - bool _isSwapTransaction( - ConfirmedTransactionMeta meta, - VersionedMessage message, - String walletAddress, - ) { - final fee = meta.fee; - final preBalances = meta.preBalances; - final postBalances = meta.postBalances; - final accountKeys = message.accountKeys; - - bool walletSentSol = false; - bool walletReceivedSol = false; - - if (preBalances.isNotEmpty && postBalances.isNotEmpty) { - final maxLength = [ - accountKeys.length, - preBalances.length, - postBalances.length, - ].reduce((a, b) => a < b ? a : b); - - for (int i = 0; i < maxLength; i++) { - if (accountKeys[i].address != walletAddress) { - continue; - } - - final change = postBalances[i] - preBalances[i]; - - if (change > BigInt.zero) { - walletReceivedSol = true; - } else if (change < BigInt.zero) { - // Only count as sent if the decrease - // exceeds the fee (otherwise it's just fees). - final netDecrease = change.abs() - BigInt.from(fee); - if (netDecrease > BigInt.zero) { - walletSentSol = true; - } - } - break; - } - } - - bool walletSentToken = false; - bool walletReceivedToken = false; - - final preTokenBalances = meta.preTokenBalances; - final postTokenBalances = meta.postTokenBalances; - - if (preTokenBalances != null && postTokenBalances != null) { - // Check wallet-owned balances that exist in pre - for (final preBal in preTokenBalances) { - if (preBal.owner?.address != walletAddress) { - continue; - } - - final mint = preBal.mint.address; - final preAmt = preBal.uiTokenAmount.uiAmount ?? 0.0; - - double postAmt = preAmt; - for (final postBal in postTokenBalances) { - if (postBal.owner?.address == walletAddress && postBal.mint.address == mint) { - postAmt = postBal.uiTokenAmount.uiAmount ?? 0.0; - break; - } - } - - final diff = postAmt - preAmt; - if (diff < 0) { - walletSentToken = true; - } else if (diff > 0) { - walletReceivedToken = true; - } - } - - // Check for tokens the wallet received into - // a newly created ATA (no pre-balance entry). - for (final postBal in postTokenBalances) { - if (postBal.owner?.address != walletAddress) { - continue; - } - final postAmt = postBal.uiTokenAmount.uiAmount ?? 0.0; - if (postAmt <= 0) continue; - - final mint = postBal.mint.address; - final existsInPre = preTokenBalances.any( - (p) => p.owner?.address == walletAddress && p.mint.address == mint, - ); - if (!existsInPre) { - walletReceivedToken = true; - } - } - } - - // A swap requires the wallet to both send and receive across different assets. - final walletSent = walletSentSol || walletSentToken; - final walletReceived = walletReceivedSol || walletReceivedToken; - return walletSent && walletReceived; - } - - /// Parses a swap transaction and creates dual entries (outgoing and incoming) - Future> _parseSwapTransaction({ - required VersionedMessage message, - required ConfirmedTransactionMeta meta, - required int fee, - required double feeInSol, - required String walletAddress, - required String signature, - required BigInt? blockTime, - required List instructions, - String? splTokenSymbol, - }) async { - final List swapTransactions = []; - - final preBalances = meta.preBalances; - final postBalances = meta.postBalances; - final accountKeys = message.accountKeys; - final preTokenBalances = meta.preTokenBalances; - final postTokenBalances = meta.postTokenBalances; - - String? decreasedMintForWallet; - String? increasedMintForWallet; - - if (preTokenBalances != null && postTokenBalances != null) { - for (final preTokenBal in preTokenBalances) { - final owner = preTokenBal.owner?.address ?? ''; - if (owner != walletAddress) continue; - - final mint = preTokenBal.mint.address; - final preAmount = preTokenBal.uiTokenAmount.uiAmount ?? 0.0; - - double postAmount = preAmount; - for (final postTokenBal in postTokenBalances) { - final postOwner = postTokenBal.owner?.address ?? ''; - final postMint = postTokenBal.mint.address; - if (postOwner == walletAddress && postMint == mint) { - postAmount = postTokenBal.uiTokenAmount.uiAmount ?? 0.0; - break; - } - } - - final diff = postAmount - preAmount; - if (diff < 0 && decreasedMintForWallet == null) { - decreasedMintForWallet = mint; - } else if (diff > 0 && increasedMintForWallet == null) { - increasedMintForWallet = mint; - } - } - } - - final bool isSplToSplSwap = decreasedMintForWallet != null && - increasedMintForWallet != null && - decreasedMintForWallet != increasedMintForWallet; - - // Parse outgoing side (what was sent) - double outgoingAmount = 0.0; - String outgoingTokenSymbol = ''; - String? outgoingMintAddress; - String? outgoingFrom; - String? outgoingTo; - - // First we check if there are any native SOL balance changes for the wallet. - // For pure SPL → SPL swaps, SOL changes are just fees, so we ignore them. - if (!isSplToSplSwap && preBalances.isNotEmpty && postBalances.isNotEmpty) { - final maxLength = - accountKeys.length < preBalances.length ? accountKeys.length : preBalances.length; - - for (int i = 0; i < maxLength && i < postBalances.length; i++) { - final accountKey = accountKeys[i]; - final accountAddress = accountKey.address; - - if (accountAddress == walletAddress) { - final preBalance = preBalances[i]; - final postBalance = postBalances[i]; - final balanceChange = preBalance - postBalance; - - if (balanceChange > BigInt.zero) { - // The wallet sent SOL - outgoingAmount = balanceChange.toDouble() / SolanaUtils.lamportsPerSol; - outgoingTokenSymbol = 'SOL'; - outgoingMintAddress = null; - outgoingFrom = walletAddress; - // We find the intermediate account or swap program account - if (instructions.isNotEmpty && instructions[0].accounts.isNotEmpty) { - final firstAccountIndex = instructions[0].accounts[0]; - if (firstAccountIndex < accountKeys.length) { - outgoingTo = accountKeys[firstAccountIndex].address; - } - } - outgoingTo ??= walletAddress; - break; - } - } - } - } - - // If no SOL outgoing, we check if there are any SPL token balance changes for the wallet - if (outgoingAmount == 0.0 && preTokenBalances != null) { - for (final preTokenBal in preTokenBalances) { - final owner = preTokenBal.owner?.address ?? ''; - - if (owner == walletAddress) { - final mint = preTokenBal.mint.address; - // For SPL → SPL swaps, we only treat the decreased mint as outgoing - if (isSplToSplSwap && mint != decreasedMintForWallet) { - continue; - } - final preAmount = preTokenBal.uiTokenAmount.uiAmount ?? 0.0; - - // We find the corresponding post balance - for (final postTokenBal in postTokenBalances ?? []) { - final postOwner = postTokenBal.owner?.address ?? ''; - final postMint = postTokenBal.mint.address; - final postAmount = postTokenBal.uiTokenAmount.uiAmount ?? 0.0; - - if (postOwner == walletAddress && postMint == mint) { - final diff = preAmount - postAmount; - - if (diff > 0) { - // The wallet sent tokens - outgoingAmount = diff.toDouble(); - outgoingMintAddress = mint; - final token = await getTokenInfo(mint); - outgoingTokenSymbol = token?.symbol ?? 'TOKEN'; - outgoingFrom = walletAddress; - // We find the intermediate account - if (instructions.isNotEmpty && instructions[0].accounts.isNotEmpty) { - final firstAccountIndex = instructions[0].accounts[0]; - if (firstAccountIndex < accountKeys.length) { - outgoingTo = accountKeys[firstAccountIndex].address; - } - } - outgoingTo ??= walletAddress; - break; - } - } - } - - if (outgoingAmount > 0) break; - } - } - } - - // Parse incoming side (what was received) - double incomingAmount = 0.0; - String incomingTokenSymbol = ''; - String? incomingMintAddress; - String? incomingFrom; - String? incomingTo; - - // We check if there are any native SOL balance changes for the wallet - if (preBalances.isNotEmpty && postBalances.isNotEmpty) { - final maxLength = - accountKeys.length < preBalances.length ? accountKeys.length : preBalances.length; - - for (int i = 0; i < maxLength && i < postBalances.length; i++) { - final accountKey = accountKeys[i]; - final accountAddress = accountKey.address; - - if (accountAddress == walletAddress) { - final preBalance = preBalances[i]; - final postBalance = postBalances[i]; - final balanceChange = postBalance - preBalance; - - if (balanceChange > BigInt.zero) { - // The wallet received SOL - incomingAmount = balanceChange.toDouble() / SolanaUtils.lamportsPerSol; - incomingTokenSymbol = 'SOL'; - incomingMintAddress = null; - incomingTo = walletAddress; - // We find the intermediate account - if (instructions.isNotEmpty && instructions[0].accounts.isNotEmpty) { - final firstAccountIndex = instructions[0].accounts[0]; - if (firstAccountIndex < accountKeys.length) { - incomingFrom = accountKeys[firstAccountIndex].address; - } - } - incomingFrom ??= walletAddress; - break; - } - } - } - } - - // If no SOL incoming, check SPL token incoming using ATA derivation - if (incomingAmount == 0.0 && preTokenBalances != null && postTokenBalances != null) { - // Collect all unique mints from token balances (excluding wrapped SOL) - final mints = {}; - for (final tokenBal in preTokenBalances) { - final mint = tokenBal.mint.address; - if (mint != 'So11111111111111111111111111111111111111112') { - mints.add(mint); - } - } - for (final tokenBal in postTokenBalances) { - final mint = tokenBal.mint.address; - if (mint != 'So11111111111111111111111111111111111111112') { - mints.add(mint); - } - } - - // For each mint, we derive the wallet's ATA address and check for balance changes - for (final mint in mints) { - try { - final walletSolAddress = SolAddress(walletAddress); - final mintSolAddress = SolAddress(mint); - - final ata = AssociatedTokenAccountProgramUtils.associatedTokenAccount( - mint: mintSolAddress, - owner: walletSolAddress, - ); - final ataAddress = ata.address.address; - - // We check if this ATA address appears in the account keys - int? ataAccountIndex; - for (int i = 0; i < accountKeys.length; i++) { - final accountKey = accountKeys[i]; - if (accountKey.address == ataAddress) { - ataAccountIndex = i; - break; - } - } - - // If ATA is in the transaction, we check for balance changes - if (ataAccountIndex != null) { - double preAmount = 0.0; - double postAmount = 0.0; - - // We find the pre balance - for (final preTokenBal in preTokenBalances) { - final accountIndex = preTokenBal.accountIndex; - final tokenMint = preTokenBal.mint.address; - if (accountIndex == ataAccountIndex && tokenMint == mint) { - preAmount = preTokenBal.uiTokenAmount.uiAmount?.toDouble() ?? 0.0; - break; - } - } - - // We find the post balance - for (final postTokenBal in postTokenBalances) { - final accountIndex = postTokenBal.accountIndex; - final tokenMint = postTokenBal.mint.address; - if (accountIndex == ataAccountIndex && tokenMint == mint) { - postAmount = postTokenBal.uiTokenAmount.uiAmount?.toDouble() ?? 0.0; - break; - } - } - - final diff = postAmount - preAmount; - if (diff > 0) { - // The wallet received tokens - incomingAmount = diff.toDouble(); - incomingMintAddress = mint; - final token = await getTokenInfo(mint); - incomingTokenSymbol = token?.symbol ?? 'TOKEN'; - incomingTo = walletAddress; - // We find the intermediate account - if (instructions.isNotEmpty && instructions[0].accounts.isNotEmpty) { - final firstAccountIndex = instructions[0].accounts[0]; - if (firstAccountIndex < accountKeys.length) { - incomingFrom = accountKeys[firstAccountIndex].address; - } - } - incomingFrom ??= walletAddress; - break; - } - } - } catch (e) { - // We skip if the ATA derivation fails - continue; - } - } - } - - // Outgoing transaction model - if (outgoingAmount > 0.0 && outgoingFrom != null && outgoingTo != null) { - final outgoingId = - '${signature}_outgoing'; // We create a composite ID for the outgoing transaction - swapTransactions.add(SolanaTransactionModel( - isOutgoingTx: true, - from: outgoingFrom, - to: outgoingTo, - id: outgoingId, - amount: outgoingAmount, - programId: outgoingMintAddress == null - ? SystemProgramConst.programId.address - : SPLTokenProgramConst.tokenProgramId.address, - blockTimeInInt: blockTime?.toInt() ?? 0, - tokenSymbol: outgoingTokenSymbol, - fee: feeInSol, - )); - } - - // Incoming transaction model - if (incomingAmount > 0.0 && incomingFrom != null && incomingTo != null) { - final incomingId = - '${signature}_incoming'; // We create a composite ID for the incoming transaction - swapTransactions.add(SolanaTransactionModel( - isOutgoingTx: false, - from: incomingFrom, - to: incomingTo, - id: incomingId, - amount: incomingAmount, - programId: incomingMintAddress == null - ? SystemProgramConst.programId.address - : SPLTokenProgramConst.tokenProgramId.address, - blockTimeInInt: blockTime?.toInt() ?? 0, - tokenSymbol: incomingTokenSymbol, - fee: 0.0, // Fee only charged on outgoing side - )); - } - - return swapTransactions; - } - - Future _parseNativeTransaction({ - required VersionedMessage message, - required ConfirmedTransactionMeta meta, - required int fee, - required double feeInSol, - required int feePayerIndex, - required String walletAddress, - required String signature, - required BigInt? blockTime, - }) async { - final accountKeys = message.accountKeys; - final preBalances = meta.preBalances; - final postBalances = meta.postBalances; - - final maxLen = [ - accountKeys.length, - preBalances.length, - postBalances.length, - ].reduce((a, b) => a < b ? a : b); - - // Find the wallet's own balance change. - int walletIndex = -1; - for (int i = 0; i < maxLen; i++) { - if (accountKeys[i].address == walletAddress) { - walletIndex = i; - break; - } - } - - if (walletIndex < 0) return null; - - final walletPre = preBalances[walletIndex]; - final walletPost = postBalances[walletIndex]; - // Positive = wallet lost SOL, negative = wallet gained. - final walletChange = walletPre - walletPost; - - final bool walletPaidFee = - feePayerIndex < accountKeys.length && accountKeys[feePayerIndex].address == walletAddress; - - // Net transfer amount excluding the fee. - final netChange = walletPaidFee ? walletChange - BigInt.from(fee) : walletChange; - - final isOutgoing = netChange > BigInt.zero; - final amountLamports = netChange.abs(); - final amountInSol = amountLamports.toDouble() / SolanaUtils.lamportsPerSol; - - if (amountInSol < minValidAmount) return null; - - // Find the most likely receiver, the account that has the largest opposite balance change. - String? receiver; - BigInt bestChange = BigInt.zero; - - for (int i = 0; i < maxLen; i++) { - if (i == walletIndex) continue; - final change = postBalances[i] - preBalances[i]; - - if (isOutgoing && change > bestChange) { - bestChange = change; - receiver = accountKeys[i].address; - } else if (!isOutgoing && change < BigInt.zero && change.abs() > bestChange) { - bestChange = change.abs(); - receiver = accountKeys[i].address; - } - } - - if (receiver == null) return null; - - return SolanaTransactionModel( - isOutgoingTx: isOutgoing, - from: isOutgoing ? walletAddress : receiver, - to: isOutgoing ? receiver : walletAddress, - id: signature, - amount: amountInSol, - programId: SystemProgramConst.programId.address, - tokenSymbol: 'SOL', - blockTimeInInt: blockTime?.toInt() ?? 0, - fee: feeInSol, - ); - } - - Future _parseSPLTokenTransaction({ - required VersionedMessage message, - required ConfirmedTransactionMeta meta, - required int fee, - required double feeInSol, - required CompiledInstruction instruction, - required String walletAddress, - required String signature, - required BigInt? blockTime, - String? splTokenSymbol, - }) async { - final preTokenBalances = meta.preTokenBalances; - final postTokenBalances = meta.postTokenBalances; - - final accountKeys = message.accountKeys; - final accounts = instruction.accounts; - - // TransferChecked has 4 accounts: - // [0] source, [1] mint, [2] destination, [3] owner - // Transfer has 3 accounts: - // [0] source, [1] destination, [2] owner - final isTransferChecked = accounts.length >= 4; - - final sourceAccountIndex = accounts[0]; - final destinationAccountIndex = isTransferChecked ? accounts[2] : accounts[1]; - - String? mintAddress; - if (isTransferChecked) { - mintAddress = accountKeys[accounts[1]].address; - } - - double userPreAmount = 0.0; - double userPostAmount = 0.0; - - if (preTokenBalances != null) { - for (final preBal in preTokenBalances) { - final idx = preBal.accountIndex; - if (idx == sourceAccountIndex || idx == destinationAccountIndex) { - if (preBal.owner?.address == walletAddress) { - if (mintAddress != null && preBal.mint.address != mintAddress) { - continue; - } - mintAddress ??= preBal.mint.address; - userPreAmount = preBal.uiTokenAmount.uiAmount ?? 0.0; - break; - } - } - } - } - - if (postTokenBalances != null) { - for (final postBal in postTokenBalances) { - final idx = postBal.accountIndex; - if (idx == sourceAccountIndex || idx == destinationAccountIndex) { - if (postBal.owner?.address == walletAddress) { - if (mintAddress != null && postBal.mint.address != mintAddress) { - continue; - } - mintAddress ??= postBal.mint.address; - userPostAmount = postBal.uiTokenAmount.uiAmount ?? 0.0; - break; - } - } - } - } - - final diff = userPreAmount - userPostAmount; - final rawAmount = diff.abs(); - - final amountInString = rawAmount.toStringAsFixed(6); - final amount = double.parse(amountInString); - final isOutgoing = diff > 0; - - // Resolve sender/receiver from token balance owners - String? senderOwner; - String? receiverOwner; - - final allBalances = [ - ...?preTokenBalances, - ...?postTokenBalances, - ]; - - for (final bal in allBalances) { - if (mintAddress != null && bal.mint.address != mintAddress) { - continue; - } - if (bal.accountIndex == sourceAccountIndex) { - senderOwner ??= bal.owner?.address; - } - if (bal.accountIndex == destinationAccountIndex) { - receiverOwner ??= bal.owner?.address; - } - if (senderOwner != null && receiverOwner != null) { - break; - } - } - - final sender = senderOwner ?? accountKeys[sourceAccountIndex].address; - final receiver = receiverOwner ?? accountKeys[destinationAccountIndex].address; - - String? tokenSymbol = splTokenSymbol; - - if (tokenSymbol == null && mintAddress != null) { - final token = await getTokenInfo(mintAddress); - tokenSymbol = token?.symbol; - } - - return SolanaTransactionModel( - isOutgoingTx: isOutgoing, - from: sender, - to: receiver, - id: signature, - amount: amount, - programId: SPLTokenProgramConst.tokenProgramId.address, - blockTimeInInt: blockTime?.toInt() ?? 0, - tokenSymbol: tokenSymbol ?? '', - fee: feeInSol, - ); - } - - /// Fetches a specific transaction by signature and parses it - /// It returns a TransactionFetchResult object containing both transactions and token mints extracted from the transaction or null if the transaction is not found or cannot be parsed - Future fetchTransactionBySignature({ - required String signature, - required String walletAddress, - String? splTokenSymbol, - }) async { - try { - final txResponse = await _provider!.request( - SolanaRPCGetTransaction( - transactionSignature: signature, - encoding: SolanaRPCEncoding.jsonParsed, - maxSupportedTransactionVersion: 1, - skipVerification: true, - ), - ); - - final versionedResponse = txResponse as VersionedTransactionResponse?; - if (versionedResponse == null) return null; - - final tokenMints = _extractTokenMintsFromMeta(versionedResponse.meta); - - final parsed = await parseTransaction( - txResponse: versionedResponse, - walletAddress: walletAddress, - splTokenSymbol: splTokenSymbol, - ); - - if (parsed == null) return null; - - return TransactionFetchResult( - transactions: parsed, - tokenMints: tokenMints, - ); - } catch (e) { - printV('Error fetching transaction by signature: $e'); - return null; - } - } - - /// Extracts token mint addresses from transaction metadata - /// It returns a list of unique token mint addresses (excluding wrapped SOL) - List _extractTokenMintsFromMeta(ConfirmedTransactionMeta? meta) { - if (meta == null) return []; - - final preTokenBalances = meta.preTokenBalances; - final postTokenBalances = meta.postTokenBalances; - - final mints = {}; - - if (preTokenBalances != null) { - for (final tokenBal in preTokenBalances) { - final mint = tokenBal.mint.address; - if (mint != 'So11111111111111111111111111111111111111112') { - mints.add(mint); - } - } - } - - if (postTokenBalances != null) { - for (final tokenBal in postTokenBalances) { - final mint = tokenBal.mint.address; - if (mint != 'So11111111111111111111111111111111111111112') { - mints.add(mint); - } - } - } - - return mints.toList(); - } - - /// Load the Address's transactions into the account - Future> fetchTransactions( - SolAddress address, { - String? splTokenSymbol, - int? splTokenDecimal, - Commitment? commitment, - SolAddress? walletAddress, - required void Function(List) onUpdate, - }) async { - List transactions = []; - try { - final signatures = await _provider!.request( - SolanaRPCGetSignaturesForAddress( - account: address, - commitment: commitment, - ), - ); - - // The maximum concurrent batch size. - const int batchSize = 10; - - for (int i = 0; i < signatures.length; i += batchSize) { - final batch = signatures.skip(i).take(batchSize).toList(); - - final batchResponses = await Future.wait(batch.map((signature) async { - try { - return await _provider!.request( - SolanaRPCGetTransaction( - transactionSignature: signature['signature'], - encoding: SolanaRPCEncoding.jsonParsed, - maxSupportedTransactionVersion: 1, - skipVerification: true, - ), - ); - } catch (e) { - return null; - } - })); - - final versionedBatchResponses = batchResponses.whereType(); - - final parsedTransactionsFutures = versionedBatchResponses.map((tx) => parseTransaction( - txResponse: tx, - splTokenSymbol: splTokenSymbol, - walletAddress: walletAddress?.address ?? address.address, - )); - - final parsedTransactionsLists = await Future.wait(parsedTransactionsFutures); - - // We flatten the list of lists into a single list - for (final parsedList in parsedTransactionsLists) { - if (parsedList != null) { - transactions.addAll(parsedList); - } - } - - // Only update UI if we have new valid transactions - if (transactions.isNotEmpty) { - onUpdate(List.from(transactions)); - } - - if (i + batchSize < signatures.length) { - await Future.delayed(const Duration(milliseconds: 100)); - } - } - - return transactions; - } catch (err, s) { - printV('Error fetching transactions: $err \n$s'); - return []; - } - } - - Future> getSPLTokenTransfers({ - required String mintAddress, - required String splTokenSymbol, - required int splTokenDecimal, - required SolanaPrivateKey privateKey, - required void Function(List) onUpdate, - }) async { - ProgramDerivedAddress? associatedTokenAccount; - final ownerWalletAddress = privateKey.publicKey().toAddress(); - try { - associatedTokenAccount = await _getOrCreateAssociatedTokenAccount( - payerPrivateKey: privateKey, - mintAddress: SolAddress(mintAddress), - ownerAddress: ownerWalletAddress, - shouldCreateATA: false, - ); - } catch (e, s) { - printV('$e \n $s'); - } - - if (associatedTokenAccount == null) return []; - - final accountPublicKey = associatedTokenAccount.address; - - final tokenTransactions = await fetchTransactions( - accountPublicKey, - splTokenSymbol: splTokenSymbol, - splTokenDecimal: splTokenDecimal, - walletAddress: ownerWalletAddress, - onUpdate: onUpdate, - ); - - return tokenTransactions; - } - - final Map tokenInfoCache = {}; - - Future getTokenInfo(String mintAddress) async { - if (tokenInfoCache.containsKey(mintAddress)) { - return tokenInfoCache[mintAddress]; - } else { - final token = await fetchSPLTokenInfo(mintAddress); - if (token != null) { - tokenInfoCache[mintAddress] = token; - } - return token; - } - } - - Future fetchSPLTokenInfo(String mintAddress) async { - try { - final uri = Uri.https( - 'solana-gateway.moralis.io', - '/token/mainnet/$mintAddress/metadata', - ); - - final response = await client.get( - uri, - headers: { - "Accept": "application/json", - "X-API-Key": secrets.moralisApiKey, - }, - ); - - final decodedResponse = jsonDecode(response.body) as Map; - - final symbol = (decodedResponse['symbol'] ?? '') as String; - - final name = decodedResponse['name'] ?? ''; - final decimal = decodedResponse['decimals'] ?? '0'; - final iconPath = decodedResponse['logo'] ?? ''; - - String filteredTokenSymbol = - symbol.replaceFirst(RegExp('^\\\$'), '').replaceAll('\u0000', ''); - - return SPLToken( - name: name, - mint: symbol, - symbol: filteredTokenSymbol, - mintAddress: mintAddress, - iconPath: iconPath, - decimal: int.tryParse(decimal) ?? 0, - ); - } catch (e, s) { - printV('Error fetching token info: $e \n $s'); - try { - final programAddress = - MetaplexTokenMetaDataProgramUtils.findMetadataPda(mint: SolAddress(mintAddress)); - - final token = await _provider!.request( - SolanaRPCGetMetadataAccount( - account: programAddress.address, - commitment: Commitment.confirmed, - ), - ); - - if (token == null) return null; - - final metadata = token.data; - - String? iconPath; - //TODO(Further explore fetching images) - // try { - // iconPath = await _client.getIconImageFromTokenUri(metadata.uri); - // } catch (_) {} - - String filteredTokenSymbol = - metadata.symbol.replaceFirst(RegExp('^\\\$'), '').replaceAll('\u0000', ''); - - return SPLToken.fromMetadata( - name: metadata.name, - mint: metadata.symbol, - symbol: filteredTokenSymbol, - mintAddress: token.mint.address, - iconPath: iconPath, - ); - } catch (_) {} - - return null; - } - } - - void stop() {} - - SolanaRPC? get getSolanaProvider => _provider; - - Future signSolanaTransaction({ - required String tokenTitle, - required int tokenDecimals, - required double inputAmount, - required String destinationAddress, - required SolanaPrivateKey ownerPrivateKey, - required bool isSendAll, - required double solBalance, - String? tokenMint, - List references = const [], - }) async { - const commitment = Commitment.confirmed; - - if (tokenTitle == CryptoCurrency.sol.title) { - final pendingNativeTokenTransaction = await _signNativeTokenTransaction( - inputAmount: inputAmount, - destinationAddress: destinationAddress, - ownerPrivateKey: ownerPrivateKey, - commitment: commitment, - isSendAll: isSendAll, - solBalance: solBalance, - ); - return pendingNativeTokenTransaction; - } else { - final pendingSPLTokenTransaction = _signSPLTokenTransaction( - tokenDecimals: tokenDecimals, - tokenMint: tokenMint!, - inputAmount: inputAmount, - ownerPrivateKey: ownerPrivateKey, - destinationAddress: destinationAddress, - commitment: commitment, - solBalance: solBalance, - ); - return pendingSPLTokenTransaction; - } - } - - Future _getLatestBlockhash(Commitment commitment) async { - final latestBlockhash = await _provider!.request( - const SolanaRPCGetLatestBlockhash(), - ); - - return latestBlockhash.blockhash; - } - - Future _getMessageForNativeTransaction({ - required SolanaPublicKey publicKey, - required String destinationAddress, - required int lamports, - required Commitment commitment, - }) async { - final instructions = [ - SystemProgram.transfer( - from: publicKey.toAddress(), - layout: SystemTransferLayout(lamports: BigInt.from(lamports)), - to: SolAddress(destinationAddress), - ), - ]; - - final latestBlockhash = await _getLatestBlockhash(commitment); - - final message = Message.compile( - transactionInstructions: instructions, - payer: publicKey.toAddress(), - recentBlockhash: latestBlockhash, - ); - return message; - } - - Future _getMessageForSPLTokenTransaction({ - required SolAddress ownerAddress, - required SolAddress destinationAddress, - required int tokenDecimals, - required SolAddress mintAddress, - required SolAddress sourceAccount, - required int amount, - required Commitment commitment, - required SolAddress tokenProgramId, - }) async { - final instructions = [ - SPLTokenProgram.transferChecked( - layout: SPLTokenTransferCheckedLayout( - amount: BigInt.from(amount), - decimals: tokenDecimals, - ), - mint: mintAddress, - source: sourceAccount, - destination: destinationAddress, - owner: ownerAddress, - ) - ]; - - final latestBlockhash = await _getLatestBlockhash(commitment); - - final message = Message.compile( - transactionInstructions: instructions, - payer: ownerAddress, - recentBlockhash: latestBlockhash, - ); - return message; - } - - Future _getFeeFromCompiledMessage(Message message, Commitment commitment) async { - final base64Message = base64Encode(message.serialize()); - - final fee = await getFeeForMessage(base64Message, commitment); - - return fee; - } - - Future hasSufficientFundsLeftForRent({ - required double inputAmount, - required double solBalance, - required double fee, - }) async { - final rent = await _provider!.request( - SolanaRPCGetMinimumBalanceForRentExemption( - size: SolanaTokenAccountUtils.accountSize, - ), - ); - - final rentInSol = (rent.toDouble() / SolanaUtils.lamportsPerSol).toDouble(); - - final remnant = solBalance - (inputAmount + fee); - - if (remnant > rentInSol) return true; - - return false; - } - - Future _signNativeTokenTransaction({ - required double inputAmount, - required String destinationAddress, - required SolanaPrivateKey ownerPrivateKey, - required Commitment commitment, - required bool isSendAll, - required double solBalance, - }) async { - // Convert SOL to lamport - int lamports = (inputAmount * SolanaUtils.lamportsPerSol).toInt(); - - Message message = await _getMessageForNativeTransaction( - publicKey: ownerPrivateKey.publicKey(), - destinationAddress: destinationAddress, - lamports: lamports, - commitment: commitment, - ); - - SolAddress latestBlockhash = await _getLatestBlockhash(commitment); - - final fee = await _getFeeFromCompiledMessage( - message, - commitment, - ); - - if (!isSendAll) { - bool hasSufficientFundsLeft = await hasSufficientFundsLeftForRent( - inputAmount: inputAmount, - fee: fee, - solBalance: solBalance, - ); - - if (!hasSufficientFundsLeft) { - throw SolanaSignNativeTokenTransactionRentException(); - } - } - - String serializedTransaction; - if (isSendAll) { - final feeInLamports = (fee * SolanaUtils.lamportsPerSol).toInt(); - final updatedLamports = lamports - feeInLamports; - - final transaction = _constructNativeTransaction( - ownerPrivateKey: ownerPrivateKey, - destinationAddress: destinationAddress, - latestBlockhash: latestBlockhash, - lamports: updatedLamports, - ); - - serializedTransaction = await _signTransactionInternal( - ownerPrivateKey: ownerPrivateKey, - transaction: transaction, - ); - } else { - final transaction = _constructNativeTransaction( - ownerPrivateKey: ownerPrivateKey, - destinationAddress: destinationAddress, - latestBlockhash: latestBlockhash, - lamports: lamports, - ); - - serializedTransaction = await _signTransactionInternal( - ownerPrivateKey: ownerPrivateKey, - transaction: transaction, - ); - } - - sendTx() async => await sendTransaction( - serializedTransaction: serializedTransaction, - commitment: commitment, - ); - - final pendingTransaction = PendingSolanaTransaction( - amount: inputAmount, - serializedTransaction: serializedTransaction, - destinationAddress: destinationAddress, - sendTransaction: sendTx, - fee: fee, - ); - - return pendingTransaction; - } - - SolanaTransaction _constructNativeTransaction({ - required SolanaPrivateKey ownerPrivateKey, - required String destinationAddress, - required SolAddress latestBlockhash, - required int lamports, - }) { - final owner = ownerPrivateKey.publicKey().toAddress(); - - /// Create a transfer instruction to move funds from the owner to the receiver. - final transferInstruction = SystemProgram.transfer( - from: owner, - layout: SystemTransferLayout(lamports: BigInt.from(lamports)), - to: SolAddress(destinationAddress), - ); - - /// Construct a Solana transaction with the transfer instruction. - return SolanaTransaction( - instructions: [transferInstruction], - recentBlockhash: latestBlockhash, - payerKey: ownerPrivateKey.publicKey().toAddress(), - type: TransactionType.v0, - ); - } - - /// Creates a transferChecked instruction with a custom token program ID. - /// This supports both standard SPL Token and Token-2022. - TransactionInstruction _createTransferCheckedInstruction({ - required SolAddress tokenProgramId, - required SolAddress source, - required SolAddress destination, - required SolAddress mint, - required SolAddress owner, - required BigInt amount, - required int decimals, - }) { - // TransferChecked instruction format: - // - Instruction discriminator: 12 (u8) - // - Amount: 8 bytes (u64, little-endian) - // - Decimals: 1 byte (u8) - - // Convert BigInt to 8-byte little-endian array - final amountBytes = []; - var amountValue = amount.toUnsigned(64); - for (int i = 0; i < 8; i++) { - amountBytes.add((amountValue & BigInt.from(0xFF)).toInt()); - amountValue = amountValue >> 8; - } - - final instructionData = [12, ...amountBytes, decimals]; - - // Account order for transferChecked: - // 0. source (writable) - // 1. mint (readonly) - // 2. destination (writable) - // 3. owner (signer) - final accounts = [ - AccountMeta( - publicKey: source, - isWritable: true, - isSigner: false, - ), - AccountMeta( - publicKey: mint, - isWritable: false, - isSigner: false, - ), - AccountMeta( - publicKey: destination, - isWritable: true, - isSigner: false, - ), - AccountMeta( - publicKey: owner, - isWritable: false, - isSigner: true, - ), - ]; - - return TransactionInstruction.fromBytes( - programId: tokenProgramId, - instructionBytes: instructionData, - keys: accounts, - ); - } - - /// Gets the token program ID for a given mint address. - /// Returns the standard SPL Token program ID if the mint account cannot be fetched. - Future _getTokenProgramId(SolAddress mintAddress) async { - try { - final mintAccountInfo = await _provider!.request( - SolanaRPCGetAccountInfo( - account: mintAddress, - commitment: Commitment.confirmed, - ), - ); - - // Determine the token program ID from the mint account owner - if (mintAccountInfo != null) { - return mintAccountInfo.owner; - } - } catch (e) { - // If we can't fetch mint info, default to standard SPL Token program - printV('Warning: Could not fetch mint account info: $e'); - } - - return SPLTokenProgramConst.tokenProgramId; - } - - Future _getOrCreateAssociatedTokenAccount({ - required SolanaPrivateKey payerPrivateKey, - required SolAddress ownerAddress, - required SolAddress mintAddress, - required bool shouldCreateATA, - }) async { - // For transaction history loading (shouldCreateATA: false), try standard token program first - // to avoid unnecessary RPC call. Only fetch token program ID when creating accounts. - SolAddress tokenProgramId = SPLTokenProgramConst.tokenProgramId; - - if (shouldCreateATA) { - // Only fetch token program ID when we need to create an account - tokenProgramId = await _getTokenProgramId(mintAddress); - } - - // Try with standard token program first (most common case) - var associatedTokenAccount = AssociatedTokenAccountProgramUtils.associatedTokenAccount( - mint: mintAddress, - owner: ownerAddress, - tokenProgramId: SPLTokenProgramConst.tokenProgramId, - ); - - SolanaAccountInfo? accountInfo; - try { - accountInfo = await _provider!.request( - SolanaRPCGetAccountInfo( - account: associatedTokenAccount.address, - commitment: Commitment.confirmed, - ), - ); - } catch (e) { - accountInfo = null; - } - - // If account exists with standard program, return it - if (accountInfo != null) return associatedTokenAccount; - - // If not found and we're not creating, try Token-2022 as fallback - if (!shouldCreateATA) { - try { - final token2022ProgramId = await _getTokenProgramId(mintAddress); - if (token2022ProgramId.address != SPLTokenProgramConst.tokenProgramId.address) { - associatedTokenAccount = AssociatedTokenAccountProgramUtils.associatedTokenAccount( - mint: mintAddress, - owner: ownerAddress, - tokenProgramId: token2022ProgramId, - ); - - try { - accountInfo = await _provider!.request( - SolanaRPCGetAccountInfo( - account: associatedTokenAccount.address, - commitment: Commitment.confirmed, - ), - ); - if (accountInfo != null) return associatedTokenAccount; - } catch (_) {} - } - } catch (_) {} - return null; - } - - // For account creation, use the detected token program ID - associatedTokenAccount = AssociatedTokenAccountProgramUtils.associatedTokenAccount( - mint: mintAddress, - owner: ownerAddress, - tokenProgramId: tokenProgramId, - ); - - final payerAddress = payerPrivateKey.publicKey().toAddress(); - - final createAssociatedTokenAccount = AssociatedTokenAccountProgram.associatedTokenAccount( - payer: payerAddress, - associatedToken: associatedTokenAccount.address, - owner: ownerAddress, - mint: mintAddress, - tokenProgramId: tokenProgramId, - ); - - final blockhash = await _getLatestBlockhash(Commitment.confirmed); - - final transaction = SolanaTransaction( - payerKey: payerAddress, - instructions: [createAssociatedTokenAccount], - recentBlockhash: blockhash, - type: TransactionType.v0, - ); - - final serializedTransaction = await _signTransactionInternal( - ownerPrivateKey: payerPrivateKey, - transaction: transaction, - ); - - await sendTransaction( - serializedTransaction: serializedTransaction, - commitment: Commitment.confirmed, - ); - - // Wait for confirmation - await Future.delayed(const Duration(seconds: 2)); - - return associatedTokenAccount; - } - - Future _signSPLTokenTransaction({ - required int tokenDecimals, - required String tokenMint, - required double inputAmount, - required String destinationAddress, - required SolanaPrivateKey ownerPrivateKey, - required Commitment commitment, - required double solBalance, - }) async { - final mintAddress = SolAddress(tokenMint); - - // Input by the user - final amount = (inputAmount * math.pow(10, tokenDecimals)).toInt(); - - final tokenProgramId = await _getTokenProgramId(mintAddress); - - ProgramDerivedAddress? associatedSenderAccount; - SolAddress senderTokenProgramId = tokenProgramId; - - try { - associatedSenderAccount = AssociatedTokenAccountProgramUtils.associatedTokenAccount( - mint: mintAddress, - owner: ownerPrivateKey.publicKey().toAddress(), - tokenProgramId: tokenProgramId, - ); - - // Verify the account exists and get the actual program ID that owns it - final accountInfo = await _provider!.request( - SolanaRPCGetAccountInfo( - account: associatedSenderAccount.address, - commitment: Commitment.confirmed, - ), - ); - - if (accountInfo != null) { - senderTokenProgramId = accountInfo.owner; - } else { - associatedSenderAccount = null; - } - } catch (e) { - associatedSenderAccount = null; - } - - // If account doesn't exist with detected program ID, try standard token program as fallback - if (associatedSenderAccount == null && - tokenProgramId.address != SPLTokenProgramConst.tokenProgramId.address) { - try { - associatedSenderAccount = AssociatedTokenAccountProgramUtils.associatedTokenAccount( - mint: mintAddress, - owner: ownerPrivateKey.publicKey().toAddress(), - tokenProgramId: SPLTokenProgramConst.tokenProgramId, - ); - - final accountInfo = await _provider!.request( - SolanaRPCGetAccountInfo( - account: associatedSenderAccount.address, - commitment: Commitment.confirmed, - ), - ); - - if (accountInfo != null) { - senderTokenProgramId = accountInfo.owner; - } else { - associatedSenderAccount = null; - } - } catch (_) { - associatedSenderAccount = null; - } - } - - if (associatedSenderAccount == null) { - throw SolanaNoAssociatedTokenAccountException( - ownerPrivateKey.publicKey().toAddress().address, - mintAddress.address, - ); - } - - // Get or create recipient account using the sender's token program ID - // This ensures both accounts use the same program - ProgramDerivedAddress? associatedRecipientAccount; - try { - // First, try to get/create with the sender's actual program ID - final recipientPDA = AssociatedTokenAccountProgramUtils.associatedTokenAccount( - mint: mintAddress, - owner: SolAddress(destinationAddress), - tokenProgramId: senderTokenProgramId, - ); - - // Check if account exists with correct program - SolanaAccountInfo? recipientInfo; - try { - recipientInfo = await _provider!.request( - SolanaRPCGetAccountInfo( - account: recipientPDA.address, - commitment: Commitment.confirmed, - ), - ); - } catch (_) { - recipientInfo = null; - } - - if (recipientInfo != null && recipientInfo.owner.address == senderTokenProgramId.address) { - associatedRecipientAccount = recipientPDA; - } else { - // Create the account with the correct program ID - final createATA = AssociatedTokenAccountProgram.associatedTokenAccount( - payer: ownerPrivateKey.publicKey().toAddress(), - associatedToken: recipientPDA.address, - owner: SolAddress(destinationAddress), - mint: mintAddress, - tokenProgramId: senderTokenProgramId, - ); - - final blockhash = await _getLatestBlockhash(Commitment.confirmed); - final createTransaction = SolanaTransaction( - payerKey: ownerPrivateKey.publicKey().toAddress(), - instructions: [createATA], - recentBlockhash: blockhash, - type: TransactionType.v0, - ); - - final serializedCreateTx = await _signTransactionInternal( - ownerPrivateKey: ownerPrivateKey, - transaction: createTransaction, - ); - - await sendTransaction( - serializedTransaction: serializedCreateTx, - commitment: Commitment.confirmed, - ); - - await Future.delayed(const Duration(seconds: 2)); - associatedRecipientAccount = recipientPDA; - } - } catch (e) { - throw SolanaCreateAssociatedTokenAccountException(e.toString()); - } - - // Create transferChecked instruction with the correct token program ID - final transferInstructions = _createTransferCheckedInstruction( - tokenProgramId: senderTokenProgramId, - source: associatedSenderAccount.address, - destination: associatedRecipientAccount.address, - mint: mintAddress, - owner: ownerPrivateKey.publicKey().toAddress(), - amount: BigInt.from(amount), - decimals: tokenDecimals, - ); - - final latestBlockHash = await _getLatestBlockhash(commitment); - - final transaction = SolanaTransaction( - payerKey: ownerPrivateKey.publicKey().toAddress(), - instructions: [transferInstructions], - recentBlockhash: latestBlockHash, - ); - - final message = await _getMessageForSPLTokenTransaction( - ownerAddress: ownerPrivateKey.publicKey().toAddress(), - tokenDecimals: tokenDecimals, - mintAddress: mintAddress, - destinationAddress: associatedRecipientAccount.address, - sourceAccount: associatedSenderAccount.address, - amount: amount, - commitment: commitment, - tokenProgramId: tokenProgramId, - ); - - final fee = await _getFeeFromCompiledMessage(message, commitment); - - bool hasSufficientFundsLeft = await hasSufficientFundsLeftForRent( - inputAmount: 0, - fee: fee, - solBalance: solBalance, - ); - - if (!hasSufficientFundsLeft) { - throw SolanaSignSPLTokenTransactionRentException(); - } - - final serializedTransaction = await _signTransactionInternal( - ownerPrivateKey: ownerPrivateKey, - transaction: transaction, - ); - - sendTx() async => await sendTransaction( - serializedTransaction: serializedTransaction, - commitment: commitment, - ); - - final pendingTransaction = PendingSolanaTransaction( - amount: inputAmount, - serializedTransaction: serializedTransaction, - destinationAddress: destinationAddress, - sendTransaction: sendTx, - fee: fee, - ); - return pendingTransaction; - } - - Future _signTransactionInternal({ - required SolanaPrivateKey ownerPrivateKey, - required SolanaTransaction transaction, - }) async { - /// Sign the transaction with the owner's private key. - final ownerSignature = ownerPrivateKey.sign(transaction.serializeMessage()); - - transaction.addSignature(ownerPrivateKey.publicKey().toAddress(), ownerSignature); - - /// Serialize the transaction. - final serializedTransaction = transaction.serializeString(); - - return serializedTransaction; - } - - Future sendTransaction({ - required String serializedTransaction, - required Commitment commitment, - }) async { - try { - /// Send the transaction to the Solana network. - final signature = await _provider!.request( - SolanaRPCSendTransaction( - encodedTransaction: serializedTransaction, - commitment: commitment, - ), - ); - return signature; - } catch (e) { - throw Exception(e); - } - } - - Future getIconImageFromTokenUri(String uri) async { - if (uri.isEmpty || uri == '…') return null; - - try { - final client = ProxyWrapper().getHttpIOClient(); - final response = await client.get(Uri.parse(uri)); - - final jsonResponse = json.decode(response.body) as Map; - - if (response.statusCode >= 200 && response.statusCode < 300) { - return jsonResponse['image']; - } else { - return null; - } - } catch (e) { - printV('Error occurred while fetching token image: \n${e.toString()}'); - return null; - } - } - - Future> fetchWalletTokensFromMoralis( - String address, - ) async { - try { - if (secrets.moralisApiKey.isEmpty) { - printV('Moralis API key is empty, cannot fetch wallet tokens'); - return []; - } - - final uri = Uri.https( - 'solana-gateway.moralis.io', - '/account/mainnet/$address/tokens', - ); - - final response = await client.get( - uri, - headers: { - "Accept": "application/json", - "X-API-Key": secrets.moralisApiKey, - }, - ); - - if (response.statusCode < 200 || response.statusCode >= 300) { - printV( - 'Moralis Solana API returned status: ' - '${response.statusCode}', - ); - return []; - } - - final decodedResponse = jsonDecode(response.body) as List; - - final List tokens = []; - - for (final item in decodedResponse) { - final tokenData = item as Map; - - final amountStr = tokenData['amount'] as String? ?? '0'; - final amount = double.tryParse(amountStr) ?? 0.0; - - if (amount <= 0) continue; - - final mint = tokenData['mint'] as String? ?? ''; - if (mint.isEmpty) continue; - - final amountRaw = tokenData['amountRaw'] as String? ?? '0'; - - final decimals = tokenData['decimals'] as int? ?? 0; - - final associatedTokenAddress = tokenData['associatedTokenAddress'] as String? ?? ''; - - tokens.add( - MoralisSolanaTokenBalance( - mint: mint, - amount: amount, - amountRaw: amountRaw, - decimals: decimals, - associatedTokenAddress: associatedTokenAddress, - ), - ); - } - - return tokens; - } catch (e) { - printV('Error fetching wallet tokens from Moralis: ${e.toString()}'); - return []; - } - } -} - -class MoralisSolanaTokenBalance { - final String mint; - final double amount; - final String amountRaw; - final int decimals; - final String associatedTokenAddress; - - const MoralisSolanaTokenBalance({ - required this.mint, - required this.amount, - required this.amountRaw, - required this.decimals, - required this.associatedTokenAddress, - }); -} diff --git a/cw_solana/lib/solana_exceptions.dart b/cw_solana/lib/solana_exceptions.dart deleted file mode 100644 index 96ba0bb6..00000000 --- a/cw_solana/lib/solana_exceptions.dart +++ /dev/null @@ -1,38 +0,0 @@ -import 'package:cw_core/crypto_currency.dart'; -import 'package:cw_core/exceptions.dart'; - -class SolanaTransactionCreationException implements Exception { - final String exceptionMessage; - - SolanaTransactionCreationException(CryptoCurrency currency) - : exceptionMessage = 'Error creating ${currency.title} transaction.'; - - @override - String toString() => exceptionMessage; -} - -class SolanaTransactionWrongBalanceException implements Exception { - final String exceptionMessage; - - SolanaTransactionWrongBalanceException(CryptoCurrency currency) - : exceptionMessage = 'Wrong balance. Not enough ${currency.title} on your balance.'; - - @override - String toString() => exceptionMessage; -} - -class SolanaSignNativeTokenTransactionRentException - extends SignNativeTokenTransactionRentException {} - -class SolanaCreateAssociatedTokenAccountException extends CreateAssociatedTokenAccountException { - SolanaCreateAssociatedTokenAccountException(super.errorMessage); -} - -class SolanaSignSPLTokenTransactionRentException extends SignSPLTokenTransactionRentException {} - -class SolanaNoAssociatedTokenAccountException extends NoAssociatedTokenAccountException { - SolanaNoAssociatedTokenAccountException(this.account, this.mint); - - final String account; - final String mint; -} diff --git a/cw_solana/lib/solana_mnemonics.dart b/cw_solana/lib/solana_mnemonics.dart deleted file mode 100644 index 21cbb613..00000000 --- a/cw_solana/lib/solana_mnemonics.dart +++ /dev/null @@ -1,2058 +0,0 @@ -class SolanaMnemonicIsIncorrectException implements Exception { - @override - String toString() => - 'Solana mnemonic has incorrect format. Mnemonic should contain 12 or 24 words separated by space.'; -} - -class SolanaMnemonics { - static const englishWordlist = [ - 'abandon', - 'ability', - 'able', - 'about', - 'above', - 'absent', - 'absorb', - 'abstract', - 'absurd', - 'abuse', - 'access', - 'accident', - 'account', - 'accuse', - 'achieve', - 'acid', - 'acoustic', - 'acquire', - 'across', - 'act', - 'action', - 'actor', - 'actress', - 'actual', - 'adapt', - 'add', - 'addict', - 'address', - 'adjust', - 'admit', - 'adult', - 'advance', - 'advice', - 'aerobic', - 'affair', - 'afford', - 'afraid', - 'again', - 'age', - 'agent', - 'agree', - 'ahead', - 'aim', - 'air', - 'airport', - 'aisle', - 'alarm', - 'album', - 'alcohol', - 'alert', - 'alien', - 'all', - 'alley', - 'allow', - 'almost', - 'alone', - 'alpha', - 'already', - 'also', - 'alter', - 'always', - 'amateur', - 'amazing', - 'among', - 'amount', - 'amused', - 'analyst', - 'anchor', - 'ancient', - 'anger', - 'angle', - 'angry', - 'animal', - 'ankle', - 'announce', - 'annual', - 'another', - 'answer', - 'antenna', - 'antique', - 'anxiety', - 'any', - 'apart', - 'apology', - 'appear', - 'apple', - 'approve', - 'april', - 'arch', - 'arctic', - 'area', - 'arena', - 'argue', - 'arm', - 'armed', - 'armor', - 'army', - 'around', - 'arrange', - 'arrest', - 'arrive', - 'arrow', - 'art', - 'artefact', - 'artist', - 'artwork', - 'ask', - 'aspect', - 'assault', - 'asset', - 'assist', - 'assume', - 'asthma', - 'athlete', - 'atom', - 'attack', - 'attend', - 'attitude', - 'attract', - 'auction', - 'audit', - 'august', - 'aunt', - 'author', - 'auto', - 'autumn', - 'average', - 'avocado', - 'avoid', - 'awake', - 'aware', - 'away', - 'awesome', - 'awful', - 'awkward', - 'axis', - 'baby', - 'bachelor', - 'bacon', - 'badge', - 'bag', - 'balance', - 'balcony', - 'ball', - 'bamboo', - 'banana', - 'banner', - 'bar', - 'barely', - 'bargain', - 'barrel', - 'base', - 'basic', - 'basket', - 'battle', - 'beach', - 'bean', - 'beauty', - 'because', - 'become', - 'beef', - 'before', - 'begin', - 'behave', - 'behind', - 'believe', - 'below', - 'belt', - 'bench', - 'benefit', - 'best', - 'betray', - 'better', - 'between', - 'beyond', - 'bicycle', - 'bid', - 'bike', - 'bind', - 'biology', - 'bird', - 'birth', - 'bitter', - 'black', - 'blade', - 'blame', - 'blanket', - 'blast', - 'bleak', - 'bless', - 'blind', - 'blood', - 'blossom', - 'blouse', - 'blue', - 'blur', - 'blush', - 'board', - 'boat', - 'body', - 'boil', - 'bomb', - 'bone', - 'bonus', - 'book', - 'boost', - 'border', - 'boring', - 'borrow', - 'boss', - 'bottom', - 'bounce', - 'box', - 'boy', - 'bracket', - 'brain', - 'brand', - 'brass', - 'brave', - 'bread', - 'breeze', - 'brick', - 'bridge', - 'brief', - 'bright', - 'bring', - 'brisk', - 'broccoli', - 'broken', - 'bronze', - 'broom', - 'brother', - 'brown', - 'brush', - 'bubble', - 'buddy', - 'budget', - 'buffalo', - 'build', - 'bulb', - 'bulk', - 'bullet', - 'bundle', - 'bunker', - 'burden', - 'burger', - 'burst', - 'bus', - 'business', - 'busy', - 'butter', - 'buyer', - 'buzz', - 'cabbage', - 'cabin', - 'cable', - 'cactus', - 'cage', - 'cake', - 'call', - 'calm', - 'camera', - 'camp', - 'can', - 'canal', - 'cancel', - 'candy', - 'cannon', - 'canoe', - 'canvas', - 'canyon', - 'capable', - 'capital', - 'captain', - 'car', - 'carbon', - 'card', - 'cargo', - 'carpet', - 'carry', - 'cart', - 'case', - 'cash', - 'casino', - 'castle', - 'casual', - 'cat', - 'catalog', - 'catch', - 'category', - 'cattle', - 'caught', - 'cause', - 'caution', - 'cave', - 'ceiling', - 'celery', - 'cement', - 'census', - 'century', - 'cereal', - 'certain', - 'chair', - 'chalk', - 'champion', - 'change', - 'chaos', - 'chapter', - 'charge', - 'chase', - 'chat', - 'cheap', - 'check', - 'cheese', - 'chef', - 'cherry', - 'chest', - 'chicken', - 'chief', - 'child', - 'chimney', - 'choice', - 'choose', - 'chronic', - 'chuckle', - 'chunk', - 'churn', - 'cigar', - 'cinnamon', - 'circle', - 'citizen', - 'city', - 'civil', - 'claim', - 'clap', - 'clarify', - 'claw', - 'clay', - 'clean', - 'clerk', - 'clever', - 'click', - 'client', - 'cliff', - 'climb', - 'clinic', - 'clip', - 'clock', - 'clog', - 'close', - 'cloth', - 'cloud', - 'clown', - 'club', - 'clump', - 'cluster', - 'clutch', - 'coach', - 'coast', - 'coconut', - 'code', - 'coffee', - 'coil', - 'coin', - 'collect', - 'color', - 'column', - 'combine', - 'come', - 'comfort', - 'comic', - 'common', - 'company', - 'concert', - 'conduct', - 'confirm', - 'congress', - 'connect', - 'consider', - 'control', - 'convince', - 'cook', - 'cool', - 'copper', - 'copy', - 'coral', - 'core', - 'corn', - 'correct', - 'cost', - 'cotton', - 'couch', - 'country', - 'couple', - 'course', - 'cousin', - 'cover', - 'coyote', - 'crack', - 'cradle', - 'craft', - 'cram', - 'crane', - 'crash', - 'crater', - 'crawl', - 'crazy', - 'cream', - 'credit', - 'creek', - 'crew', - 'cricket', - 'crime', - 'crisp', - 'critic', - 'crop', - 'cross', - 'crouch', - 'crowd', - 'crucial', - 'cruel', - 'cruise', - 'crumble', - 'crunch', - 'crush', - 'cry', - 'crystal', - 'cube', - 'culture', - 'cup', - 'cupboard', - 'curious', - 'current', - 'curtain', - 'curve', - 'cushion', - 'custom', - 'cute', - 'cycle', - 'dad', - 'damage', - 'damp', - 'dance', - 'danger', - 'daring', - 'dash', - 'daughter', - 'dawn', - 'day', - 'deal', - 'debate', - 'debris', - 'decade', - 'december', - 'decide', - 'decline', - 'decorate', - 'decrease', - 'deer', - 'defense', - 'define', - 'defy', - 'degree', - 'delay', - 'deliver', - 'demand', - 'demise', - 'denial', - 'dentist', - 'deny', - 'depart', - 'depend', - 'deposit', - 'depth', - 'deputy', - 'derive', - 'describe', - 'desert', - 'design', - 'desk', - 'despair', - 'destroy', - 'detail', - 'detect', - 'develop', - 'device', - 'devote', - 'diagram', - 'dial', - 'diamond', - 'diary', - 'dice', - 'diesel', - 'diet', - 'differ', - 'digital', - 'dignity', - 'dilemma', - 'dinner', - 'dinosaur', - 'direct', - 'dirt', - 'disagree', - 'discover', - 'disease', - 'dish', - 'dismiss', - 'disorder', - 'display', - 'distance', - 'divert', - 'divide', - 'divorce', - 'dizzy', - 'doctor', - 'document', - 'dog', - 'doll', - 'dolphin', - 'domain', - 'donate', - 'donkey', - 'donor', - 'door', - 'dose', - 'double', - 'dove', - 'draft', - 'dragon', - 'drama', - 'drastic', - 'draw', - 'dream', - 'dress', - 'drift', - 'drill', - 'drink', - 'drip', - 'drive', - 'drop', - 'drum', - 'dry', - 'duck', - 'dumb', - 'dune', - 'during', - 'dust', - 'dutch', - 'duty', - 'dwarf', - 'dynamic', - 'eager', - 'eagle', - 'early', - 'earn', - 'earth', - 'easily', - 'east', - 'easy', - 'echo', - 'ecology', - 'economy', - 'edge', - 'edit', - 'educate', - 'effort', - 'egg', - 'eight', - 'either', - 'elbow', - 'elder', - 'electric', - 'elegant', - 'element', - 'elephant', - 'elevator', - 'elite', - 'else', - 'embark', - 'embody', - 'embrace', - 'emerge', - 'emotion', - 'employ', - 'empower', - 'empty', - 'enable', - 'enact', - 'end', - 'endless', - 'endorse', - 'enemy', - 'energy', - 'enforce', - 'engage', - 'engine', - 'enhance', - 'enjoy', - 'enlist', - 'enough', - 'enrich', - 'enroll', - 'ensure', - 'enter', - 'entire', - 'entry', - 'envelope', - 'episode', - 'equal', - 'equip', - 'era', - 'erase', - 'erode', - 'erosion', - 'error', - 'erupt', - 'escape', - 'essay', - 'essence', - 'estate', - 'eternal', - 'ethics', - 'evidence', - 'evil', - 'evoke', - 'evolve', - 'exact', - 'example', - 'excess', - 'exchange', - 'excite', - 'exclude', - 'excuse', - 'execute', - 'exercise', - 'exhaust', - 'exhibit', - 'exile', - 'exist', - 'exit', - 'exotic', - 'expand', - 'expect', - 'expire', - 'explain', - 'expose', - 'express', - 'extend', - 'extra', - 'eye', - 'eyebrow', - 'fabric', - 'face', - 'faculty', - 'fade', - 'faint', - 'faith', - 'fall', - 'false', - 'fame', - 'family', - 'famous', - 'fan', - 'fancy', - 'fantasy', - 'farm', - 'fashion', - 'fat', - 'fatal', - 'father', - 'fatigue', - 'fault', - 'favorite', - 'feature', - 'february', - 'federal', - 'fee', - 'feed', - 'feel', - 'female', - 'fence', - 'festival', - 'fetch', - 'fever', - 'few', - 'fiber', - 'fiction', - 'field', - 'figure', - 'file', - 'film', - 'filter', - 'final', - 'find', - 'fine', - 'finger', - 'finish', - 'fire', - 'firm', - 'first', - 'fiscal', - 'fish', - 'fit', - 'fitness', - 'fix', - 'flag', - 'flame', - 'flash', - 'flat', - 'flavor', - 'flee', - 'flight', - 'flip', - 'float', - 'flock', - 'floor', - 'flower', - 'fluid', - 'flush', - 'fly', - 'foam', - 'focus', - 'fog', - 'foil', - 'fold', - 'follow', - 'food', - 'foot', - 'force', - 'forest', - 'forget', - 'fork', - 'fortune', - 'forum', - 'forward', - 'fossil', - 'foster', - 'found', - 'fox', - 'fragile', - 'frame', - 'frequent', - 'fresh', - 'friend', - 'fringe', - 'frog', - 'front', - 'frost', - 'frown', - 'frozen', - 'fruit', - 'fuel', - 'fun', - 'funny', - 'furnace', - 'fury', - 'future', - 'gadget', - 'gain', - 'galaxy', - 'gallery', - 'game', - 'gap', - 'garage', - 'garbage', - 'garden', - 'garlic', - 'garment', - 'gas', - 'gasp', - 'gate', - 'gather', - 'gauge', - 'gaze', - 'general', - 'genius', - 'genre', - 'gentle', - 'genuine', - 'gesture', - 'ghost', - 'giant', - 'gift', - 'giggle', - 'ginger', - 'giraffe', - 'girl', - 'give', - 'glad', - 'glance', - 'glare', - 'glass', - 'glide', - 'glimpse', - 'globe', - 'gloom', - 'glory', - 'glove', - 'glow', - 'glue', - 'goat', - 'goddess', - 'gold', - 'good', - 'goose', - 'gorilla', - 'gospel', - 'gossip', - 'govern', - 'gown', - 'grab', - 'grace', - 'grain', - 'grant', - 'grape', - 'grass', - 'gravity', - 'great', - 'green', - 'grid', - 'grief', - 'grit', - 'grocery', - 'group', - 'grow', - 'grunt', - 'guard', - 'guess', - 'guide', - 'guilt', - 'guitar', - 'gun', - 'gym', - 'habit', - 'hair', - 'half', - 'hammer', - 'hamster', - 'hand', - 'happy', - 'harbor', - 'hard', - 'harsh', - 'harvest', - 'hat', - 'have', - 'hawk', - 'hazard', - 'head', - 'health', - 'heart', - 'heavy', - 'hedgehog', - 'height', - 'hello', - 'helmet', - 'help', - 'hen', - 'hero', - 'hidden', - 'high', - 'hill', - 'hint', - 'hip', - 'hire', - 'history', - 'hobby', - 'hockey', - 'hold', - 'hole', - 'holiday', - 'hollow', - 'home', - 'honey', - 'hood', - 'hope', - 'horn', - 'horror', - 'horse', - 'hospital', - 'host', - 'hotel', - 'hour', - 'hover', - 'hub', - 'huge', - 'human', - 'humble', - 'humor', - 'hundred', - 'hungry', - 'hunt', - 'hurdle', - 'hurry', - 'hurt', - 'husband', - 'hybrid', - 'ice', - 'icon', - 'idea', - 'identify', - 'idle', - 'ignore', - 'ill', - 'illegal', - 'illness', - 'image', - 'imitate', - 'immense', - 'immune', - 'impact', - 'impose', - 'improve', - 'impulse', - 'inch', - 'include', - 'income', - 'increase', - 'index', - 'indicate', - 'indoor', - 'industry', - 'infant', - 'inflict', - 'inform', - 'inhale', - 'inherit', - 'initial', - 'inject', - 'injury', - 'inmate', - 'inner', - 'innocent', - 'input', - 'inquiry', - 'insane', - 'insect', - 'inside', - 'inspire', - 'install', - 'intact', - 'interest', - 'into', - 'invest', - 'invite', - 'involve', - 'iron', - 'island', - 'isolate', - 'issue', - 'item', - 'ivory', - 'jacket', - 'jaguar', - 'jar', - 'jazz', - 'jealous', - 'jeans', - 'jelly', - 'jewel', - 'job', - 'join', - 'joke', - 'journey', - 'joy', - 'judge', - 'juice', - 'jump', - 'jungle', - 'junior', - 'junk', - 'just', - 'kangaroo', - 'keen', - 'keep', - 'ketchup', - 'key', - 'kick', - 'kid', - 'kidney', - 'kind', - 'kingdom', - 'kiss', - 'kit', - 'kitchen', - 'kite', - 'kitten', - 'kiwi', - 'knee', - 'knife', - 'knock', - 'know', - 'lab', - 'label', - 'labor', - 'ladder', - 'lady', - 'lake', - 'lamp', - 'language', - 'laptop', - 'large', - 'later', - 'latin', - 'laugh', - 'laundry', - 'lava', - 'law', - 'lawn', - 'lawsuit', - 'layer', - 'lazy', - 'leader', - 'leaf', - 'learn', - 'leave', - 'lecture', - 'left', - 'leg', - 'legal', - 'legend', - 'leisure', - 'lemon', - 'lend', - 'length', - 'lens', - 'leopard', - 'lesson', - 'letter', - 'level', - 'liar', - 'liberty', - 'library', - 'license', - 'life', - 'lift', - 'light', - 'like', - 'limb', - 'limit', - 'link', - 'lion', - 'liquid', - 'list', - 'little', - 'live', - 'lizard', - 'load', - 'loan', - 'lobster', - 'local', - 'lock', - 'logic', - 'lonely', - 'long', - 'loop', - 'lottery', - 'loud', - 'lounge', - 'love', - 'loyal', - 'lucky', - 'luggage', - 'lumber', - 'lunar', - 'lunch', - 'luxury', - 'lyrics', - 'machine', - 'mad', - 'magic', - 'magnet', - 'maid', - 'mail', - 'main', - 'major', - 'make', - 'mammal', - 'man', - 'manage', - 'mandate', - 'mango', - 'mansion', - 'manual', - 'maple', - 'marble', - 'march', - 'margin', - 'marine', - 'market', - 'marriage', - 'mask', - 'mass', - 'master', - 'match', - 'material', - 'math', - 'matrix', - 'matter', - 'maximum', - 'maze', - 'meadow', - 'mean', - 'measure', - 'meat', - 'mechanic', - 'medal', - 'media', - 'melody', - 'melt', - 'member', - 'memory', - 'mention', - 'menu', - 'mercy', - 'merge', - 'merit', - 'merry', - 'mesh', - 'message', - 'metal', - 'method', - 'middle', - 'midnight', - 'milk', - 'million', - 'mimic', - 'mind', - 'minimum', - 'minor', - 'minute', - 'miracle', - 'mirror', - 'misery', - 'miss', - 'mistake', - 'mix', - 'mixed', - 'mixture', - 'mobile', - 'model', - 'modify', - 'mom', - 'moment', - 'monitor', - 'monkey', - 'monster', - 'month', - 'moon', - 'moral', - 'more', - 'morning', - 'mosquito', - 'mother', - 'motion', - 'motor', - 'mountain', - 'mouse', - 'move', - 'movie', - 'much', - 'muffin', - 'mule', - 'multiply', - 'muscle', - 'museum', - 'mushroom', - 'music', - 'must', - 'mutual', - 'myself', - 'mystery', - 'myth', - 'naive', - 'name', - 'napkin', - 'narrow', - 'nasty', - 'nation', - 'nature', - 'near', - 'neck', - 'need', - 'negative', - 'neglect', - 'neither', - 'nephew', - 'nerve', - 'nest', - 'net', - 'network', - 'neutral', - 'never', - 'news', - 'next', - 'nice', - 'night', - 'noble', - 'noise', - 'nominee', - 'noodle', - 'normal', - 'north', - 'nose', - 'notable', - 'note', - 'nothing', - 'notice', - 'novel', - 'now', - 'nuclear', - 'number', - 'nurse', - 'nut', - 'oak', - 'obey', - 'object', - 'oblige', - 'obscure', - 'observe', - 'obtain', - 'obvious', - 'occur', - 'ocean', - 'october', - 'odor', - 'off', - 'offer', - 'office', - 'often', - 'oil', - 'okay', - 'old', - 'olive', - 'olympic', - 'omit', - 'once', - 'one', - 'onion', - 'online', - 'only', - 'open', - 'opera', - 'opinion', - 'oppose', - 'option', - 'orange', - 'orbit', - 'orchard', - 'order', - 'ordinary', - 'organ', - 'orient', - 'original', - 'orphan', - 'ostrich', - 'other', - 'outdoor', - 'outer', - 'output', - 'outside', - 'oval', - 'oven', - 'over', - 'own', - 'owner', - 'oxygen', - 'oyster', - 'ozone', - 'pact', - 'paddle', - 'page', - 'pair', - 'palace', - 'palm', - 'panda', - 'panel', - 'panic', - 'panther', - 'paper', - 'parade', - 'parent', - 'park', - 'parrot', - 'party', - 'pass', - 'patch', - 'path', - 'patient', - 'patrol', - 'pattern', - 'pause', - 'pave', - 'payment', - 'peace', - 'peanut', - 'pear', - 'peasant', - 'pelican', - 'pen', - 'penalty', - 'pencil', - 'people', - 'pepper', - 'perfect', - 'permit', - 'person', - 'pet', - 'phone', - 'photo', - 'phrase', - 'physical', - 'piano', - 'picnic', - 'picture', - 'piece', - 'pig', - 'pigeon', - 'pill', - 'pilot', - 'pink', - 'pioneer', - 'pipe', - 'pistol', - 'pitch', - 'pizza', - 'place', - 'planet', - 'plastic', - 'plate', - 'play', - 'please', - 'pledge', - 'pluck', - 'plug', - 'plunge', - 'poem', - 'poet', - 'point', - 'polar', - 'pole', - 'police', - 'pond', - 'pony', - 'pool', - 'popular', - 'portion', - 'position', - 'possible', - 'post', - 'potato', - 'pottery', - 'poverty', - 'powder', - 'power', - 'practice', - 'praise', - 'predict', - 'prefer', - 'prepare', - 'present', - 'pretty', - 'prevent', - 'price', - 'pride', - 'primary', - 'print', - 'priority', - 'prison', - 'private', - 'prize', - 'problem', - 'process', - 'produce', - 'profit', - 'program', - 'project', - 'promote', - 'proof', - 'property', - 'prosper', - 'protect', - 'proud', - 'provide', - 'public', - 'pudding', - 'pull', - 'pulp', - 'pulse', - 'pumpkin', - 'punch', - 'pupil', - 'puppy', - 'purchase', - 'purity', - 'purpose', - 'purse', - 'push', - 'put', - 'puzzle', - 'pyramid', - 'quality', - 'quantum', - 'quarter', - 'question', - 'quick', - 'quit', - 'quiz', - 'quote', - 'rabbit', - 'raccoon', - 'race', - 'rack', - 'radar', - 'radio', - 'rail', - 'rain', - 'raise', - 'rally', - 'ramp', - 'ranch', - 'random', - 'range', - 'rapid', - 'rare', - 'rate', - 'rather', - 'raven', - 'raw', - 'razor', - 'ready', - 'real', - 'reason', - 'rebel', - 'rebuild', - 'recall', - 'receive', - 'recipe', - 'record', - 'recycle', - 'reduce', - 'reflect', - 'reform', - 'refuse', - 'region', - 'regret', - 'regular', - 'reject', - 'relax', - 'release', - 'relief', - 'rely', - 'remain', - 'remember', - 'remind', - 'remove', - 'render', - 'renew', - 'rent', - 'reopen', - 'repair', - 'repeat', - 'replace', - 'report', - 'require', - 'rescue', - 'resemble', - 'resist', - 'resource', - 'response', - 'result', - 'retire', - 'retreat', - 'return', - 'reunion', - 'reveal', - 'review', - 'reward', - 'rhythm', - 'rib', - 'ribbon', - 'rice', - 'rich', - 'ride', - 'ridge', - 'rifle', - 'right', - 'rigid', - 'ring', - 'riot', - 'ripple', - 'risk', - 'ritual', - 'rival', - 'river', - 'road', - 'roast', - 'robot', - 'robust', - 'rocket', - 'romance', - 'roof', - 'rookie', - 'room', - 'rose', - 'rotate', - 'rough', - 'round', - 'route', - 'royal', - 'rubber', - 'rude', - 'rug', - 'rule', - 'run', - 'runway', - 'rural', - 'sad', - 'saddle', - 'sadness', - 'safe', - 'sail', - 'salad', - 'salmon', - 'salon', - 'salt', - 'salute', - 'same', - 'sample', - 'sand', - 'satisfy', - 'satoshi', - 'sauce', - 'sausage', - 'save', - 'say', - 'scale', - 'scan', - 'scare', - 'scatter', - 'scene', - 'scheme', - 'school', - 'science', - 'scissors', - 'scorpion', - 'scout', - 'scrap', - 'screen', - 'script', - 'scrub', - 'sea', - 'search', - 'season', - 'seat', - 'second', - 'secret', - 'section', - 'security', - 'seed', - 'seek', - 'segment', - 'select', - 'sell', - 'seminar', - 'senior', - 'sense', - 'sentence', - 'series', - 'service', - 'session', - 'settle', - 'setup', - 'seven', - 'shadow', - 'shaft', - 'shallow', - 'share', - 'shed', - 'shell', - 'sheriff', - 'shield', - 'shift', - 'shine', - 'ship', - 'shiver', - 'shock', - 'shoe', - 'shoot', - 'shop', - 'short', - 'shoulder', - 'shove', - 'shrimp', - 'shrug', - 'shuffle', - 'shy', - 'sibling', - 'sick', - 'side', - 'siege', - 'sight', - 'sign', - 'silent', - 'silk', - 'silly', - 'silver', - 'similar', - 'simple', - 'since', - 'sing', - 'siren', - 'sister', - 'situate', - 'six', - 'size', - 'skate', - 'sketch', - 'ski', - 'skill', - 'skin', - 'skirt', - 'skull', - 'slab', - 'slam', - 'sleep', - 'slender', - 'slice', - 'slide', - 'slight', - 'slim', - 'slogan', - 'slot', - 'slow', - 'slush', - 'small', - 'smart', - 'smile', - 'smoke', - 'smooth', - 'snack', - 'snake', - 'snap', - 'sniff', - 'snow', - 'soap', - 'soccer', - 'social', - 'sock', - 'soda', - 'soft', - 'solar', - 'soldier', - 'solid', - 'solution', - 'solve', - 'someone', - 'song', - 'soon', - 'sorry', - 'sort', - 'soul', - 'sound', - 'soup', - 'source', - 'south', - 'space', - 'spare', - 'spatial', - 'spawn', - 'speak', - 'special', - 'speed', - 'spell', - 'spend', - 'sphere', - 'spice', - 'spider', - 'spike', - 'spin', - 'spirit', - 'split', - 'spoil', - 'sponsor', - 'spoon', - 'sport', - 'spot', - 'spray', - 'spread', - 'spring', - 'spy', - 'square', - 'squeeze', - 'squirrel', - 'stable', - 'stadium', - 'staff', - 'stage', - 'stairs', - 'stamp', - 'stand', - 'start', - 'state', - 'stay', - 'steak', - 'steel', - 'stem', - 'step', - 'stereo', - 'stick', - 'still', - 'sting', - 'stock', - 'stomach', - 'stone', - 'stool', - 'story', - 'stove', - 'strategy', - 'street', - 'strike', - 'strong', - 'struggle', - 'student', - 'stuff', - 'stumble', - 'style', - 'subject', - 'submit', - 'subway', - 'success', - 'such', - 'sudden', - 'suffer', - 'sugar', - 'suggest', - 'suit', - 'summer', - 'sun', - 'sunny', - 'sunset', - 'super', - 'supply', - 'supreme', - 'sure', - 'surface', - 'surge', - 'surprise', - 'surround', - 'survey', - 'suspect', - 'sustain', - 'swallow', - 'swamp', - 'swap', - 'swarm', - 'swear', - 'sweet', - 'swift', - 'swim', - 'swing', - 'switch', - 'sword', - 'symbol', - 'symptom', - 'syrup', - 'system', - 'table', - 'tackle', - 'tag', - 'tail', - 'talent', - 'talk', - 'tank', - 'tape', - 'target', - 'task', - 'taste', - 'tattoo', - 'taxi', - 'teach', - 'team', - 'tell', - 'ten', - 'tenant', - 'tennis', - 'tent', - 'term', - 'test', - 'text', - 'thank', - 'that', - 'theme', - 'then', - 'theory', - 'there', - 'they', - 'thing', - 'this', - 'thought', - 'three', - 'thrive', - 'throw', - 'thumb', - 'thunder', - 'ticket', - 'tide', - 'tiger', - 'tilt', - 'timber', - 'time', - 'tiny', - 'tip', - 'tired', - 'tissue', - 'title', - 'toast', - 'tobacco', - 'today', - 'toddler', - 'toe', - 'together', - 'toilet', - 'token', - 'tomato', - 'tomorrow', - 'tone', - 'tongue', - 'tonight', - 'tool', - 'tooth', - 'top', - 'topic', - 'topple', - 'torch', - 'tornado', - 'tortoise', - 'toss', - 'total', - 'tourist', - 'toward', - 'tower', - 'town', - 'toy', - 'track', - 'trade', - 'traffic', - 'tragic', - 'train', - 'transfer', - 'trap', - 'trash', - 'travel', - 'tray', - 'treat', - 'tree', - 'trend', - 'trial', - 'tribe', - 'trick', - 'trigger', - 'trim', - 'trip', - 'trophy', - 'trouble', - 'truck', - 'true', - 'truly', - 'trumpet', - 'trust', - 'truth', - 'try', - 'tube', - 'tuition', - 'tumble', - 'tuna', - 'tunnel', - 'turkey', - 'turn', - 'turtle', - 'twelve', - 'twenty', - 'twice', - 'twin', - 'twist', - 'two', - 'type', - 'typical', - 'ugly', - 'umbrella', - 'unable', - 'unaware', - 'uncle', - 'uncover', - 'under', - 'undo', - 'unfair', - 'unfold', - 'unhappy', - 'uniform', - 'unique', - 'unit', - 'universe', - 'unknown', - 'unlock', - 'until', - 'unusual', - 'unveil', - 'update', - 'upgrade', - 'uphold', - 'upon', - 'upper', - 'upset', - 'urban', - 'urge', - 'usage', - 'use', - 'used', - 'useful', - 'useless', - 'usual', - 'utility', - 'vacant', - 'vacuum', - 'vague', - 'valid', - 'valley', - 'valve', - 'van', - 'vanish', - 'vapor', - 'various', - 'vast', - 'vault', - 'vehicle', - 'velvet', - 'vendor', - 'venture', - 'venue', - 'verb', - 'verify', - 'version', - 'very', - 'vessel', - 'veteran', - 'viable', - 'vibrant', - 'vicious', - 'victory', - 'video', - 'view', - 'village', - 'vintage', - 'violin', - 'virtual', - 'virus', - 'visa', - 'visit', - 'visual', - 'vital', - 'vivid', - 'vocal', - 'voice', - 'void', - 'volcano', - 'volume', - 'vote', - 'voyage', - 'wage', - 'wagon', - 'wait', - 'walk', - 'wall', - 'walnut', - 'want', - 'warfare', - 'warm', - 'warrior', - 'wash', - 'wasp', - 'waste', - 'water', - 'wave', - 'way', - 'wealth', - 'weapon', - 'wear', - 'weasel', - 'weather', - 'web', - 'wedding', - 'weekend', - 'weird', - 'welcome', - 'west', - 'wet', - 'whale', - 'what', - 'wheat', - 'wheel', - 'when', - 'where', - 'whip', - 'whisper', - 'wide', - 'width', - 'wife', - 'wild', - 'will', - 'win', - 'window', - 'wine', - 'wing', - 'wink', - 'winner', - 'winter', - 'wire', - 'wisdom', - 'wise', - 'wish', - 'witness', - 'wolf', - 'woman', - 'wonder', - 'wood', - 'wool', - 'word', - 'work', - 'world', - 'worry', - 'worth', - 'wrap', - 'wreck', - 'wrestle', - 'wrist', - 'write', - 'wrong', - 'yard', - 'year', - 'yellow', - 'you', - 'young', - 'youth', - 'zebra', - 'zero', - 'zone', - 'zoo' - ]; -} diff --git a/cw_solana/lib/solana_transaction_credentials.dart b/cw_solana/lib/solana_transaction_credentials.dart deleted file mode 100644 index bd0c97f0..00000000 --- a/cw_solana/lib/solana_transaction_credentials.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:cw_core/crypto_currency.dart'; -import 'package:cw_core/output_info.dart'; - -class SolanaTransactionCredentials { - SolanaTransactionCredentials( - this.outputs, { - required this.currency, - }); - - final List outputs; - final CryptoCurrency currency; -} diff --git a/cw_solana/lib/solana_transaction_history.dart b/cw_solana/lib/solana_transaction_history.dart deleted file mode 100644 index 62b9db8f..00000000 --- a/cw_solana/lib/solana_transaction_history.dart +++ /dev/null @@ -1,84 +0,0 @@ -import 'dart:convert'; -import 'dart:core'; -import 'package:cw_core/encryption_file_utils.dart'; -import 'package:cw_core/pathForWallet.dart'; -import 'package:cw_core/utils/print_verbose.dart'; -import 'package:cw_core/wallet_info.dart'; -import 'package:cw_solana/solana_transaction_info.dart'; -import 'package:mobx/mobx.dart'; -import 'package:cw_core/transaction_history.dart'; - -part 'solana_transaction_history.g.dart'; - -const transactionsHistoryFileName = 'solana_transactions.json'; - -class SolanaTransactionHistory = SolanaTransactionHistoryBase with _$SolanaTransactionHistory; - -abstract class SolanaTransactionHistoryBase extends TransactionHistoryBase - with Store { - SolanaTransactionHistoryBase( - {required this.walletInfo, required String password, required this.encryptionFileUtils}) - : _password = password { - transactions = ObservableMap(); - } - - final WalletInfo walletInfo; - final EncryptionFileUtils encryptionFileUtils; - String _password; - - Future init() async { - clear(); - await _load(); - } - - @override - Future save() async { - try { - final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type); - final path = '$dirPath/$transactionsHistoryFileName'; - final transactionMaps = transactions.map((key, value) => MapEntry(key, value.toJson())); - final data = json.encode({'transactions': transactionMaps}); - await encryptionFileUtils.write(path: path, password: _password, data: data); - } catch (e, s) { - printV('Error while saving solana transaction history: ${e.toString()}'); - printV(s); - } - } - - @override - void addOne(SolanaTransactionInfo transaction) => transactions[transaction.id] = transaction; - - @override - void addMany(Map transactions) => - this.transactions.addAll(transactions); - - Future> _read() async { - final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type); - final path = '$dirPath/$transactionsHistoryFileName'; - final content = await encryptionFileUtils.read(path: path, password: _password); - if (content.isEmpty) { - return {}; - } - return json.decode(content) as Map; - } - - Future _load() async { - try { - final content = await _read(); - final txs = content['transactions'] as Map? ?? {}; - - txs.entries.forEach((entry) { - final val = entry.value; - - if (val is Map) { - final tx = SolanaTransactionInfo.fromJson(val); - _update(tx); - } - }); - } catch (e) { - printV(e); - } - } - - void _update(SolanaTransactionInfo transaction) => transactions[transaction.id] = transaction; -} diff --git a/cw_solana/lib/solana_transaction_info.dart b/cw_solana/lib/solana_transaction_info.dart deleted file mode 100644 index f51c55da..00000000 --- a/cw_solana/lib/solana_transaction_info.dart +++ /dev/null @@ -1,77 +0,0 @@ -import 'package:cw_core/format_amount.dart'; -import 'package:cw_core/transaction_direction.dart'; -import 'package:cw_core/transaction_info.dart'; - -class SolanaTransactionInfo extends TransactionInfo { - SolanaTransactionInfo({ - required this.id, - required this.blockTime, - required this.to, - required this.from, - required this.direction, - required this.solAmount, - this.tokenSymbol = "SOL", - required this.isPending, - required this.txFee, - }) : amount = solAmount.toInt(); - - final String id; - final String? to; - final String? from; - final int amount; - final bool isPending; - final double solAmount; - final String tokenSymbol; - final DateTime blockTime; - final double txFee; - final TransactionDirection direction; - - String? _fiatAmount; - - @override - DateTime get date => blockTime; - - @override - String amountFormatted() { - String stringBalance = solAmount.toString(); - if (stringBalance.toString().length >= 12) { - stringBalance = stringBalance.substring(0, 12); - } - return '$stringBalance $tokenSymbol'; - } - - @override - String fiatAmount() => _fiatAmount ?? ''; - - @override - void changeFiatAmount(String amount) => _fiatAmount = formatAmount(amount); - - @override - String feeFormatted() => '${txFee.toString()} SOL'; - - factory SolanaTransactionInfo.fromJson(Map data) { - return SolanaTransactionInfo( - id: data['id'] as String, - solAmount: data['solAmount'], - direction: parseTransactionDirectionFromInt(data['direction'] as int), - blockTime: DateTime.fromMillisecondsSinceEpoch(data['blockTime'] as int), - isPending: data['isPending'] as bool, - tokenSymbol: data['tokenSymbol'] as String, - to: data['to'], - from: data['from'], - txFee: data['txFee'], - ); - } - - Map toJson() => { - 'id': id, - 'solAmount': solAmount, - 'direction': direction.index, - 'blockTime': blockTime.millisecondsSinceEpoch, - 'isPending': isPending, - 'tokenSymbol': tokenSymbol, - 'to': to, - 'from': from, - 'txFee': txFee, - }; -} diff --git a/cw_solana/lib/solana_transaction_model.dart b/cw_solana/lib/solana_transaction_model.dart deleted file mode 100644 index c16c4925..00000000 --- a/cw_solana/lib/solana_transaction_model.dart +++ /dev/null @@ -1,47 +0,0 @@ -class SolanaTransactionModel { - final String id; - - final String from; - - final String to; - - final double amount; - - // If this is an outgoing transaction - final bool isOutgoingTx; - - // The Program ID of this transaction, e.g, System Program, Token Program... - final String programId; - - // The DateTime from the UNIX timestamp of the block where the transaction was included - final DateTime blockTime; - - // The Transaction fee - final double fee; - - // The token symbol - final String tokenSymbol; - - SolanaTransactionModel({ - required this.id, - required this.to, - required this.from, - required this.amount, - required this.programId, - required int blockTimeInInt, - this.isOutgoingTx = false, - required this.tokenSymbol, - required this.fee, - }) : blockTime = DateTime.fromMillisecondsSinceEpoch(blockTimeInInt * 1000); - - factory SolanaTransactionModel.fromJson(Map json) => SolanaTransactionModel( - id: json['id'], - blockTimeInInt: int.parse(json["timeStamp"]) * 1000, - from: json["from"], - to: json["to"], - amount: double.parse(json["value"]), - programId: json["programId"], - fee: json['fee'], - tokenSymbol: json['tokenSymbol'], - ); -} diff --git a/cw_solana/lib/solana_wallet.dart b/cw_solana/lib/solana_wallet.dart deleted file mode 100644 index 76f2d892..00000000 --- a/cw_solana/lib/solana_wallet.dart +++ /dev/null @@ -1,845 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; - -import 'package:cw_core/cake_hive.dart'; -import 'package:cw_core/crypto_currency.dart'; -import 'package:cw_core/encryption_file_utils.dart'; -import 'package:cw_core/node.dart'; -import 'package:cw_core/pathForWallet.dart'; -import 'package:cw_core/pending_transaction.dart'; -import 'package:cw_core/sync_status.dart'; -import 'package:cw_core/transaction_direction.dart'; -import 'package:cw_core/transaction_priority.dart'; -import 'package:cw_core/utils/print_verbose.dart'; -import 'package:cw_core/wallet_addresses.dart'; -import 'package:cw_core/wallet_base.dart'; -import 'package:cw_core/wallet_info.dart'; -import 'package:cw_core/wallet_keys_file.dart'; -import 'package:cw_solana/default_spl_tokens.dart'; -import 'package:cw_solana/solana_balance.dart'; -import 'package:cw_solana/solana_client.dart'; -import 'package:cw_solana/solana_exceptions.dart'; -import 'package:cw_solana/solana_transaction_credentials.dart'; -import 'package:cw_solana/solana_transaction_history.dart'; -import 'package:cw_solana/solana_transaction_info.dart'; -import 'package:cw_solana/solana_transaction_model.dart'; -import 'package:cw_solana/solana_wallet_addresses.dart'; -import 'package:cw_core/spl_token.dart'; -import 'package:hex/hex.dart'; -import 'package:hive/hive.dart'; -import 'package:mobx/mobx.dart'; -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:on_chain/solana/solana.dart' hide Store; -import 'package:bip39/bip39.dart' as bip39; -import 'package:blockchain_utils/blockchain_utils.dart'; - -part 'solana_wallet.g.dart'; - -class SolanaWallet = SolanaWalletBase with _$SolanaWallet; - -abstract class SolanaWalletBase - extends WalletBase - with Store, WalletKeysFile { - SolanaWalletBase({ - required WalletInfo walletInfo, - required DerivationInfo derivationInfo, - String? mnemonic, - String? privateKey, - required String password, - SolanaBalance? initialBalance, - required this.encryptionFileUtils, - this.passphrase, - }) : syncStatus = const NotConnectedSyncStatus(), - _password = password, - _mnemonic = mnemonic, - _hexPrivateKey = privateKey, - _client = SolanaWalletClient(), - walletAddresses = SolanaWalletAddresses(walletInfo), - balance = ObservableMap.of( - {CryptoCurrency.sol: initialBalance ?? SolanaBalance(BigInt.zero.toDouble(), false)}), - super(walletInfo, derivationInfo) { - this.walletInfo = walletInfo; - transactionHistory = SolanaTransactionHistory( - walletInfo: walletInfo, - password: password, - encryptionFileUtils: encryptionFileUtils, - ); - - if (!CakeHive.isAdapterRegistered(SPLToken.typeId)) { - CakeHive.registerAdapter(SPLTokenAdapter()); - } - - _sharedPrefs.complete(SharedPreferences.getInstance()); - } - - final String _password; - final String? _mnemonic; - final String? _hexPrivateKey; - final EncryptionFileUtils encryptionFileUtils; - - late final SolanaWalletClient _client; - - SolanaWalletClient get client => _client; - - @observable - double? estimatedFee; - - Timer? _transactionsUpdateTimer; - - late final Box splTokensBox; - - @override - WalletAddresses walletAddresses; - - @override - @observable - SyncStatus syncStatus; - - @override - @observable - ObservableMap balance = - ObservableMap(); - - final Completer _sharedPrefs = Completer(); - - @override - Object get keys => throw UnimplementedError("keys"); - - late final SolanaPrivateKey _solanaPrivateKey; - - late final SolanaPublicKey _solanaPublicKey; - - SolanaPublicKey get solanaPublicKey => _solanaPublicKey; - - SolanaPrivateKey get solanaPrivateKey => _solanaPrivateKey; - - String get solanaAddress => _solanaPublicKey.toAddress().address; - - @override - String? get seed => _mnemonic; - - @override - String get privateKey => _solanaPrivateKey.seedHex(); - - @override - WalletKeysData get walletKeysData => WalletKeysData( - mnemonic: _mnemonic, - privateKey: privateKey, - passphrase: passphrase, - ); - - Future init() async { - final boxName = "${walletInfo.name.replaceAll(" ", "_")}_${SPLToken.boxName}"; - - splTokensBox = await CakeHive.openBox(boxName); - - // Create the privatekey using either the mnemonic or the privateKey - _solanaPrivateKey = await getPrivateKey( - mnemonic: _mnemonic, - privateKey: _hexPrivateKey, - passphrase: passphrase, - ); - - // Extract the public key and wallet address - _solanaPublicKey = _solanaPrivateKey.publicKey(); - - walletInfo.address = _solanaPublicKey.toAddress().address; - - await walletAddresses.init(); - await transactionHistory.init(); - - await save(); - } - - Future getPrivateKey({ - String? mnemonic, - String? privateKey, - String? passphrase, - }) async { - assert(mnemonic != null || privateKey != null); - - if (mnemonic != null) { - final seed = bip39.mnemonicToSeed(mnemonic, passphrase: passphrase ?? ''); - - // Derive a Solana private key from the seed - final bip44 = Bip44.fromSeed(seed, Bip44Coins.solana); - - final childKey = bip44.deriveDefaultPath.change(Bip44Changes.chainExt); - - return SolanaPrivateKey.fromSeed(childKey.privateKey.raw); - } - - try { - final keypairBytes = Base58Decoder.decode(privateKey!); - return SolanaPrivateKey.fromBytes(keypairBytes); - } catch (_) { - final privateKeyBytes = HEX.decode(privateKey!); - return SolanaPrivateKey.fromSeed(privateKeyBytes); - } - } - - @override - int calculateEstimatedFee(TransactionPriority priority, int? amount) => 0; - - @override - Future changePassword(String password) => throw UnimplementedError("changePassword"); - - @override - Future close({bool shouldCleanup = false}) async { - _client.stop(); - _transactionsUpdateTimer?.cancel(); - } - - @action - @override - Future connectToNode({required Node node}) async { - try { - syncStatus = ConnectingSyncStatus(); - - final isConnected = _client.connect(node); - - if (!isConnected) { - throw Exception("Solana Node connection failed"); - } - - _setTransactionUpdateTimer(); - - syncStatus = ConnectedSyncStatus(); - } catch (e) { - syncStatus = FailedSyncStatus(); - } - } - - Future _getEstimatedFees() async { - try { - estimatedFee = await _client.getEstimatedFee(_solanaPublicKey, Commitment.confirmed); - printV(estimatedFee.toString()); - } catch (e) { - estimatedFee = 0.0; - } - } - - @override - Future createTransaction(Object credentials) async { - final solCredentials = credentials as SolanaTransactionCredentials; - - final outputs = solCredentials.outputs; - - final hasMultiDestination = outputs.length > 1; - - await updateTokenBalance(); - - final transactionCurrency = balance.keys.firstWhere( - (currency) => - currency.title == credentials.currency.title && - currency.tag == credentials.currency.tag, - orElse: () => throw Exception( - 'Currency ${credentials.currency.title} ${credentials.currency.tag} is not accessible in the wallet, try to enable it first.')); - - final walletBalanceForCurrency = balance[transactionCurrency]!.balance; - - final solBalance = balance[CryptoCurrency.sol]!.balance; - - double totalAmount = 0.0; - - bool isSendAll = false; - - if (hasMultiDestination) { - if (outputs.any((item) => item.sendAll || (item.formattedCryptoAmount ?? 0) <= 0)) { - throw SolanaTransactionWrongBalanceException(transactionCurrency); - } - - final totalAmountFromCredentials = - outputs.fold(0, (acc, value) => acc + (value.formattedCryptoAmount ?? 0)); - - totalAmount = totalAmountFromCredentials.toDouble(); - - if (walletBalanceForCurrency < totalAmount) { - throw SolanaTransactionWrongBalanceException(transactionCurrency); - } - } else { - final output = outputs.first; - - isSendAll = output.sendAll; - - if (isSendAll) { - totalAmount = walletBalanceForCurrency; - } else { - final totalOriginalAmount = double.parse(output.cryptoAmount ?? '0.0'); - - totalAmount = totalOriginalAmount; - } - - if (walletBalanceForCurrency < totalAmount) { - throw SolanaTransactionWrongBalanceException(transactionCurrency); - } - } - - String? tokenMint; - // Token Mint is only needed for transactions that are not native tokens(non-SOL transactions) - if (transactionCurrency.title != CryptoCurrency.sol.title) { - tokenMint = (transactionCurrency as SPLToken).mintAddress; - } - - final pendingSolanaTransaction = await _client.signSolanaTransaction( - tokenMint: tokenMint, - tokenTitle: transactionCurrency.title, - inputAmount: totalAmount, - ownerPrivateKey: _solanaPrivateKey, - tokenDecimals: transactionCurrency.decimals, - destinationAddress: solCredentials.outputs.first.isParsedAddress - ? solCredentials.outputs.first.extractedAddress! - : solCredentials.outputs.first.address, - isSendAll: isSendAll, - solBalance: solBalance, - ); - - return pendingSolanaTransaction; - } - - @override - Future> fetchTransactions() async => {}; - - @override - Future updateTransactionsHistory({List? specificTokenMints}) async { - await Future.wait([ - _updateNativeSOLTransactions(), - updateSPLTokenTransactions(specificMints: specificTokenMints), - ]); - } - - /// Polls for a specific transaction by signature with exponential backoff - /// I'm using this in case we make the call to fetch the transaction and it has not finished its confirmations on the solana network and been indexed by the node networks we use. - Future pollForTransaction({ - required String signature, - Duration initialDelay = const Duration(seconds: 1), - int maxRetries = 5, - }) async { - final walletAddress = _solanaPublicKey.toAddress().address; - - for (int i = 0; i < maxRetries; i++) { - await Future.delayed(initialDelay * (i + 1)); - - try { - final result = await _client.fetchTransactionBySignature( - signature: signature, - walletAddress: walletAddress, - ); - - if (result != null && result.transactions.isNotEmpty) { - await addTransactionsToTransactionHistory(result.transactions); - - // Update only the tokens involved in this transaction - if (result.tokenMints.isNotEmpty) { - await Future.wait([ - updateSPLTokenTransactions(specificMints: result.tokenMints), - updateTokenBalance(tokenMints: result.tokenMints), - ]); - } else { - // If no token mints, still update SOL balance - await updateTokenBalance(tokenMints: []); - } - - return; - } - } catch (e) { - printV('Error polling for transaction (attempt ${i + 1}/$maxRetries): $e'); - } - } - - // Fallback to full refresh if not found after max retries - printV('Transaction not found after $maxRetries attempts, falling back to full refresh'); - await updateTransactionsHistory(); - } - - void updateTransactions(List updatedTx) { - addTransactionsToTransactionHistory(updatedTx); - } - - /// Fetches the native SOL transactions linked to the wallet Public Key - Future _updateNativeSOLTransactions() async { - final transactions = - await _client.fetchTransactions(_solanaPublicKey.toAddress(), onUpdate: updateTransactions); - - await addTransactionsToTransactionHistory(transactions); - } - - Future updateSPLTokenTransactions({List? specificMints}) async { - final allTokens = balance.keys.whereType().toList(growable: false); - - // Filter to specific mints if provided - final tokens = specificMints != null - ? allTokens.where((t) => specificMints.contains(t.mintAddress)).toList(growable: false) - : allTokens; - - if (tokens.isEmpty) return; - - const int batchSize = 5; - - for (var i = 0; i < tokens.length; i += batchSize) { - final batch = tokens.sublist( - i, - i + batchSize > tokens.length ? tokens.length : i + batchSize, - ); - final results = await Future.wait( - batch.map((token) async { - try { - return await _client.getSPLTokenTransfers( - mintAddress: token.mintAddress, - splTokenSymbol: token.symbol, - splTokenDecimal: token.decimal, - privateKey: _solanaPrivateKey, - onUpdate: updateTransactions, - ); - } catch (_) { - return []; - } - }), - ); - - for (final list in results) { - await addTransactionsToTransactionHistory(list); - } - } - } - - Future addTransactionsToTransactionHistory( - List transactions, - ) async { - final Map result = {}; - - for (var transactionModel in transactions) { - result[transactionModel.id] = SolanaTransactionInfo( - id: transactionModel.id, - to: transactionModel.to, - from: transactionModel.from, - blockTime: transactionModel.blockTime, - direction: transactionModel.isOutgoingTx - ? TransactionDirection.outgoing - : TransactionDirection.incoming, - solAmount: transactionModel.amount, - isPending: false, - txFee: transactionModel.fee, - tokenSymbol: transactionModel.tokenSymbol, - ); - } - - transactionHistory.addMany(result); - - await transactionHistory.save(); - } - - @override - Future rescan({required int height}) => throw UnimplementedError("rescan"); - - @override - Future save() async { - if (!(await WalletKeysFile.hasKeysFile(walletInfo.name, walletInfo.type))) { - await saveKeysFile(_password, encryptionFileUtils); - saveKeysFile(_password, encryptionFileUtils, true); - } - - await walletAddresses.updateAddressesInBox(); - final path = await makePath(); - await encryptionFileUtils.write(path: path, password: _password, data: toJSON()); - await transactionHistory.save(); - } - - @action - @override - Future startSync() async { - try { - syncStatus = AttemptingSyncStatus(); - - // Verify node health before attempting to sync - final isHealthy = await checkNodeHealth(); - if (!isHealthy) { - syncStatus = FailedSyncStatus(); - return; - } - - await Future.wait([ - updateTokenBalance(), - _updateNativeSOLTransactions(), - updateSPLTokenTransactions(), - _getEstimatedFees(), - ]); - - syncStatus = SyncedSyncStatus(); - } catch (e) { - syncStatus = FailedSyncStatus(); - } - } - - String toJSON() => json.encode({ - 'mnemonic': _mnemonic, - 'private_key': _hexPrivateKey, - 'balance': balance[currency]!.toJSON(), - 'passphrase': passphrase, - }); - - static Future open({ - required String name, - required String password, - required WalletInfo walletInfo, - required EncryptionFileUtils encryptionFileUtils, - }) async { - final hasKeysFile = await WalletKeysFile.hasKeysFile(name, walletInfo.type); - final path = await pathForWallet(name: name, type: walletInfo.type); - - Map? data; - try { - final jsonSource = await encryptionFileUtils.read(path: path, password: password); - - data = json.decode(jsonSource) as Map; - } catch (e) { - if (!hasKeysFile) rethrow; - } - - final balance = SolanaBalance.fromJSON(data?['balance'] as String?, false) ?? SolanaBalance(0.0, false); - - final WalletKeysData keysData; - // Migrate wallet from the old scheme to then new .keys file scheme - if (!hasKeysFile) { - final mnemonic = data!['mnemonic'] as String?; - final privateKey = data['private_key'] as String?; - final passphrase = data['passphrase'] as String?; - - keysData = WalletKeysData(mnemonic: mnemonic, privateKey: privateKey, passphrase: passphrase); - } else { - keysData = await WalletKeysFile.readKeysFile( - name, - walletInfo.type, - password, - encryptionFileUtils, - ); - } - - final derivationInfo = await walletInfo.getDerivationInfo(); - - return SolanaWallet( - walletInfo: walletInfo, - derivationInfo: derivationInfo, - password: password, - passphrase: keysData.passphrase, - mnemonic: keysData.mnemonic, - privateKey: keysData.privateKey, - initialBalance: balance, - encryptionFileUtils: encryptionFileUtils, - ); - } - - Future updateTokenBalance({List? tokenMints}) async { - // Fetch SOL and SPL token balances in parallel for better performance - await Future.wait([ - _fetchSOLBalance().then((solBalance) { - balance[CryptoCurrency.sol] = solBalance; - }), - _updateSplTokenBalancesInternal(tokenMints: tokenMints), - ]); - - await save(); - } - - Future _fetchSOLBalance() async { - final balance = await _client.getBalance(solanaAddress); - - return SolanaBalance(balance, false); - } - - /// Internal helper to update SPL token balances. - /// When [tokenMints] is null or empty, updates all enabled tokens. - Future _updateSplTokenBalancesInternal({ - List? tokenMints, - }) async { - // Remove disabled tokens first to keep state clean - for (var token in splTokensBox.values.where((t) => !t.enabled)) { - balance.remove(token); - } - - final enabledTokens = splTokensBox.values.where((t) => t.enabled).toList(growable: false); - if (enabledTokens.isEmpty) return; - - final tokens = tokenMints == null || tokenMints.isEmpty - ? enabledTokens - : enabledTokens.where((t) => tokenMints.contains(t.mintAddress)).toList(growable: false); - - if (tokens.isEmpty) return; - - const int batchSize = 5; - - for (var i = 0; i < tokens.length; i += batchSize) { - final batch = tokens.sublist( - i, - i + batchSize > tokens.length ? tokens.length : i + batchSize, - ); - - final results = await Future.wait(batch.map((token) async { - try { - final fetched = await _client.getSplTokenBalance(token.mintAddress, solanaAddress); - return MapEntry(token, fetched); - } catch (e) { - printV('Error fetching spl token (${token.symbol}) balance ${e.toString()}'); - return MapEntry(token, null); - } - })); - - for (final entry in results) { - final token = entry.key; - final fetchedBalance = entry.value; - final currentBalance = balance[token] ?? - SolanaBalance.forToken(BigInt.zero, 0.0); - balance[token] = fetchedBalance ?? currentBalance; - } - } - } - - @override - Future? updateBalance() async => await updateTokenBalance(); - - @override - Future checkNodeHealth() async { - try { - // Check native balance - await _client.getBalance(solanaAddress, throwOnError: true); - - // Check USDC token balance - const usdcMintAddress = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"; - await _client.getSplTokenBalance(usdcMintAddress, solanaAddress, throwOnError: true); - - return true; - } catch (e) { - return false; - } - } - - List get splTokenCurrencies => splTokensBox.values.toList(); - - void addInitialTokens() { - final initialSPLTokens = DefaultSPLTokens().initialSPLTokens; - - for (var token in initialSPLTokens) { - if (!splTokensBox.containsKey(token.mintAddress)) { - splTokensBox.put(token.mintAddress, token); - } else { - // update existing token - final existingToken = splTokensBox.get(token.mintAddress); - splTokensBox.put( - token.mintAddress, SPLToken.copyWith(token, enabled: existingToken!.enabled)); - } - } - } - - Future discoverTokensFromMoralis() async { - try { - if (!splTokensBox.isOpen) return SolanaMoralisDiscoveryResult.empty; - - final address = walletAddresses.address; - if (address.isEmpty) return SolanaMoralisDiscoveryResult.empty; - - final walletTokens = await _client.fetchWalletTokensFromMoralis(address); - if (walletTokens.isEmpty) return SolanaMoralisDiscoveryResult.empty; - - final existingMints = { - for (final token in splTokensBox.values) token.mintAddress: token, - }; - - final defaultMints = DefaultSPLTokens().initialSPLTokens.map((t) => t.mintAddress).toSet(); - - final newTokens = []; - - for (final moralisToken in walletTokens) { - final mint = moralisToken.mint; - - final existingToken = existingMints[mint]; - if (existingToken != null) { - if (defaultMints.contains(mint) && !existingToken.enabled) { - existingToken.enabled = true; - await existingToken.save(); - await addSPLToken(existingToken); - } - continue; - } - - final tokenInfo = await _client.fetchSPLTokenInfo(mint); - if (tokenInfo == null) continue; - - final discoveredToken = SPLToken( - name: tokenInfo.name, - symbol: tokenInfo.symbol, - mintAddress: mint, - decimal: moralisToken.decimals, - mint: tokenInfo.mint, - iconPath: tokenInfo.iconPath, - tag: 'SOL', - ); - - newTokens.add( - DiscoveredSPLToken( - token: discoveredToken, - balance: moralisToken.amount, - ), - ); - } - - return SolanaMoralisDiscoveryResult(newTokens: newTokens); - } catch (e) { - printV('Error discovering SPL tokens from Moralis: ${e.toString()}'); - return SolanaMoralisDiscoveryResult.empty; - } - } - - Future addSPLToken(SPLToken token) async { - await splTokensBox.put(token.mintAddress, token); - - if (token.enabled) { - final tokenBalance = await _client.getSplTokenBalance(token.mintAddress, solanaAddress) ?? - balance[token] ?? - SolanaBalance.forToken(BigInt.zero, 0.0); - - balance[token] = tokenBalance; - } else { - balance.remove(token); - } - } - - Future deleteSPLToken(SPLToken token) async { - if (splTokensBox.isOpen) { - await splTokensBox.delete(token.mintAddress); - } - - balance.remove(token); - await _removeTokenTransactionsInHistory(token); - updateTokenBalance(); - } - - Future _removeTokenTransactionsInHistory(SPLToken token) async { - transactionHistory.transactions.removeWhere((key, value) => value.tokenSymbol == token.title); - await transactionHistory.save(); - } - - Future getSPLToken(String mintAddress) async { - try { - return await _client.fetchSPLTokenInfo(mintAddress); - } catch (e, s) { - printV('Error fetching token: ${e.toString()}, ${s.toString()}'); - return null; - } - } - - @override - Future renameWalletFiles(String newWalletName) async { - final currentWalletPath = await pathForWallet(name: walletInfo.name, type: type); - final currentWalletFile = File(currentWalletPath); - - final currentDirPath = await pathForWalletDir(name: walletInfo.name, type: type); - final currentTransactionsFile = File('$currentDirPath/$transactionsHistoryFileName'); - - // Copies current wallet files into new wallet name's dir and files - if (currentWalletFile.existsSync()) { - final newWalletPath = await pathForWallet(name: newWalletName, type: type); - await currentWalletFile.copy(newWalletPath); - } - if (currentTransactionsFile.existsSync()) { - final newDirPath = await pathForWalletDir(name: newWalletName, type: type); - await currentTransactionsFile.copy('$newDirPath/$transactionsHistoryFileName'); - } - - // Delete old name's dir and files - await Directory(currentDirPath).delete(recursive: true); - } - - void _setTransactionUpdateTimer() { - if (_transactionsUpdateTimer?.isActive ?? false) { - _transactionsUpdateTimer!.cancel(); - } - - _transactionsUpdateTimer = Timer.periodic(const Duration(seconds: 30), (_) { - updateTokenBalance(); - _updateNativeSOLTransactions(); - updateSPLTokenTransactions(); - _getEstimatedFees(); - }); - } - - @override - Future signMessage(String message, {String? address}) async { - // Convert the message to bytes - final messageBytes = utf8.encode(message); - - // Sign the message bytes with the wallet's private key - final signature = (_solanaPrivateKey.sign(messageBytes)); - - return Base58Encoder.encode(signature); - } - - List> bytesFromSigString(String signatureString) { - final regex = RegExp(r'Signature\(\[(.+)\], publicKey: (.+)\)'); - final match = regex.firstMatch(signatureString); - - if (match != null) { - final bytesString = match.group(1)!; - final base58EncodedPublicKeyString = match.group(2)!; - final sigBytes = bytesString.split(', ').map(int.parse).toList(); - - List pubKeyBytes = SolAddrDecoder().decodeAddr(base58EncodedPublicKeyString); - - return [sigBytes, pubKeyBytes]; - } else { - throw const FormatException('Invalid Signature string format'); - } - } - - @override - Future verifyMessage(String message, String signature, {String? address}) async { - String signatureString = utf8.decode(HEX.decode(signature)); - - List> bytes = bytesFromSigString(signatureString); - - final messageBytes = utf8.encode(message); - final sigBytes = bytes[0]; - final pubKeyBytes = bytes[1]; - - if (address == null) { - return false; - } - - // make sure the address derived from the public key provided matches the one we expect - final pub = SolanaPublicKey.fromBytes(pubKeyBytes); - if (address != pub.toAddress().address) { - return false; - } - - return pub.verify( - message: messageBytes, - signature: sigBytes, - ); - } - - SolanaRPC? get solanaProvider => _client.getSolanaProvider; - - @override - String get password => _password; - - @override - final String? passphrase; -} - -class DiscoveredSPLToken { - final SPLToken token; - final double balance; - - const DiscoveredSPLToken({ - required this.token, - required this.balance, - }); -} - -class SolanaMoralisDiscoveryResult { - final List newTokens; - - const SolanaMoralisDiscoveryResult({required this.newTokens}); - - static const SolanaMoralisDiscoveryResult empty = SolanaMoralisDiscoveryResult(newTokens: []); -} diff --git a/cw_solana/lib/solana_wallet_addresses.dart b/cw_solana/lib/solana_wallet_addresses.dart deleted file mode 100644 index 1431f8cc..00000000 --- a/cw_solana/lib/solana_wallet_addresses.dart +++ /dev/null @@ -1,41 +0,0 @@ -import 'package:cw_core/payment_uris.dart'; -import 'package:cw_core/utils/print_verbose.dart'; -import 'package:cw_core/wallet_addresses.dart'; -import 'package:cw_core/wallet_info.dart'; -import 'package:mobx/mobx.dart'; - -part 'solana_wallet_addresses.g.dart'; - -class SolanaWalletAddresses = SolanaWalletAddressesBase with _$SolanaWalletAddresses; - -abstract class SolanaWalletAddressesBase extends WalletAddresses with Store { - SolanaWalletAddressesBase(WalletInfo walletInfo) - : address = '', - super(walletInfo); - - @override - String address; - - @override - String get primaryAddress => address; - - @override - Future init() async { - address = walletInfo.address; - await updateAddressesInBox(); - } - - @override - Future updateAddressesInBox() async { - try { - addressesMap.clear(); - addressesMap[address] = ''; - await saveAddressesInBox(); - } catch (e) { - printV(e.toString()); - } - } - - @override - PaymentURI getPaymentUri(String amount) => SolanaURI(address: address, amount: amount); -} diff --git a/cw_solana/lib/solana_wallet_creation_credentials.dart b/cw_solana/lib/solana_wallet_creation_credentials.dart deleted file mode 100644 index 309c41cf..00000000 --- a/cw_solana/lib/solana_wallet_creation_credentials.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'package:cw_core/wallet_credentials.dart'; -import 'package:cw_core/wallet_info.dart'; - -class SolanaNewWalletCredentials extends WalletCredentials { - SolanaNewWalletCredentials({ - required String name, - WalletInfo? walletInfo, - String? password, - this.mnemonic, - String? passphrase, - }) : super( - name: name, - walletInfo: walletInfo, - password: password, - passphrase: passphrase, - ); - final String? mnemonic; -} - -class SolanaRestoreWalletFromSeedCredentials extends WalletCredentials { - SolanaRestoreWalletFromSeedCredentials({ - required String name, - required String password, - required this.mnemonic, - WalletInfo? walletInfo, - String? passphrase, - }) : super( - name: name, - password: password, - walletInfo: walletInfo, - passphrase: passphrase, - ); - - final String mnemonic; -} - -class SolanaRestoreWalletFromPrivateKey extends WalletCredentials { - SolanaRestoreWalletFromPrivateKey( - {required String name, - required String password, - required this.privateKey, - WalletInfo? walletInfo}) - : super(name: name, password: password, walletInfo: walletInfo); - - final String privateKey; -} diff --git a/cw_solana/lib/solana_wallet_service.dart b/cw_solana/lib/solana_wallet_service.dart deleted file mode 100644 index a16f3ee6..00000000 --- a/cw_solana/lib/solana_wallet_service.dart +++ /dev/null @@ -1,169 +0,0 @@ -import 'dart:io'; - -import 'package:bip39/bip39.dart' as bip39; -import 'package:collection/collection.dart'; -import 'package:cw_core/encryption_file_utils.dart'; -import 'package:cw_core/balance.dart'; -import 'package:cw_core/pathForWallet.dart'; -import 'package:cw_core/transaction_history.dart'; -import 'package:cw_core/transaction_info.dart'; -import 'package:cw_core/wallet_base.dart'; -import 'package:cw_core/wallet_info.dart'; -import 'package:cw_core/wallet_service.dart'; -import 'package:cw_core/wallet_type.dart'; -import 'package:cw_solana/solana_mnemonics.dart'; -import 'package:cw_solana/solana_wallet.dart'; -import 'package:cw_solana/solana_wallet_creation_credentials.dart'; -import 'package:hive/hive.dart'; - -class SolanaWalletService extends WalletService { - SolanaWalletService(this.isDirect); - - final bool isDirect; - - @override - Future create(SolanaNewWalletCredentials credentials, {bool? isTestnet}) async { - final strength = credentials.seedPhraseLength == 24 ? 256 : 128; - - final mnemonic = credentials.mnemonic ?? bip39.generateMnemonic(strength: strength); - - final wallet = SolanaWallet( - walletInfo: credentials.walletInfo!, - derivationInfo: await credentials.walletInfo!.getDerivationInfo(), - mnemonic: mnemonic, - password: credentials.password!, - passphrase: credentials.passphrase, - encryptionFileUtils: encryptionFileUtilsFor(isDirect), - ); - - await wallet.init(); - wallet.addInitialTokens(); - await wallet.save(); - return wallet; - } - - @override - WalletType getType() => WalletType.solana; - - @override - Future isWalletExit(String name) async => - File(await pathForWallet(name: name, type: getType())).existsSync(); - - @override - Future openWallet(String name, String password) async { - final walletInfo = await WalletInfo.get(name, getType()); - if (walletInfo == null) { - throw Exception('Wallet not found'); - } - - try { - final wallet = await SolanaWalletBase.open( - name: name, - password: password, - walletInfo: walletInfo, - encryptionFileUtils: encryptionFileUtilsFor(isDirect), - ); - - await wallet.init(); - wallet.addInitialTokens(); - await wallet.save(); - saveBackup(name); - return wallet; - } catch (_) { - await restoreWalletFilesFromBackup(name); - - final wallet = await SolanaWalletBase.open( - name: name, - password: password, - walletInfo: walletInfo, - encryptionFileUtils: encryptionFileUtilsFor(isDirect), - ); - - await wallet.init(); - wallet.addInitialTokens(); - await wallet.save(); - return wallet; - } - } - - @override - Future remove(String wallet) async { - File(await pathForWalletDir(name: wallet, type: getType())).delete(recursive: true); - final walletInfo = await WalletInfo.get(wallet, getType()); - if (walletInfo == null) { - throw Exception('Wallet not found'); - } - await WalletInfo.delete(walletInfo); - } - - @override - Future restoreFromKeys(SolanaRestoreWalletFromPrivateKey credentials, - {bool? isTestnet}) async { - final wallet = SolanaWallet( - password: credentials.password!, - privateKey: credentials.privateKey, - walletInfo: credentials.walletInfo!, - derivationInfo: await credentials.walletInfo!.getDerivationInfo(), - encryptionFileUtils: encryptionFileUtilsFor(isDirect), - ); - - await wallet.init(); - wallet.addInitialTokens(); - await wallet.save(); - - return wallet; - } - - @override - Future restoreFromSeed(SolanaRestoreWalletFromSeedCredentials credentials, - {bool? isTestnet}) async { - if (!bip39.validateMnemonic(credentials.mnemonic)) { - throw SolanaMnemonicIsIncorrectException(); - } - - final wallet = SolanaWallet( - password: credentials.password!, - mnemonic: credentials.mnemonic, - walletInfo: credentials.walletInfo!, - derivationInfo: await credentials.walletInfo!.getDerivationInfo(), - passphrase: credentials.passphrase, - encryptionFileUtils: encryptionFileUtilsFor(isDirect), - ); - - await wallet.init(); - wallet.addInitialTokens(); - await wallet.save(); - - return wallet; - } - - @override - Future rename(String currentName, String password, String newName) async { - final currentWalletInfo = await WalletInfo.get(currentName, getType()); - if (currentWalletInfo == null) { - throw Exception('Wallet not found'); - } - final currentWallet = await SolanaWalletBase.open( - password: password, - name: currentName, - walletInfo: currentWalletInfo, - encryptionFileUtils: encryptionFileUtilsFor(isDirect), - ); - - await currentWallet.renameWalletFiles(newName); - await saveBackup(newName); - - final newWalletInfo = currentWalletInfo; - newWalletInfo.id = WalletBase.idFor(newName, getType()); - newWalletInfo.name = newName; - - await newWalletInfo.save(); - } - - @override - Future, TransactionInfo>> restoreFromHardwareWallet(SolanaNewWalletCredentials credentials) { - // TODO: implement restoreFromHardwareWallet - throw UnimplementedError(); - } -} diff --git a/cw_solana/pubspec.yaml b/cw_solana/pubspec.yaml deleted file mode 100644 index d0f4f9fe..00000000 --- a/cw_solana/pubspec.yaml +++ /dev/null @@ -1,46 +0,0 @@ -name: cw_solana -description: A new Flutter package project. -version: 0.0.1 -publish_to: none -homepage: https://github.com/Such-Software/hash-wallet - -environment: - sdk: '>=3.0.6 <4.0.0' - flutter: ">=1.17.0" - -dependencies: - flutter: - sdk: flutter - cw_core: - path: ../cw_core - http: ^1.1.0 - hive: ^2.2.3 - bip39: ^1.0.6 - mobx: ^2.3.0+1 - shared_preferences: ^2.0.15 - bip32: ^2.0.0 - hex: ^0.2.0 - on_chain: - git: - url: https://github.com/cake-tech/on_chain.git - ref: 096865a8c6b89c260beadfec04f7e184c40a3273 - blockchain_utils: - git: - url: https://github.com/cake-tech/blockchain_utils - ref: cake-update-v2 - -dev_dependencies: - flutter_test: - sdk: flutter - flutter_lints: ^2.0.0 - build_runner: ^2.4.15 - mobx_codegen: ^2.0.7 - hive_generator: ^2.0.1 - -dependency_overrides: - watcher: ^1.1.0 - -flutter: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg diff --git a/cw_solana/test/cw_solana_test.dart b/cw_solana/test/cw_solana_test.dart deleted file mode 100644 index 42a5d8bd..00000000 --- a/cw_solana/test/cw_solana_test.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; - -import 'package:cw_solana/cw_solana.dart'; - -void main() { - test('adds one to input values', () { - final calculator = Calculator(); - expect(calculator.addOne(2), 3); - expect(calculator.addOne(-7), -6); - expect(calculator.addOne(0), 1); - }); -} diff --git a/cw_tron/.gitignore b/cw_tron/.gitignore deleted file mode 100644 index 96486fd9..00000000 --- a/cw_tron/.gitignore +++ /dev/null @@ -1,30 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ -migrate_working_dir/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. -/pubspec.lock -**/doc/api/ -.dart_tool/ -.packages -build/ diff --git a/cw_tron/.metadata b/cw_tron/.metadata deleted file mode 100644 index fa347fc6..00000000 --- a/cw_tron/.metadata +++ /dev/null @@ -1,10 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - channel: stable - -project_type: package diff --git a/cw_tron/CHANGELOG.md b/cw_tron/CHANGELOG.md deleted file mode 100644 index 41cc7d81..00000000 --- a/cw_tron/CHANGELOG.md +++ /dev/null @@ -1,3 +0,0 @@ -## 0.0.1 - -* TODO: Describe initial release. diff --git a/cw_tron/LICENSE b/cw_tron/LICENSE deleted file mode 100644 index ba75c69f..00000000 --- a/cw_tron/LICENSE +++ /dev/null @@ -1 +0,0 @@ -TODO: Add your license here. diff --git a/cw_tron/README.md b/cw_tron/README.md deleted file mode 100644 index 4ebd4563..00000000 --- a/cw_tron/README.md +++ /dev/null @@ -1,63 +0,0 @@ -## cw_tron - -TRON wallet module for Cake Wallet. Implements TRX and TRC-20 token support on top of `on_chain` (Tron), with transaction history and fee estimation via TronGrid. - -### Features - -- Connect to TRON nodes over HTTP(S) via `TronProvider`/`TronHTTPProvider`. -- Fetch TRX balance and TRC-20 token balances. -- Estimate fees using bandwidth/energy and memo fee; accounts for available account resources. -- Create and sign TRX and TRC-20 transfers (supports send-all and optional memo). -- Broadcast signed transactions. -- Load account history (TRX and TRC-20), filtering spam and TRC10-only events. -- Manage TRC-20 tokens: add/remove tokens and fetch token metadata. -- Sign/verify messages. -- Node health checks for both native and token balance endpoints. - -### Getting started - -Provide a TRON RPC endpoint and a TronGrid API key. Add a secrets file: - -```dart -// cw_tron/lib/.secrets.g.dart (DO NOT COMMIT) -const String tronGridApiKey = 'YOUR_TRONGRID_API_KEY'; -``` - -Basic connect and sync: - -```dart -final service = TronWalletService(walletInfoBox, client: TronClient(), isDirect: true); -final wallet = await service.create(TronNewWalletCredentials(name: 'My TRON', password: 'secret')); -await wallet.connectToNode(node: Node(uriRaw: 'api.trongrid.io', isSSL: true)); -await wallet.startSync(); -final trxBalance = wallet.balance[CryptoCurrency.trx]; -``` - -### Usage - -Send TRX: - -```dart -final pending = await wallet.createTransaction( - TronTransactionCredentials.single( - address: 'T...', - cryptoAmount: '1.5', - currency: CryptoCurrency.trx, - ), -); -final txHash = await pending.commit(); -``` - -Add USDT (TRC-20): - -```dart -final usdt = await wallet.getTronToken('TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t'); -if (usdt != null) { - await wallet.addTronToken(usdt); -} -``` - -### Additional information - -- History and token queries use TronGrid; set `tronGridApiKey`. -- See `lib/` for APIs: `TronClient`, `TronWallet`, `TronWalletService`, and credential types. diff --git a/cw_tron/analysis_options.yaml b/cw_tron/analysis_options.yaml deleted file mode 100644 index a5744c1c..00000000 --- a/cw_tron/analysis_options.yaml +++ /dev/null @@ -1,4 +0,0 @@ -include: package:flutter_lints/flutter.yaml - -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options diff --git a/cw_tron/lib/cw_tron.dart b/cw_tron/lib/cw_tron.dart deleted file mode 100644 index 6981fccb..00000000 --- a/cw_tron/lib/cw_tron.dart +++ /dev/null @@ -1,7 +0,0 @@ -library cw_tron; - -/// A Calculator. -class Calculator { - /// Returns [value] plus 1. - int addOne(int value) => value + 1; -} diff --git a/cw_tron/lib/default_tron_tokens.dart b/cw_tron/lib/default_tron_tokens.dart deleted file mode 100644 index 49c83752..00000000 --- a/cw_tron/lib/default_tron_tokens.dart +++ /dev/null @@ -1,107 +0,0 @@ -import 'package:cw_core/crypto_currency.dart'; -import 'package:cw_core/tron_token.dart'; - -class DefaultTronTokens { - final List _defaultTokens = [ - TronToken( - name: "Tether USD", - symbol: "USDT", - contractAddress: "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", - decimal: 6, - enabled: true, - ), - TronToken( - name: "USD Coin", - symbol: "USDC", - contractAddress: "TEkxiTehnzSmSe2XqrBj4w32RUN966rdz8", - decimal: 6, - enabled: true, - ), - TronToken( - name: "Bitcoin", - symbol: "BTC", - contractAddress: "TN3W4H6rK2ce4vX9YnFQHwKENnHjoxb3m9", - decimal: 8, - enabled: false, - ), - TronToken( - name: "Ethereum", - symbol: "ETH", - contractAddress: "TRFe3hT5oYhjSZ6f3ji5FJ7YCfrkWnHRvh", - decimal: 18, - enabled: false, - ), - TronToken( - name: "Wrapped BTC", - symbol: "WBTC", - contractAddress: "TXpw8XeWYeTUd4quDskoUqeQPowRh4jY65", - decimal: 8, - enabled: true, - ), - TronToken( - name: "Dogecoin", - symbol: "DOGE", - contractAddress: "THbVQp8kMjStKNnf2iCY6NEzThKMK5aBHg", - decimal: 8, - enabled: true, - ), - TronToken( - name: "JUST Stablecoin", - symbol: "USDJ", - contractAddress: "TMwFHYXLJaRUPeW6421aqXL4ZEzPRFGkGT", - decimal: 18, - enabled: false, - ), - TronToken( - name: "SUN", - symbol: "SUN", - contractAddress: "TSSMHYeV2uE9qYH95DqyoCuNCzEL1NvU3S", - decimal: 18, - enabled: false, - ), - TronToken( - name: "Wrapped TRX", - symbol: "WTRX", - contractAddress: "TNUC9Qb1rRpS5CbWLmNMxXBjyFoydXjWFR", - decimal: 6, - enabled: false, - ), - TronToken( - name: "BitTorent", - symbol: "BTT", - contractAddress: "TAFjULxiVgT4qWk6UZwjqwZXTSaGaqnVp4", - decimal: 18, - enabled: false, - ), - TronToken( - name: "BUSD Token", - symbol: "BUSD", - contractAddress: "TMz2SWatiAtZVVcH2ebpsbVtYwUPT9EdjH", - decimal: 18, - enabled: false, - ), - TronToken( - name: "HTX", - symbol: "HTX", - contractAddress: "TUPM7K8REVzD2UdV4R5fe5M8XbnR2DdoJ6", - decimal: 18, - enabled: false, - ), - ]; - - List get initialTronTokens => _defaultTokens.map((token) { - String? iconPath; - if (token.iconPath?.isEmpty ?? true) { - try { - iconPath = CryptoCurrency.all - .firstWhere((element) => - element.title.toUpperCase() == token.symbol.split(".").first.toUpperCase()) - .iconPath; - } catch (_) {} - } else { - iconPath = token.iconPath; - } - - return TronToken.copyWith(token, icon: iconPath, tag: 'TRX'); - }).toList(); -} diff --git a/cw_tron/lib/pending_tron_transaction.dart b/cw_tron/lib/pending_tron_transaction.dart deleted file mode 100644 index b1d601f8..00000000 --- a/cw_tron/lib/pending_tron_transaction.dart +++ /dev/null @@ -1,41 +0,0 @@ - - -import 'package:cw_core/pending_transaction.dart'; -import 'package:web3dart/crypto.dart'; - -class PendingTronTransaction with PendingTransaction { - final Function sendTransaction; - final List signedTransaction; - final String fee; - final String amount; - - PendingTronTransaction({ - required this.sendTransaction, - required this.signedTransaction, - required this.fee, - required this.amount, - }); - - @override - String get amountFormatted => amount; - - @override - Future commit() async => await sendTransaction(); - - @override - String get feeFormatted => "$feeFormattedValue TRX"; - - @override - String get feeFormattedValue => fee; - - @override - String get hex => bytesToHex(signedTransaction); - - @override - String get id => ''; - - @override - Future> commitUR() { - throw UnimplementedError(); - } -} diff --git a/cw_tron/lib/tron_abi.dart b/cw_tron/lib/tron_abi.dart deleted file mode 100644 index fdb99863..00000000 --- a/cw_tron/lib/tron_abi.dart +++ /dev/null @@ -1,436 +0,0 @@ -final trc20Abi = [ - {"inputs": [], "stateMutability": "nonpayable", "type": "constructor"}, - { - "anonymous": false, - "inputs": [ - {"indexed": true, "internalType": "address", "name": "owner", "type": "address"}, - {"indexed": true, "internalType": "address", "name": "spender", "type": "address"}, - {"indexed": false, "internalType": "uint256", "name": "value", "type": "uint256"} - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - {"indexed": false, "internalType": "uint256", "name": "total", "type": "uint256"}, - {"indexed": true, "internalType": "uint16", "name": "order_id", "type": "uint16"}, - {"indexed": true, "internalType": "address", "name": "buyer", "type": "address"}, - {"indexed": true, "internalType": "address", "name": "seller", "type": "address"}, - {"indexed": false, "internalType": "address", "name": "contract_address", "type": "address"} - ], - "name": "OrderPaid", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - {"indexed": true, "internalType": "address", "name": "previousOwner", "type": "address"}, - {"indexed": true, "internalType": "address", "name": "newOwner", "type": "address"} - ], - "name": "OwnershipTransferred", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - {"indexed": false, "internalType": "address", "name": "token", "type": "address"}, - {"indexed": false, "internalType": "bool", "name": "active", "type": "bool"} - ], - "name": "TokenUpdate", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - {"indexed": true, "internalType": "address", "name": "from", "type": "address"}, - {"indexed": true, "internalType": "address", "name": "to", "type": "address"}, - {"indexed": false, "internalType": "uint256", "name": "value", "type": "uint256"} - ], - "name": "Transfer", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - {"indexed": false, "internalType": "string", "name": "username", "type": "string"}, - {"indexed": true, "internalType": "address", "name": "seller", "type": "address"} - ], - "name": "UserRegistred", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - {"indexed": true, "internalType": "uint16", "name": "order_id", "type": "uint16"}, - {"indexed": true, "internalType": "address", "name": "buyer", "type": "address"}, - {"indexed": false, "internalType": "address", "name": "seller", "type": "address"} - ], - "name": "WBuyer", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - {"indexed": true, "internalType": "uint16", "name": "order_id", "type": "uint16"}, - {"indexed": true, "internalType": "address", "name": "seller", "type": "address"}, - {"indexed": false, "internalType": "address", "name": "buyer", "type": "address"} - ], - "name": "WSeller", - "type": "event" - }, - { - "inputs": [], - "name": "CONTRACTPERCENTAGE", - "outputs": [ - {"internalType": "uint8", "name": "", "type": "uint8"} - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - {"internalType": "uint16", "name": "order_id", "type": "uint16"}, - {"internalType": "uint256", "name": "order_total", "type": "uint256"}, - {"internalType": "address", "name": "contractAddress", "type": "address"}, - {"internalType": "address", "name": "seller", "type": "address"} - ], - "name": "PayWithTokens", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "TOKENINCREAMENT", - "outputs": [ - {"internalType": "uint16", "name": "", "type": "uint16"} - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - {"internalType": "address", "name": "", "type": "address"} - ], - "name": "_signer", - "outputs": [ - {"internalType": "bool", "name": "", "type": "bool"} - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - {"internalType": "address", "name": "", "type": "address"} - ], - "name": "_tokens", - "outputs": [ - {"internalType": "bool", "name": "active", "type": "bool"}, - {"internalType": "uint16", "name": "token", "type": "uint16"} - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - {"internalType": "address", "name": "", "type": "address"} - ], - "name": "_users", - "outputs": [ - {"internalType": "bool", "name": "active", "type": "bool"} - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - {"internalType": "address", "name": "owner", "type": "address"}, - {"internalType": "address", "name": "spender", "type": "address"} - ], - "name": "allowance", - "outputs": [ - {"internalType": "uint256", "name": "", "type": "uint256"} - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - {"internalType": "address", "name": "spender", "type": "address"}, - {"internalType": "uint256", "name": "amount", "type": "uint256"} - ], - "name": "approve", - "outputs": [ - {"internalType": "bool", "name": "", "type": "bool"} - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - {"internalType": "address", "name": "account", "type": "address"} - ], - "name": "balanceOf", - "outputs": [ - {"internalType": "uint256", "name": "", "type": "uint256"} - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - {"internalType": "address", "name": "token", "type": "address"} - ], - "name": "balanceOfContract", - "outputs": [ - {"internalType": "uint256", "name": "", "type": "uint256"} - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - {"internalType": "uint256", "name": "amount", "type": "uint256"} - ], - "name": "burn", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - {"internalType": "address", "name": "account", "type": "address"}, - {"internalType": "uint256", "name": "amount", "type": "uint256"} - ], - "name": "burnFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - {"internalType": "uint256", "name": "value", "type": "uint256"}, - {"internalType": "address", "name": "_contractAddress", "type": "address"} - ], - "name": "contractWithdraw", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "decimals", - "outputs": [ - {"internalType": "uint8", "name": "", "type": "uint8"} - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - {"internalType": "address", "name": "spender", "type": "address"}, - {"internalType": "uint256", "name": "subtractedValue", "type": "uint256"} - ], - "name": "decreaseAllowance", - "outputs": [ - {"internalType": "bool", "name": "", "type": "bool"} - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - {"internalType": "address", "name": "spender", "type": "address"}, - {"internalType": "uint256", "name": "addedValue", "type": "uint256"} - ], - "name": "increaseAllowance", - "outputs": [ - {"internalType": "bool", "name": "", "type": "bool"} - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - {"internalType": "address", "name": "to", "type": "address"}, - {"internalType": "uint256", "name": "amount", "type": "uint256"} - ], - "name": "mint", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - {"internalType": "string", "name": "", "type": "string"} - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - {"internalType": "address", "name": "", "type": "address"} - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - {"internalType": "address", "name": "token", "type": "address"}, - {"internalType": "uint256", "name": "value", "type": "uint256"} - ], - "name": "payToContract", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - {"internalType": "uint16", "name": "order_id", "type": "uint16"}, - {"internalType": "address", "name": "seller", "type": "address"} - ], - "name": "payWithNativeToken", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - {"internalType": "string", "name": "username", "type": "string"} - ], - "name": "regiserUser", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - {"internalType": "uint16", "name": "id", "type": "uint16"}, - {"internalType": "address", "name": "buyer", "type": "address"}, - {"internalType": "address", "name": "seller", "type": "address"} - ], - "name": "selectOrder", - "outputs": [ - {"internalType": "uint232", "name": "", "type": "uint232"}, - {"internalType": "uint16", "name": "", "type": "uint16"}, - {"internalType": "uint8", "name": "", "type": "uint8"} - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - {"internalType": "string", "name": "", "type": "string"} - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - {"internalType": "address", "name": "signer", "type": "address"} - ], - "name": "toggleSigner", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - {"internalType": "address", "name": "tokenAddress", "type": "address"} - ], - "name": "toggleToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalSupply", - "outputs": [ - {"internalType": "uint256", "name": "", "type": "uint256"} - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - {"internalType": "address", "name": "to", "type": "address"}, - {"internalType": "uint256", "name": "amount", "type": "uint256"} - ], - "name": "transfer", - "outputs": [ - {"internalType": "bool", "name": "", "type": "bool"} - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - {"internalType": "address", "name": "from", "type": "address"}, - {"internalType": "address", "name": "to", "type": "address"}, - {"internalType": "uint256", "name": "amount", "type": "uint256"} - ], - "name": "transferFrom", - "outputs": [ - {"internalType": "bool", "name": "", "type": "bool"} - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - {"internalType": "address", "name": "newOwner", "type": "address"} - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - {"internalType": "uint8", "name": "newPercentage", "type": "uint8"} - ], - "name": "updateContractPercentage", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - {"internalType": "address[]", "name": "buyer", "type": "address[]"}, - {"internalType": "bytes[]", "name": "signature", "type": "bytes[]"}, - {"internalType": "uint16[]", "name": "order_id", "type": "uint16[]"}, - {"internalType": "address", "name": "contractAddress", "type": "address"} - ], - "name": "widthrawForSellers", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - {"internalType": "address", "name": "seller", "type": "address"}, - {"internalType": "bytes", "name": "signature", "type": "bytes"}, - {"internalType": "uint16", "name": "order_id", "type": "uint16"}, - {"internalType": "address", "name": "contractAddress", "type": "address"} - ], - "name": "widthrowForBuyers", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -]; diff --git a/cw_tron/lib/tron_balance.dart b/cw_tron/lib/tron_balance.dart deleted file mode 100644 index 6c28ad33..00000000 --- a/cw_tron/lib/tron_balance.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'dart:convert'; - -import 'package:cw_core/balance.dart'; - -class TronBalance extends Balance { - TronBalance(this.balance) : super(balance, balance); - - final BigInt balance; - - String toJSON() => json.encode({ 'balance': balance.toString() }); - - static TronBalance? fromJSON(String? jsonSource) { - if (jsonSource == null) { - return null; - } - - final decoded = json.decode(jsonSource) as Map; - - try { - return TronBalance(BigInt.parse(decoded['balance'])); - } catch (e) { - return TronBalance(BigInt.zero); - } - } -} diff --git a/cw_tron/lib/tron_client.dart b/cw_tron/lib/tron_client.dart deleted file mode 100644 index 60431674..00000000 --- a/cw_tron/lib/tron_client.dart +++ /dev/null @@ -1,568 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:developer'; - -import 'package:blockchain_utils/blockchain_utils.dart'; -import 'package:cw_core/crypto_currency.dart'; -import 'package:cw_core/node.dart'; -import 'package:cw_core/utils/proxy_wrapper.dart'; -import 'package:cw_tron/pending_tron_transaction.dart'; -import 'package:cw_tron/tron_abi.dart'; -import 'package:cw_tron/tron_balance.dart'; -import 'package:cw_tron/tron_http_provider.dart'; -import 'package:cw_core/tron_token.dart'; -import 'package:cw_tron/tron_transaction_model.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import '.secrets.g.dart' as secrets; -import 'package:on_chain/on_chain.dart'; - -class TronClient { - late final client = ProxyWrapper().getHttpIOClient(); - - TronProvider? _provider; - // This is an internal tracker, so we don't have to "refetch". - int _nativeTxEstimatedFee = 0; - - Future> fetchTransactions(String address, - {String? contractAddress}) async { - try { - final response = await client.get( - Uri.https( - "api.trongrid.io", - "/v1/accounts/$address/transactions", - { - "only_confirmed": "true", - "limit": "200", - }, - ), - headers: { - 'Content-Type': 'application/json', - 'TRON-PRO-API-KEY': secrets.tronGridApiKey, - }, - ); - final jsonResponse = json.decode(response.body) as Map; - - if (response.statusCode >= 200 && - response.statusCode < 300 && - jsonResponse['status'] != false) { - return (jsonResponse['data'] as List).map((e) { - return TronTransactionModel.fromJson(e as Map); - }).toList(); - } - - return []; - } catch (e, s) { - log('Error getting tx: ${e.toString()}\n ${s.toString()}'); - return []; - } - } - - Future> fetchTrc20ExcludedTransactions(String address) async { - try { - final response = await client.get( - Uri.https( - "api.trongrid.io", - "/v1/accounts/$address/transactions/trc20", - { - "only_confirmed": "true", - "limit": "200", - }, - ), - headers: { - 'Content-Type': 'application/json', - 'TRON-PRO-API-KEY': secrets.tronGridApiKey, - }, - ); - final jsonResponse = json.decode(response.body) as Map; - - if (response.statusCode >= 200 && - response.statusCode < 300 && - jsonResponse['status'] != false) { - return (jsonResponse['data'] as List).map((e) { - return TronTRC20TransactionModel.fromJson(e as Map); - }).toList(); - } - - return []; - } catch (e, s) { - log('Error getting trc20 tx: ${e.toString()}\n ${s.toString()}'); - return []; - } - } - - bool connect(Node node) { - try { - final formattedUrl = '${node.isSSL ? 'https' : 'http'}://${node.uriRaw}'; - _provider = TronProvider(TronHTTPProvider(url: formattedUrl)); - - return true; - } catch (e) { - return false; - } - } - - Future getBalance(TronAddress address, {bool throwOnError = false}) async { - try { - final accountDetails = await _provider!.request(TronRequestGetAccount(address: address)); - - return accountDetails?.balance ?? BigInt.zero; - } catch (_) { - if (throwOnError) { - rethrow; - } - return BigInt.zero; - } - } - - Future getFeeLimit( - TransactionRaw rawTransaction, - TronAddress address, - TronAddress receiverAddress, { - int energyUsed = 0, - bool isEstimatedFeeFlow = false, - }) async { - try { - // Get the tron chain parameters. - final chainParams = await _provider!.request(TronRequestGetChainParameters()); - - final bandWidthInSun = chainParams.getTransactionFee!; - log('BandWidth In Sun: $bandWidthInSun'); - - final energyInSun = chainParams.getEnergyFee!; - log('Energy In Sun: $energyInSun'); - - final fakeTransaction = Transaction( - rawData: rawTransaction, - signature: [Uint8List(65)], - ); - - // Calculate the total size of the fake transaction, considering the required network overhead. - final transactionSize = fakeTransaction.length + 64; - - // Assign the calculated size to the variable representing the required bandwidth. - int neededBandWidth = transactionSize; - log('Initial Needed Bandwidth: $neededBandWidth'); - - int neededEnergy = energyUsed; - log('Initial Needed Energy: $neededEnergy'); - - // Fetch account resources to assess the available bandwidth and energy - final accountResource = - await _provider!.request(TronRequestGetAccountResource(address: address)); - - neededEnergy -= accountResource.howManyEnergy.toInt(); - log('Account resource energy: ${accountResource.howManyEnergy.toInt()}'); - log('Needed Energy after deducting from account resource energy: $neededEnergy'); - - // Deduct the bandwidth from the account's available bandwidth. - final BigInt accountBandWidth = accountResource.howManyBandwIth; - log('Account resource bandwidth: ${accountResource.howManyBandwIth.toInt()}'); - - if (accountBandWidth >= BigInt.from(neededBandWidth) && !isEstimatedFeeFlow) { - log('Account has more bandwidth than required'); - neededBandWidth = 0; - } - - if (neededEnergy < 0) { - neededEnergy = 0; - } - - final energyBurn = neededEnergy * energyInSun.toInt(); - log('Energy Burn: $energyBurn'); - - final bandWidthBurn = neededBandWidth * bandWidthInSun; - log('Bandwidth Burn: $bandWidthBurn'); - - int totalBurn = energyBurn + bandWidthBurn; - log('Total Burn: $totalBurn'); - - /// If there is a note (memo), calculate the memo fee. - if (rawTransaction.data != null) { - totalBurn += chainParams.getMemoFee!; - } - - log('Final total burn: $totalBurn'); - - return totalBurn; - } catch (_) { - return 0; - } - } - - Future getEstimatedFee(TronAddress ownerAddress) async { - const constantAmount = '1000'; - // Fetch the latest Tron block - final block = await _provider!.request(TronRequestGetNowBlock()); - - // Create the transfer contract - final contract = TransferContract( - amount: TronHelper.toSun(constantAmount), - ownerAddress: ownerAddress, - toAddress: ownerAddress, - ); - - // Prepare the contract parameter for the transaction. - final parameter = Any(typeUrl: contract.typeURL, value: contract); - - // Create a TransactionContract object with the contract type and parameter. - final transactionContract = - TransactionContract(type: contract.contractType, parameter: parameter); - - // Set the transaction expiration time (maximum 24 hours) - final expireTime = DateTime.now().add(const Duration(minutes: 30)); - - // Create a raw transaction - TransactionRaw rawTransaction = TransactionRaw( - refBlockBytes: block.blockHeader.rawData.refBlockBytes, - refBlockHash: block.blockHeader.rawData.refBlockHash, - expiration: BigInt.from(expireTime.millisecondsSinceEpoch), - contract: [transactionContract], - timestamp: block.blockHeader.rawData.timestamp, - ); - - final estimatedFee = await getFeeLimit( - rawTransaction, - ownerAddress, - ownerAddress, - isEstimatedFeeFlow: true, - ); - - _nativeTxEstimatedFee = estimatedFee; - - return estimatedFee; - } - - Future getTRCEstimatedFee(TronAddress ownerAddress) async { - String contractAddress = 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t'; - String constantAmount = - '0'; // We're using 0 as the base amount here as we get an error when balance is zero i.e for new wallets. - final contract = ContractABI.fromJson(trc20Abi, isTron: true); - - final function = contract.functionFromName("transfer"); - - /// address /// amount - final transferparams = [ - ownerAddress, - TronHelper.toSun(constantAmount), - ]; - - final contractAddr = TronAddress(contractAddress); - - final request = await _provider!.request( - TronRequestTriggerConstantContract( - ownerAddress: ownerAddress, - contractAddress: contractAddr, - data: function.encodeHex(transferparams), - ), - ); - - if (!request.isSuccess) { - log("Tron TRC20 error: ${request.error} \n ${request.respose}"); - } - - final feeLimit = await getFeeLimit( - request.transactionRaw!, - ownerAddress, - ownerAddress, - energyUsed: request.energyUsed ?? 0, - isEstimatedFeeFlow: true, - ); - return feeLimit; - } - - Future signTransaction({ - required TronPrivateKey ownerPrivKey, - required String toAddress, - required String amount, - required CryptoCurrency currency, - required BigInt tronBalance, - required bool sendAll, - }) async { - // Get the owner tron address from the key - final ownerAddress = ownerPrivKey.publicKey().toAddress(); - - // Define the receiving Tron address for the transaction. - final receiverAddress = TronAddress(toAddress); - - bool isNativeTransaction = currency == CryptoCurrency.trx; - - String totalAmount; - TransactionRaw rawTransaction; - if (isNativeTransaction) { - if (sendAll) { - final accountResource = - await _provider!.request(TronRequestGetAccountResource(address: ownerAddress)); - - final availableBandWidth = accountResource.howManyBandwIth.toInt(); - - // 269 is the current middle ground for bandwidth per transaction - if (availableBandWidth >= 269) { - totalAmount = amount; - } else { - final amountInSun = TronHelper.toSun(amount).toInt(); - - // 5000 added here is a buffer since we're working with "estimated" value of the fee. - final result = amountInSun - (_nativeTxEstimatedFee + 5000); - - totalAmount = TronHelper.fromSun(BigInt.from(result)); - } - } else { - totalAmount = amount; - } - rawTransaction = await _signNativeTransaction( - ownerAddress, - receiverAddress, - totalAmount, - tronBalance, - sendAll, - ); - } else { - final tokenAddress = (currency as TronToken).contractAddress; - totalAmount = amount; - rawTransaction = await _signTrcTokenTransaction( - ownerAddress, - receiverAddress, - totalAmount, - tokenAddress, - tronBalance, - ); - } - - final signature = ownerPrivKey.sign(rawTransaction.toBuffer()); - - sendTx() async => await sendTransaction( - rawTransaction: rawTransaction, - signature: signature, - ); - - return PendingTronTransaction( - signedTransaction: signature, - amount: totalAmount, - fee: TronHelper.fromSun(rawTransaction.feeLimit ?? BigInt.zero), - sendTransaction: sendTx, - ); - } - - Future _signNativeTransaction( - TronAddress ownerAddress, - TronAddress receiverAddress, - String amount, - BigInt tronBalance, - bool sendAll, - ) async { - // This is introduce to server as a limit in cases where feeLimit is 0 - // The transaction signing will fail if the feeLimit is explicitly 0. - int defaultFeeLimit = 269000; - - final block = await _provider!.request(TronRequestGetNowBlock()); - // Create the transfer contract - final contract = TransferContract( - amount: TronHelper.toSun(amount), - ownerAddress: ownerAddress, - toAddress: receiverAddress, - ); - - // Prepare the contract parameter for the transaction. - final parameter = Any(typeUrl: contract.typeURL, value: contract); - - // Create a TransactionContract object with the contract type and parameter. - final transactionContract = - TransactionContract(type: contract.contractType, parameter: parameter); - - // Set the transaction expiration time (maximum 24 hours) - final expireTime = DateTime.now().add(const Duration(minutes: 30)); - - // Create a raw transaction - TransactionRaw rawTransaction = TransactionRaw( - refBlockBytes: block.blockHeader.rawData.refBlockBytes, - refBlockHash: block.blockHeader.rawData.refBlockHash, - expiration: BigInt.from(expireTime.millisecondsSinceEpoch), - contract: [transactionContract], - timestamp: block.blockHeader.rawData.timestamp, - ); - - final feeLimit = await getFeeLimit(rawTransaction, ownerAddress, receiverAddress); - final feeLimitToUse = feeLimit != 0 ? feeLimit : defaultFeeLimit; - final tronBalanceInt = tronBalance.toInt(); - - if (feeLimit > tronBalanceInt) { - final feeInTrx = TronHelper.fromSun(BigInt.parse(feeLimit.toString())); - throw Exception( - 'You don\'t have enough TRX to cover the transaction fee for this transaction. Please top up.\nTransaction fee: $feeInTrx TRX', - ); - } - - rawTransaction = rawTransaction.copyWith( - feeLimit: BigInt.from(feeLimitToUse), - ); - - return rawTransaction; - } - - Future _signTrcTokenTransaction( - TronAddress ownerAddress, - TronAddress receiverAddress, - String amount, - String contractAddress, - BigInt tronBalance, - ) async { - final contract = ContractABI.fromJson(trc20Abi, isTron: true); - - final function = contract.functionFromName("transfer"); - - /// address /// amount - final transferparams = [ - receiverAddress, - TronHelper.toSun(amount), - ]; - - final contractAddr = TronAddress(contractAddress); - - final request = await _provider!.request( - TronRequestTriggerConstantContract( - ownerAddress: ownerAddress, - contractAddress: contractAddr, - data: function.encodeHex(transferparams), - ), - ); - - if (!request.isSuccess) { - log("Tron TRC20 error: ${request.error} \n ${request.respose}"); - throw Exception( - 'An error occurred while creating the transfer request. Please try again.', - ); - } - - final feeLimit = await getFeeLimit( - request.transactionRaw!, - ownerAddress, - receiverAddress, - energyUsed: request.energyUsed ?? 0, - ); - - final tronBalanceInt = tronBalance.toInt(); - - if (feeLimit > tronBalanceInt) { - final feeInTrx = TronHelper.fromSun(BigInt.parse(feeLimit.toString())); - throw Exception( - 'You don\'t have enough TRX to cover the transaction fee for this transaction. Please top up. Transaction fee: $feeInTrx TRX', - ); - } - - final rawTransaction = request.transactionRaw!.copyWith( - feeLimit: BigInt.from(feeLimit), - ); - - return rawTransaction; - } - - Future sendTransaction({ - required TransactionRaw rawTransaction, - required List signature, - }) async { - try { - final transaction = Transaction(rawData: rawTransaction, signature: [signature]); - - final raw = BytesUtils.toHexString(transaction.toBuffer()); - - final txBroadcastResult = await _provider!.request(TronRequestBroadcastHex(transaction: raw)); - - if (txBroadcastResult.isSuccess) { - return txBroadcastResult.txId!; - } else { - throw Exception(txBroadcastResult.error); - } - } catch (e) { - log('Send block Exception: ${e.toString()}'); - throw Exception(e); - } - } - - Future fetchTronTokenBalances(String userAddress, String contractAddress, {bool throwOnError = false}) async { - try { - final ownerAddress = TronAddress(userAddress); - - final tokenAddress = TronAddress(contractAddress); - - final contract = ContractABI.fromJson(trc20Abi, isTron: true); - - final function = contract.functionFromName("balanceOf"); - - final request = await _provider!.request( - TronRequestTriggerConstantContract.fromMethod( - ownerAddress: ownerAddress, - contractAddress: tokenAddress, - function: function, - params: [ownerAddress], - ), - ); - - final outputResult = request.outputResult?.first ?? BigInt.zero; - - return TronBalance(outputResult); - } catch (_) { - if (throwOnError) { - rethrow; - } - return TronBalance(BigInt.zero); - } - } - - Future getTronToken(String contractAddress, String userAddress) async { - try { - final tokenAddress = TronAddress(contractAddress); - - final ownerAddress = TronAddress(userAddress); - - final contract = ContractABI.fromJson(trc20Abi, isTron: true); - - final name = - (await getTokenDetail(contract, "name", ownerAddress, tokenAddress) as String?) ?? ''; - - final symbol = - (await getTokenDetail(contract, "symbol", ownerAddress, tokenAddress) as String?) ?? ''; - - final decimal = - (await getTokenDetail(contract, "decimals", ownerAddress, tokenAddress) as BigInt?) ?? - BigInt.zero; - - return TronToken( - name: name, - symbol: symbol, - contractAddress: contractAddress, - decimal: decimal.toInt(), - ); - } catch (e) { - return null; - } - } - - Future getTokenDetail( - ContractABI contract, - String functionName, - TronAddress ownerAddress, - TronAddress tokenAddress, - ) async { - final function = contract.functionFromName(functionName); - - try { - final request = await _provider!.request( - TronRequestTriggerConstantContract.fromMethod( - ownerAddress: ownerAddress, - contractAddress: tokenAddress, - function: function, - params: [], - ), - ); - - final outputResult = request.outputResult?.first; - - return outputResult; - } catch (_) { - log('Erorr fetching detail: ${_.toString()}'); - - return null; - } - } -} diff --git a/cw_tron/lib/tron_exception.dart b/cw_tron/lib/tron_exception.dart deleted file mode 100644 index 13b98c02..00000000 --- a/cw_tron/lib/tron_exception.dart +++ /dev/null @@ -1,16 +0,0 @@ -import 'package:cw_core/crypto_currency.dart'; - -class TronMnemonicIsIncorrectException implements Exception { - @override - String toString() => - 'Tron mnemonic has incorrect format. Mnemonic should contain 12 or 24 words separated by space.'; -} -class TronTransactionCreationException implements Exception { - final String exceptionMessage; - - TronTransactionCreationException(CryptoCurrency currency) - : exceptionMessage = 'Wrong balance. Not enough ${currency.title} on your balance.'; - - @override - String toString() => exceptionMessage; -} \ No newline at end of file diff --git a/cw_tron/lib/tron_http_provider.dart b/cw_tron/lib/tron_http_provider.dart deleted file mode 100644 index 420ff85b..00000000 --- a/cw_tron/lib/tron_http_provider.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'dart:convert'; - -import 'package:cw_core/utils/proxy_wrapper.dart'; -import 'package:on_chain/tron/tron.dart'; -import '.secrets.g.dart' as secrets; - -class TronHTTPProvider implements TronServiceProvider { - TronHTTPProvider( - {required this.url, - this.defaultRequestTimeout = const Duration(seconds: 30)}); - - @override - final String url; - late final client = ProxyWrapper().getHttpIOClient(); - final Duration defaultRequestTimeout; - - @override - Future> get(TronRequestDetails params, - [Duration? timeout]) async { - final response = await client.get(Uri.parse(params.url(url)), headers: { - 'Content-Type': 'application/json', - if (url.contains("trongrid")) 'TRON-PRO-API-KEY': secrets.tronGridApiKey, - if (url.contains("nownodes")) 'api-key': secrets.tronNowNodesApiKey, - }).timeout(timeout ?? defaultRequestTimeout); - final data = json.decode(response.body) as Map; - return data; - } - - @override - Future> post(TronRequestDetails params, - [Duration? timeout]) async { - final response = await client - .post(Uri.parse(params.url(url)), - headers: { - 'Content-Type': 'application/json', - if (url.contains("trongrid")) - 'TRON-PRO-API-KEY': secrets.tronGridApiKey, - if (url.contains("nownodes")) - 'api-key': secrets.tronNowNodesApiKey, - }, - body: params.toRequestBody()) - .timeout(timeout ?? defaultRequestTimeout); - final data = json.decode(response.body) as Map; - return data; - } -} diff --git a/cw_tron/lib/tron_transaction_credentials.dart b/cw_tron/lib/tron_transaction_credentials.dart deleted file mode 100644 index e68d5525..00000000 --- a/cw_tron/lib/tron_transaction_credentials.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:cw_core/crypto_currency.dart'; -import 'package:cw_core/output_info.dart'; - -class TronTransactionCredentials { - TronTransactionCredentials( - this.outputs, { - required this.currency, - }); - - final List outputs; - final CryptoCurrency currency; -} diff --git a/cw_tron/lib/tron_transaction_history.dart b/cw_tron/lib/tron_transaction_history.dart deleted file mode 100644 index c940c770..00000000 --- a/cw_tron/lib/tron_transaction_history.dart +++ /dev/null @@ -1,85 +0,0 @@ -import 'dart:convert'; -import 'dart:core'; -import 'dart:developer'; -import 'package:cw_core/pathForWallet.dart'; -import 'package:cw_core/wallet_info.dart'; -import 'package:cw_core/encryption_file_utils.dart'; -import 'package:cw_tron/tron_transaction_info.dart'; -import 'package:mobx/mobx.dart'; -import 'package:cw_core/transaction_history.dart'; - -part 'tron_transaction_history.g.dart'; - -class TronTransactionHistory = TronTransactionHistoryBase with _$TronTransactionHistory; - -abstract class TronTransactionHistoryBase extends TransactionHistoryBase - with Store { - TronTransactionHistoryBase( - {required this.walletInfo, required String password, required this.encryptionFileUtils}) - : _password = password { - transactions = ObservableMap(); - } - - String _password; - - final WalletInfo walletInfo; - final EncryptionFileUtils encryptionFileUtils; - - Future init() async { - clear(); - await _load(); - } - - @override - Future save() async { - String transactionsHistoryFileNameForWallet = 'tron_transactions.json'; - try { - final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type); - String path = '$dirPath/$transactionsHistoryFileNameForWallet'; - final transactionMaps = transactions.map((key, value) => MapEntry(key, value.toJson())); - final data = json.encode({'transactions': transactionMaps}); - await encryptionFileUtils.write(path: path, password: _password, data: data); - } catch (e, s) { - log('Error while saving ${walletInfo.type.name} transaction history: ${e.toString()}'); - log(s.toString()); - } - } - - @override - void addOne(TronTransactionInfo transaction) => transactions[transaction.id] = transaction; - - @override - void addMany(Map transactions) => - this.transactions.addAll(transactions); - - Future> _read() async { - String transactionsHistoryFileNameForWallet = 'tron_transactions.json'; - final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type); - String path = '$dirPath/$transactionsHistoryFileNameForWallet'; - final content = await encryptionFileUtils.read(path: path, password: _password); - if (content.isEmpty) { - return {}; - } - return json.decode(content) as Map; - } - - Future _load() async { - try { - final content = await _read(); - final txs = content['transactions'] as Map? ?? {}; - - for (var entry in txs.entries) { - final val = entry.value; - - if (val is Map) { - final tx = TronTransactionInfo.fromJson(val); - _update(tx); - } - } - } catch (e) { - log(e.toString()); - } - } - - void _update(TronTransactionInfo transaction) => transactions[transaction.id] = transaction; -} diff --git a/cw_tron/lib/tron_transaction_info.dart b/cw_tron/lib/tron_transaction_info.dart deleted file mode 100644 index 28c704d2..00000000 --- a/cw_tron/lib/tron_transaction_info.dart +++ /dev/null @@ -1,93 +0,0 @@ -import 'package:cw_core/format_amount.dart'; -import 'package:cw_core/transaction_direction.dart'; -import 'package:cw_core/transaction_info.dart'; -import 'package:on_chain/on_chain.dart' as onchain; -import 'package:on_chain/tron/tron.dart'; - -class TronTransactionInfo extends TransactionInfo { - TronTransactionInfo({ - required this.id, - required this.tronAmount, - required this.txFee, - required this.direction, - required this.blockTime, - required this.to, - required this.from, - required this.isPending, - this.tokenSymbol = 'TRX', - }) : amount = tronAmount.toInt(); - - final String id; - final String? to; - final String? from; - final int amount; - final BigInt tronAmount; - final String tokenSymbol; - final DateTime blockTime; - final bool isPending; - final int? txFee; - final TransactionDirection direction; - - factory TronTransactionInfo.fromJson(Map data) { - return TronTransactionInfo( - id: data['id'] as String, - tronAmount: BigInt.parse(data['tronAmount']), - txFee: data['txFee'], - direction: parseTransactionDirectionFromInt(data['direction'] as int), - blockTime: DateTime.fromMillisecondsSinceEpoch(data['blockTime'] as int), - tokenSymbol: data['tokenSymbol'] as String, - to: data['to'], - from: data['from'], - isPending: data['isPending'], - ); - } - - Map toJson() => { - 'id': id, - 'tronAmount': tronAmount.toString(), - 'txFee': txFee, - 'direction': direction.index, - 'blockTime': blockTime.millisecondsSinceEpoch, - 'tokenSymbol': tokenSymbol, - 'to': to, - 'from': from, - 'isPending': isPending, - }; - - @override - DateTime get date => blockTime; - - String? _fiatAmount; - - @override - String amountFormatted() { - String formattedAmount = _rawAmountAsString(tronAmount); - - return '$formattedAmount $tokenSymbol'; - } - - @override - String fiatAmount() => _fiatAmount ?? ''; - - @override - void changeFiatAmount(String amount) => _fiatAmount = formatAmount(amount); - - @override - String feeFormatted() { - final formattedFee = onchain.TronHelper.fromSun(BigInt.from(txFee ?? 0)); - - return '$formattedFee TRX'; - } - - String _rawAmountAsString(BigInt amount) { - String formattedAmount = TronHelper.fromSun(amount); - - if (formattedAmount.length >= 8) { - formattedAmount = formattedAmount.substring(0, 8); - } - - return formattedAmount; - } - - String rawTronAmount() => _rawAmountAsString(tronAmount); -} diff --git a/cw_tron/lib/tron_transaction_model.dart b/cw_tron/lib/tron_transaction_model.dart deleted file mode 100644 index 1748adc5..00000000 --- a/cw_tron/lib/tron_transaction_model.dart +++ /dev/null @@ -1,205 +0,0 @@ -import 'package:blockchain_utils/hex/hex.dart'; -import 'package:on_chain/on_chain.dart'; - -class TronTRC20TransactionModel extends TronTransactionModel { - String? transactionId; - - String? tokenSymbol; - - int? timestamp; - - @override - String? from; - - @override - String? to; - - String? value; - - @override - String get hash => transactionId!; - - @override - DateTime get date => DateTime.fromMillisecondsSinceEpoch(timestamp ?? 0); - - @override - BigInt? get amount => BigInt.parse(value ?? '0'); - - @override - int? get fee => 0; - - TronTRC20TransactionModel({ - this.transactionId, - this.tokenSymbol, - this.timestamp, - this.from, - this.to, - this.value, - }); - - TronTRC20TransactionModel.fromJson(Map json) { - transactionId = json['transaction_id']; - tokenSymbol = json['token_info'] != null ? json['token_info']['symbol'] : null; - timestamp = json['block_timestamp']; - from = json['from']; - to = json['to']; - value = json['value']; - } -} - -class TronTransactionModel { - List? ret; - String? txID; - int? blockTimestamp; - List? contracts; - - /// Getters to extract out the needed/useful information directly from the model params - /// Without having to go through extra steps in the methods that use this model. - bool get isError { - if (ret?.first.contractRet == null) return true; - - return ret?.first.contractRet != "SUCCESS"; - } - - String get hash => txID!; - - DateTime get date => DateTime.fromMillisecondsSinceEpoch(blockTimestamp ?? 0); - - String? get from => contracts?.first.parameter?.value?.ownerAddress; - - String? get to => contracts?.first.parameter?.value?.receiverAddress; - - BigInt? get amount => contracts?.first.parameter?.value?.txAmount; - - int? get fee => ret?.first.fee; - - String? get contractAddress => contracts?.first.parameter?.value?.contractAddress; - - TronTransactionModel({ - this.ret, - this.txID, - this.blockTimestamp, - this.contracts, - }); - - TronTransactionModel.fromJson(Map json) { - if (json['ret'] != null) { - ret = []; - json['ret'].forEach((v) { - ret!.add(Ret.fromJson(v)); - }); - } - txID = json['txID']; - blockTimestamp = json['block_timestamp']; - contracts = json['raw_data'] != null - ? (json['raw_data']['contract'] as List) - .map((e) => Contract.fromJson(e as Map)) - .toList() - : null; - } -} - -class Ret { - String? contractRet; - int? fee; - - Ret({this.contractRet, this.fee}); - - Ret.fromJson(Map json) { - contractRet = json['contractRet']; - fee = json['fee']; - } -} - -class Contract { - Parameter? parameter; - String? type; - - Contract({this.parameter, this.type}); - - Contract.fromJson(Map json) { - parameter = json['parameter'] != null ? Parameter.fromJson(json['parameter']) : null; - type = json['type']; - } -} - -class Parameter { - Value? value; - String? typeUrl; - - Parameter({this.value, this.typeUrl}); - - Parameter.fromJson(Map json) { - value = json['value'] != null ? Value.fromJson(json['value']) : null; - typeUrl = json['type_url']; - } -} - -class Value { - String? data; - String? ownerAddress; - String? contractAddress; - int? amount; - String? toAddress; - String? assetName; - - //Getters to extract address for tron transactions - /// If the contract address is null, it returns the toAddress - /// If it's not null, it decodes the data field and gets the receiver address. - String? get receiverAddress { - if (contractAddress == null) return toAddress; - - if (data == null) return null; - - return _decodeAddressFromEncodedDataField(data!); - } - - //Getters to extract amount for tron transactions - /// If the contract address is null, it returns the amount - /// If it's not null, it decodes the data field and gets the tx amount. - BigInt? get txAmount { - if (contractAddress == null) return BigInt.from(amount ?? 0); - - if (data == null) return null; - - return _decodeAmountInvolvedFromEncodedDataField(data!); - } - - Value( - {this.data, - this.ownerAddress, - this.contractAddress, - this.amount, - this.toAddress, - this.assetName}); - - Value.fromJson(Map json) { - data = json['data']; - ownerAddress = json['owner_address']; - contractAddress = json['contract_address']; - amount = json['amount']; - toAddress = json['to_address']; - assetName = json['asset_name']; - } - - /// To get the address from the encoded data field - String _decodeAddressFromEncodedDataField(String output) { - // To get the receiver address from the encoded params - output = output.replaceFirst('0x', '').substring(8); - final abiCoder = ABICoder.fromType('address'); - final decoded = abiCoder.decode(AbiParameter.bytes, hex.decode(output)); - final tronAddress = TronAddress.fromEthAddress((decoded.result as ETHAddress).toBytes()); - - return tronAddress.toString(); - } - - /// To get the amount from the encoded data field - BigInt _decodeAmountInvolvedFromEncodedDataField(String output) { - output = output.replaceFirst('0x', '').substring(72); - final amountAbiCoder = ABICoder.fromType('uint256'); - final decodedA = amountAbiCoder.decode(AbiParameter.uint256, hex.decode(output)); - final amount = decodedA.result as BigInt; - - return amount; - } -} diff --git a/cw_tron/lib/tron_wallet.dart b/cw_tron/lib/tron_wallet.dart deleted file mode 100644 index c8d9fb92..00000000 --- a/cw_tron/lib/tron_wallet.dart +++ /dev/null @@ -1,676 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:developer'; -import 'dart:io'; - -import 'package:bip39/bip39.dart' as bip39; -import 'package:blockchain_utils/blockchain_utils.dart'; -import 'package:cw_core/cake_hive.dart'; -import 'package:cw_core/crypto_currency.dart'; -import 'package:cw_core/encryption_file_utils.dart'; -import 'package:cw_core/node.dart'; -import 'package:cw_core/pathForWallet.dart'; -import 'package:cw_core/pending_transaction.dart'; -import 'package:cw_core/sync_status.dart'; -import 'package:cw_core/transaction_direction.dart'; -import 'package:cw_core/transaction_priority.dart'; -import 'package:cw_core/wallet_addresses.dart'; -import 'package:cw_core/wallet_base.dart'; -import 'package:cw_core/wallet_info.dart'; -import 'package:cw_core/wallet_keys_file.dart'; -import 'package:cw_core/wallet_type.dart'; -import 'package:cw_tron/default_tron_tokens.dart'; -import 'package:cw_tron/tron_abi.dart'; -import 'package:cw_tron/tron_balance.dart'; -import 'package:cw_tron/tron_client.dart'; -import 'package:cw_tron/tron_exception.dart'; -import 'package:cw_core/tron_token.dart'; -import 'package:cw_tron/tron_transaction_credentials.dart'; -import 'package:cw_tron/tron_transaction_history.dart'; -import 'package:cw_tron/tron_transaction_info.dart'; -import 'package:cw_tron/tron_wallet_addresses.dart'; -import 'package:hive/hive.dart'; -import 'package:mobx/mobx.dart'; -import 'package:on_chain/on_chain.dart'; - -part 'tron_wallet.g.dart'; - -class TronWallet = TronWalletBase with _$TronWallet; - -abstract class TronWalletBase - extends WalletBase - with Store, WalletKeysFile { - TronWalletBase({ - required WalletInfo walletInfo, - required DerivationInfo derivationInfo, - String? mnemonic, - String? privateKey, - required String password, - TronBalance? initialBalance, - required this.encryptionFileUtils, - this.passphrase, - }) : syncStatus = const NotConnectedSyncStatus(), - _password = password, - _mnemonic = mnemonic, - _hexPrivateKey = privateKey, - _client = TronClient(), - walletAddresses = TronWalletAddresses(walletInfo), - balance = ObservableMap.of( - {CryptoCurrency.trx: initialBalance ?? TronBalance(BigInt.zero)}, - ), - super(walletInfo, derivationInfo) { - this.walletInfo = walletInfo; - transactionHistory = TronTransactionHistory( - walletInfo: walletInfo, password: password, encryptionFileUtils: encryptionFileUtils); - - if (!CakeHive.isAdapterRegistered(TronToken.typeId)) { - CakeHive.registerAdapter(TronTokenAdapter()); - } - } - - final String? _mnemonic; - final String? _hexPrivateKey; - final String _password; - final EncryptionFileUtils encryptionFileUtils; - - late final Box tronTokensBox; - - late final TronPrivateKey _tronPrivateKey; - - late final TronPublicKey _tronPublicKey; - - TronPublicKey get tronPublicKey => _tronPublicKey; - - TronPrivateKey get tronPrivateKey => _tronPrivateKey; - - late String _tronAddress; - - late final TronClient _client; - - Timer? _transactionsUpdateTimer; - - @override - WalletAddresses walletAddresses; - - @observable - String? nativeTxEstimatedFee; - - @observable - String? trc20EstimatedFee; - - @override - @observable - SyncStatus syncStatus; - - @override - @observable - late ObservableMap balance; - - Future init() async { - await initTronTokensBox(); - - await walletAddresses.init(); - await transactionHistory.init(); - _tronPrivateKey = await getPrivateKey( - mnemonic: _mnemonic, - privateKey: _hexPrivateKey, - password: _password, - passphrase: passphrase, - ); - - _tronPublicKey = _tronPrivateKey.publicKey(); - - _tronAddress = _tronPublicKey.toAddress().toString(); - - walletAddresses.address = _tronAddress; - - await save(); - } - - static Future open({ - required String name, - required String password, - required WalletInfo walletInfo, - required EncryptionFileUtils encryptionFileUtils, - }) async { - final hasKeysFile = await WalletKeysFile.hasKeysFile(name, walletInfo.type); - final path = await pathForWallet(name: name, type: walletInfo.type); - - Map? data; - try { - final jsonSource = await encryptionFileUtils.read(path: path, password: password); - - data = json.decode(jsonSource) as Map; - } catch (e) { - if (!hasKeysFile) rethrow; - } - - final balance = TronBalance.fromJSON(data?['balance'] as String?) ?? TronBalance(BigInt.zero); - - final WalletKeysData keysData; - // Migrate wallet from the old scheme to then new .keys file scheme - if (!hasKeysFile) { - final mnemonic = data!['mnemonic'] as String?; - final privateKey = data['private_key'] as String?; - final passphrase = data['passphrase'] as String?; - - keysData = WalletKeysData(mnemonic: mnemonic, privateKey: privateKey, passphrase: passphrase); - } else { - keysData = await WalletKeysFile.readKeysFile( - name, - walletInfo.type, - password, - encryptionFileUtils, - ); - } - - final derivationInfo = await walletInfo.getDerivationInfo(); - - return TronWallet( - walletInfo: walletInfo, - derivationInfo: derivationInfo, - password: password, - mnemonic: keysData.mnemonic, - privateKey: keysData.privateKey, - passphrase: keysData.passphrase, - initialBalance: balance, - encryptionFileUtils: encryptionFileUtils, - ); - } - - void addInitialTokens() { - final initialTronTokens = DefaultTronTokens().initialTronTokens; - - for (var token in initialTronTokens) { - if (!tronTokensBox.containsKey(token.contractAddress)) { - tronTokensBox.put(token.contractAddress, token); - } else { - // update existing token - final existingToken = tronTokensBox.get(token.contractAddress); - tronTokensBox.put( - token.contractAddress, TronToken.copyWith(token, enabled: existingToken!.enabled)); - } - } - } - - Future initTronTokensBox() async { - final boxName = "${walletInfo.name.replaceAll(" ", "_")}_${TronToken.boxName}"; - - tronTokensBox = await CakeHive.openBox(boxName); - } - - String idFor(String name, WalletType type) => '${walletTypeToString(type).toLowerCase()}_$name'; - - Future getPrivateKey({ - String? mnemonic, - String? privateKey, - required String password, - String? passphrase, - }) async { - assert(mnemonic != null || privateKey != null); - - if (privateKey != null) return TronPrivateKey(privateKey); - - final seed = bip39.mnemonicToSeed(mnemonic!, passphrase: passphrase ?? ''); - - // Derive a TRON private key from the seed - final bip44 = Bip44.fromSeed(seed, Bip44Coins.tron); - - final childKey = bip44.deriveDefaultPath; - - return TronPrivateKey.fromBytes(childKey.privateKey.raw); - } - - @override - int calculateEstimatedFee(TransactionPriority priority, int? amount) => 0; - - @override - Future changePassword(String password) => throw UnimplementedError("changePassword"); - - @override - Future close({bool shouldCleanup = false}) async => _transactionsUpdateTimer?.cancel(); - - @action - @override - Future connectToNode({required Node node}) async { - try { - syncStatus = ConnectingSyncStatus(); - - final isConnected = _client.connect(node); - - if (!isConnected) { - throw Exception("${walletInfo.type.name.toUpperCase()} Node connection failed"); - } - - _getEstimatedFees(); - _setTransactionUpdateTimer(); - - syncStatus = ConnectedSyncStatus(); - } catch (e) { - syncStatus = FailedSyncStatus(); - } - } - - Future _getEstimatedFees() async { - final nativeFee = await _getNativeTxFee(); - nativeTxEstimatedFee = TronHelper.fromSun(BigInt.from(nativeFee)); - - final trc20Fee = await _getTrc20TxFee(); - trc20EstimatedFee = TronHelper.fromSun(BigInt.from(trc20Fee)); - - log('Native Estimated Fee: $nativeTxEstimatedFee'); - log('TRC20 Estimated Fee: $trc20EstimatedFee'); - } - - Future _getNativeTxFee() async { - try { - final fee = await _client.getEstimatedFee(_tronPublicKey.toAddress()); - return fee; - } catch (e) { - log(e.toString()); - return 0; - } - } - - Future _getTrc20TxFee() async { - try { - final trc20fee = await _client.getTRCEstimatedFee(_tronPublicKey.toAddress()); - return trc20fee; - } catch (e) { - log(e.toString()); - return 0; - } - } - - @action - @override - Future startSync() async { - try { - syncStatus = AttemptingSyncStatus(); - - // Verify node health before attempting to sync - final isHealthy = await checkNodeHealth(); - if (!isHealthy) { - syncStatus = FailedSyncStatus(); - return; - } - await _updateBalance(); - await fetchTransactions(); - fetchTrc20ExcludedTransactions(); - - syncStatus = SyncedSyncStatus(); - } catch (e) { - syncStatus = FailedSyncStatus(); - } - } - - @override - Future createTransaction(Object credentials) async { - final tronCredentials = credentials as TronTransactionCredentials; - - final outputs = tronCredentials.outputs; - - final hasMultiDestination = outputs.length > 1; - - final transactionCurrency = balance.keys.firstWhere( - (currency) => - currency.title == tronCredentials.currency.title && - currency.tag == tronCredentials.currency.tag, - orElse: () => throw Exception( - 'Currency ${tronCredentials.currency.title} ${tronCredentials.currency.tag} is not accessible in the wallet, try to enable it first.')); - - final walletBalanceForCurrency = balance[transactionCurrency]!.balance; - - BigInt totalAmount = BigInt.zero; - bool shouldSendAll = false; - if (hasMultiDestination) { - if (outputs.any((item) => item.sendAll || (item.formattedCryptoAmount ?? 0) <= 0)) { - throw TronTransactionCreationException(transactionCurrency); - } - - final totalAmountFromCredentials = - outputs.fold(0, (acc, value) => acc + (value.formattedCryptoAmount ?? 0)); - - totalAmount = BigInt.from(totalAmountFromCredentials); - - if (walletBalanceForCurrency < totalAmount) { - throw TronTransactionCreationException(transactionCurrency); - } - } else { - final output = outputs.first; - - shouldSendAll = output.sendAll; - - if (shouldSendAll) { - totalAmount = walletBalanceForCurrency; - } else { - final totalOriginalAmount = double.parse(output.cryptoAmount ?? '0.0'); - totalAmount = TronHelper.toSun(totalOriginalAmount.toString()); - } - - if (walletBalanceForCurrency < totalAmount || totalAmount < BigInt.zero) { - throw TronTransactionCreationException(transactionCurrency); - } - } - - final tronBalance = balance[CryptoCurrency.trx]?.balance ?? BigInt.zero; - - final pendingTransaction = await _client.signTransaction( - ownerPrivKey: _tronPrivateKey, - toAddress: tronCredentials.outputs.first.isParsedAddress - ? tronCredentials.outputs.first.extractedAddress! - : tronCredentials.outputs.first.address, - amount: TronHelper.fromSun(totalAmount), - currency: transactionCurrency, - tronBalance: tronBalance, - sendAll: shouldSendAll, - ); - - return pendingTransaction; - } - - @override - Future updateTransactionsHistory() async { - await Future.wait([ - fetchTransactions(), - fetchTrc20ExcludedTransactions(), - ]); - } - - @override - Future> fetchTransactions() async { - final address = _tronAddress; - - final transactions = await _client.fetchTransactions(address); - - final Map result = {}; - - final contract = ContractABI.fromJson(trc20Abi, isTron: true); - - final ownerAddress = TronAddress(_tronAddress); - - for (var transactionModel in transactions) { - if (transactionModel.isError) { - continue; - } - - // Filter out spam transaactions that involve receiving TRC10 assets transaction, we deal with TRX and TRC20 transactions - if (transactionModel.contracts?.first.type == "TransferAssetContract") { - continue; - } - - String? tokenSymbol; - if (transactionModel.contractAddress != null) { - final tokenAddress = TronAddress(transactionModel.contractAddress!); - - tokenSymbol = (await _client.getTokenDetail( - contract, - "symbol", - ownerAddress, - tokenAddress, - ) as String?) ?? - ''; - } - - result[transactionModel.hash] = TronTransactionInfo( - id: transactionModel.hash, - tronAmount: transactionModel.amount ?? BigInt.zero, - direction: TronAddress(transactionModel.from!, visible: false).toAddress() == address - ? TransactionDirection.outgoing - : TransactionDirection.incoming, - blockTime: transactionModel.date, - txFee: transactionModel.fee, - tokenSymbol: tokenSymbol ?? "TRX", - to: transactionModel.to, - from: transactionModel.from, - isPending: false, - ); - } - - transactionHistory.addMany(result); - - await transactionHistory.save(); - - return transactionHistory.transactions; - } - - Future fetchTrc20ExcludedTransactions() async { - final address = _tronAddress; - - final transactions = await _client.fetchTrc20ExcludedTransactions(address); - - final Map result = {}; - - for (var transactionModel in transactions) { - if (transactionHistory.transactions.containsKey(transactionModel.hash)) { - continue; - } - - result[transactionModel.hash] = TronTransactionInfo( - id: transactionModel.hash, - tronAmount: transactionModel.amount ?? BigInt.zero, - direction: transactionModel.from! == address - ? TransactionDirection.outgoing - : TransactionDirection.incoming, - blockTime: transactionModel.date, - txFee: transactionModel.fee, - tokenSymbol: transactionModel.tokenSymbol ?? "TRX", - to: transactionModel.to, - from: transactionModel.from, - isPending: false, - ); - } - - transactionHistory.addMany(result); - - await transactionHistory.save(); - } - - @override - Object get keys => throw UnimplementedError("keys"); - - @override - Future rescan({required int height}) => throw UnimplementedError("rescan"); - - @override - Future save() async { - if (!(await WalletKeysFile.hasKeysFile(walletInfo.name, walletInfo.type))) { - await saveKeysFile(_password, encryptionFileUtils); - saveKeysFile(_password, encryptionFileUtils, true); - } - - await walletAddresses.updateAddressesInBox(); - final path = await makePath(); - await encryptionFileUtils.write(path: path, password: _password, data: toJSON()); - await transactionHistory.save(); - } - - @override - String? get seed => _mnemonic; - - @override - String get privateKey => _tronPrivateKey.toHex(); - - @override - WalletKeysData get walletKeysData => WalletKeysData( - mnemonic: _mnemonic, - privateKey: privateKey, - passphrase: passphrase, - ); - - String toJSON() => json.encode({ - 'mnemonic': _mnemonic, - 'private_key': privateKey, - 'balance': balance[currency]!.toJSON(), - 'passphrase': passphrase, - }); - - Future _updateBalance() async { - balance[currency] = await _fetchTronBalance(); - - await _fetchTronTokenBalances(); - await save(); - } - - Future _fetchTronBalance() async { - final balance = await _client.getBalance(_tronPublicKey.toAddress()); - return TronBalance(balance); - } - - Future _fetchTronTokenBalances() async { - for (var token in tronTokensBox.values) { - try { - if (token.enabled) { - balance[token] = await _client.fetchTronTokenBalances( - _tronAddress, - token.contractAddress, - ); - } else { - balance.remove(token); - } - } catch (_) {} - } - } - - @override - Future? updateBalance() async => await _updateBalance(); - - @override - Future checkNodeHealth() async { - try { - // Check native balance - await _client.getBalance(_tronPublicKey.toAddress(), throwOnError: true); - - // Check USDT token balance - const usdtContractAddress = "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"; - await _client.fetchTronTokenBalances(_tronAddress, usdtContractAddress, throwOnError: true); - - return true; - } catch (e) { - return false; - } - } - - List get tronTokenCurrencies => tronTokensBox.values.toList(); - - Future addTronToken(TronToken token) async { - String? iconPath; - if ((token.iconPath == null || token.iconPath!.isEmpty) && !token.isPotentialScam) { - try { - iconPath = CryptoCurrency.all - .firstWhere((element) => element.title.toUpperCase() == token.symbol.toUpperCase()) - .iconPath; - } catch (_) {} - } else if (!token.isPotentialScam) { - iconPath = token.iconPath; - } - - final newToken = TronToken( - name: token.name, - symbol: token.symbol, - contractAddress: token.contractAddress, - decimal: token.decimal, - enabled: token.enabled, - tag: token.tag ?? "TRX", - iconPath: iconPath, - isPotentialScam: token.isPotentialScam, - ); - - await tronTokensBox.put(newToken.contractAddress, newToken); - - if (newToken.enabled) { - balance[newToken] = await _client.fetchTronTokenBalances( - _tronAddress, - newToken.contractAddress, - ); - } else { - balance.remove(newToken); - } - } - - Future deleteTronToken(TronToken token) async { - if (tronTokensBox.isOpen) { - await tronTokensBox.delete(token.contractAddress); - } - - balance.remove(token); - await _removeTokenTransactionsInHistory(token); - _updateBalance(); - } - - Future _removeTokenTransactionsInHistory(TronToken token) async { - transactionHistory.transactions.removeWhere((key, value) => value.tokenSymbol == token.title); - await transactionHistory.save(); - } - - Future getTronToken(String contractAddress) async => - await _client.getTronToken(contractAddress, _tronAddress); - - @override - Future renameWalletFiles(String newWalletName) async { - const transactionHistoryFileNameForWallet = 'tron_transactions.json'; - - final currentWalletPath = await pathForWallet(name: walletInfo.name, type: type); - final currentWalletFile = File(currentWalletPath); - - final currentDirPath = await pathForWalletDir(name: walletInfo.name, type: type); - final currentTransactionsFile = File('$currentDirPath/$transactionHistoryFileNameForWallet'); - - // Copies current wallet files into new wallet name's dir and files - if (currentWalletFile.existsSync()) { - final newWalletPath = await pathForWallet(name: newWalletName, type: type); - await currentWalletFile.copy(newWalletPath); - } - if (currentTransactionsFile.existsSync()) { - final newDirPath = await pathForWalletDir(name: newWalletName, type: type); - await currentTransactionsFile.copy('$newDirPath/$transactionHistoryFileNameForWallet'); - } - - // Delete old name's dir and files - await Directory(currentDirPath).delete(recursive: true); - } - - void _setTransactionUpdateTimer() { - if (_transactionsUpdateTimer?.isActive ?? false) { - _transactionsUpdateTimer!.cancel(); - } - - _transactionsUpdateTimer = Timer.periodic(const Duration(seconds: 30), (_) async { - _updateBalance(); - await fetchTransactions(); - fetchTrc20ExcludedTransactions(); - }); - } - - @override - Future signMessage(String message, {String? address}) async { - return _tronPrivateKey.signPersonalMessage(ascii.encode(message)); - } - - @override - Future verifyMessage(String message, String signature, {String? address}) async { - if (address == null) { - return false; - } - TronPublicKey pubKey = TronPublicKey.fromPersonalSignature(ascii.encode(message), signature)!; - return pubKey.toAddress().toString() == address; - } - - String getTronBase58AddressFromHex(String hexAddress) => TronAddress(hexAddress).toAddress(); - - void updateScanProviderUsageState(bool isEnabled) { - if (isEnabled) { - fetchTransactions(); - fetchTrc20ExcludedTransactions(); - _setTransactionUpdateTimer(); - } else { - _transactionsUpdateTimer?.cancel(); - } - } - - @override - String get password => _password; - - @override - final String? passphrase; -} diff --git a/cw_tron/lib/tron_wallet_addresses.dart b/cw_tron/lib/tron_wallet_addresses.dart deleted file mode 100644 index 99767e96..00000000 --- a/cw_tron/lib/tron_wallet_addresses.dart +++ /dev/null @@ -1,43 +0,0 @@ -import 'dart:developer'; - -import 'package:cw_core/payment_uris.dart'; -import 'package:cw_core/wallet_addresses.dart'; -import 'package:cw_core/wallet_info.dart'; -import 'package:mobx/mobx.dart'; - -part 'tron_wallet_addresses.g.dart'; - -class TronWalletAddresses = TronWalletAddressesBase with _$TronWalletAddresses; - -abstract class TronWalletAddressesBase extends WalletAddresses with Store { - TronWalletAddressesBase(WalletInfo walletInfo) - : address = '', - super(walletInfo); - - @override - @observable - String address; - - @override - String get primaryAddress => address; - - @override - Future init() async { - address = walletInfo.address; - await updateAddressesInBox(); - } - - @override - Future updateAddressesInBox() async { - try { - addressesMap.clear(); - addressesMap[address] = ''; - await saveAddressesInBox(); - } catch (e) { - log(e.toString()); - } - } - - @override - PaymentURI getPaymentUri(String amount) => TronURI(amount: amount, address: address); -} diff --git a/cw_tron/lib/tron_wallet_creation_credentials.dart b/cw_tron/lib/tron_wallet_creation_credentials.dart deleted file mode 100644 index 402cff2f..00000000 --- a/cw_tron/lib/tron_wallet_creation_credentials.dart +++ /dev/null @@ -1,47 +0,0 @@ -import 'package:cw_core/wallet_credentials.dart'; -import 'package:cw_core/wallet_info.dart'; - -class TronNewWalletCredentials extends WalletCredentials { - TronNewWalletCredentials({ - required String name, - WalletInfo? walletInfo, - String? password, - this.mnemonic, - String? passphrase, - }) : super( - name: name, - walletInfo: walletInfo, - password: password, - passphrase: passphrase, - ); - - final String? mnemonic; -} - -class TronRestoreWalletFromSeedCredentials extends WalletCredentials { - TronRestoreWalletFromSeedCredentials({ - required String name, - required String password, - required this.mnemonic, - WalletInfo? walletInfo, - String? passphrase, - }) : super( - name: name, - password: password, - walletInfo: walletInfo, - passphrase: passphrase, - ); - - final String mnemonic; -} - -class TronRestoreWalletFromPrivateKey extends WalletCredentials { - TronRestoreWalletFromPrivateKey( - {required String name, - required String password, - required this.privateKey, - WalletInfo? walletInfo}) - : super(name: name, password: password, walletInfo: walletInfo); - - final String privateKey; -} diff --git a/cw_tron/lib/tron_wallet_service.dart b/cw_tron/lib/tron_wallet_service.dart deleted file mode 100644 index cf83b915..00000000 --- a/cw_tron/lib/tron_wallet_service.dart +++ /dev/null @@ -1,180 +0,0 @@ -import 'dart:io'; - -import 'package:bip39/bip39.dart' as bip39; -import 'package:cw_core/balance.dart'; -import 'package:cw_core/encryption_file_utils.dart'; -import 'package:cw_core/pathForWallet.dart'; -import 'package:cw_core/transaction_history.dart'; -import 'package:cw_core/transaction_info.dart'; -import 'package:cw_core/wallet_base.dart'; -import 'package:cw_core/wallet_info.dart'; -import 'package:cw_core/wallet_service.dart'; -import 'package:cw_core/wallet_type.dart'; -import 'package:cw_tron/tron_client.dart'; -import 'package:cw_tron/tron_exception.dart'; -import 'package:cw_tron/tron_wallet.dart'; -import 'package:cw_tron/tron_wallet_creation_credentials.dart'; -import 'package:hive/hive.dart'; - -class TronWalletService extends WalletService< - TronNewWalletCredentials, - TronRestoreWalletFromSeedCredentials, - TronRestoreWalletFromPrivateKey, - TronNewWalletCredentials> { - TronWalletService({required this.client, required this.isDirect}); - - late TronClient client; - - final bool isDirect; - - @override - WalletType getType() => WalletType.tron; - - @override - Future create(TronNewWalletCredentials credentials, {bool? isTestnet}) async { - final strength = credentials.seedPhraseLength == 24 ? 256 : 128; - - final mnemonic = credentials.mnemonic ?? bip39.generateMnemonic(strength: strength); - - final wallet = TronWallet( - walletInfo: credentials.walletInfo!, - derivationInfo: await credentials.walletInfo!.getDerivationInfo(), - mnemonic: mnemonic, - password: credentials.password!, - passphrase: credentials.passphrase, - encryptionFileUtils: encryptionFileUtilsFor(isDirect), - ); - - await wallet.init(); - wallet.addInitialTokens(); - await wallet.save(); - - return wallet; - } - - @override - Future openWallet(String name, String password) async { - final walletInfo = await WalletInfo.get(name, getType()); - if (walletInfo == null) { - throw Exception('Wallet not found'); - } - - try { - final wallet = await TronWalletBase.open( - name: name, - password: password, - walletInfo: walletInfo, - encryptionFileUtils: encryptionFileUtilsFor(isDirect), - ); - - await wallet.init(); - wallet.addInitialTokens(); - await wallet.save(); - saveBackup(name); - return wallet; - } catch (_) { - await restoreWalletFilesFromBackup(name); - - final wallet = await TronWalletBase.open( - name: name, - password: password, - walletInfo: walletInfo, - encryptionFileUtils: encryptionFileUtilsFor(isDirect), - ); - - await wallet.init(); - wallet.addInitialTokens(); - await wallet.save(); - return wallet; - } - } - - @override - Future restoreFromKeys( - TronRestoreWalletFromPrivateKey credentials, { - bool? isTestnet, - }) async { - final wallet = TronWallet( - password: credentials.password!, - privateKey: credentials.privateKey, - walletInfo: credentials.walletInfo!, - derivationInfo: await credentials.walletInfo!.getDerivationInfo(), - encryptionFileUtils: encryptionFileUtilsFor(isDirect), - ); - - await wallet.init(); - wallet.addInitialTokens(); - await wallet.save(); - - return wallet; - } - - @override - Future restoreFromSeed( - TronRestoreWalletFromSeedCredentials credentials, { - bool? isTestnet, - }) async { - if (!bip39.validateMnemonic(credentials.mnemonic)) { - throw TronMnemonicIsIncorrectException(); - } - - final wallet = TronWallet( - password: credentials.password!, - mnemonic: credentials.mnemonic, - walletInfo: credentials.walletInfo!, - derivationInfo: await credentials.walletInfo!.getDerivationInfo(), - passphrase: credentials.passphrase, - encryptionFileUtils: encryptionFileUtilsFor(isDirect), - ); - - await wallet.init(); - wallet.addInitialTokens(); - await wallet.save(); - - return wallet; - } - - @override - Future rename(String currentName, String password, String newName) async { - final currentWalletInfo = await WalletInfo.get(currentName, getType()); - if (currentWalletInfo == null) { - throw Exception('Wallet not found'); - } - final currentWallet = await TronWalletBase.open( - password: password, - name: currentName, - walletInfo: currentWalletInfo, - encryptionFileUtils: encryptionFileUtilsFor(isDirect), - ); - - await currentWallet.renameWalletFiles(newName); - await saveBackup(newName); - - final newWalletInfo = currentWalletInfo; - newWalletInfo.id = WalletBase.idFor(newName, getType()); - newWalletInfo.name = newName; - - await newWalletInfo.save(); - } - - @override - Future isWalletExit(String name) async => - File(await pathForWallet(name: name, type: getType())).existsSync(); - - @override - Future remove(String wallet) async { - File(await pathForWalletDir(name: wallet, type: getType())).delete(recursive: true); - final walletInfo = await WalletInfo.get(wallet, getType()); - if (walletInfo == null) { - throw Exception('Wallet not found'); - } - await WalletInfo.delete(walletInfo); - } - - @override - Future, TransactionInfo>> - restoreFromHardwareWallet(TronNewWalletCredentials credentials) { - // TODO: implement restoreFromHardwareWallet - throw UnimplementedError(); - } -} diff --git a/cw_tron/pubspec.yaml b/cw_tron/pubspec.yaml deleted file mode 100644 index 18d17185..00000000 --- a/cw_tron/pubspec.yaml +++ /dev/null @@ -1,39 +0,0 @@ -name: cw_tron -description: A new Flutter package project. -version: 0.0.1 -publish_to: none -homepage: https://github.com/Such-Software/hash-wallet - -environment: - sdk: '>=3.0.6 <4.0.0' - flutter: ">=1.17.0" - -dependencies: - flutter: - sdk: flutter - cw_core: - path: ../cw_core - cw_evm: - path: ../cw_evm - on_chain: - git: - url: https://github.com/cake-tech/on_chain.git - ref: 096865a8c6b89c260beadfec04f7e184c40a3273 - blockchain_utils: - git: - url: https://github.com/cake-tech/blockchain_utils - ref: cake-update-v2 - mobx: ^2.3.0+1 - bip39: ^1.0.6 - hive: ^2.2.3 - -dev_dependencies: - flutter_test: - sdk: flutter - flutter_lints: ^2.0.0 - build_runner: ^2.4.15 - mobx_codegen: ^2.1.1 - hive_generator: ^2.0.1 -flutter: - # assets: - # - images/a_dot_burr.jpeg diff --git a/cw_tron/test/cw_tron_test.dart b/cw_tron/test/cw_tron_test.dart deleted file mode 100644 index 55a2b04b..00000000 --- a/cw_tron/test/cw_tron_test.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; - -import 'package:cw_tron/cw_tron.dart'; - -void main() { - test('adds one to input values', () { - final calculator = Calculator(); - expect(calculator.addOne(2), 3); - expect(calculator.addOne(-7), -6); - expect(calculator.addOne(0), 1); - }); -} diff --git a/cw_zano/.gitignore b/cw_zano/.gitignore deleted file mode 100644 index e9dc58d3..00000000 --- a/cw_zano/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -.DS_Store -.dart_tool/ - -.packages -.pub/ - -build/ diff --git a/cw_zano/.metadata b/cw_zano/.metadata deleted file mode 100644 index cb1a29e7..00000000 --- a/cw_zano/.metadata +++ /dev/null @@ -1,10 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: 4d7946a68d26794349189cf21b3f68cc6fe61dcb - channel: stable - -project_type: plugin diff --git a/cw_zano/CHANGELOG.md b/cw_zano/CHANGELOG.md deleted file mode 100644 index 41cc7d81..00000000 --- a/cw_zano/CHANGELOG.md +++ /dev/null @@ -1,3 +0,0 @@ -## 0.0.1 - -* TODO: Describe initial release. diff --git a/cw_zano/LICENSE b/cw_zano/LICENSE deleted file mode 100644 index ba75c69f..00000000 --- a/cw_zano/LICENSE +++ /dev/null @@ -1 +0,0 @@ -TODO: Add your license here. diff --git a/cw_zano/README.md b/cw_zano/README.md deleted file mode 100644 index d8f977d1..00000000 --- a/cw_zano/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# cw_zano - -Zano wallet module for Cake Wallet. Provides a Dart wrapper around the Zano wallet API with typed models and transaction helpers. - -## Features - -- Wallet lifecycle and status queries via `ZanoWalletApi`. -- Typed models for balances, transfers, recent history, and wallet info. -- Build and submit transfers; pending transaction modeling. -- Address and asset utilities, formatter helpers. - -## Usage - -See `lib/zano_wallet_api.dart` and `lib/zano_wallet.dart` for the high-level API. Typical flow: - -```dart -final api = ZanoWalletApi(); -final info = await api.getWalletInfo(); -final balance = await api.getBalance(); -// create transfer params and broadcast -``` - -Consult `lib/api/model/` for full set of supported request/response models. diff --git a/cw_zano/lib/api/consts.dart b/cw_zano/lib/api/consts.dart deleted file mode 100644 index 80002b88..00000000 --- a/cw_zano/lib/api/consts.dart +++ /dev/null @@ -1,6 +0,0 @@ -class Consts { - static const errorWrongSeed = 'WRONG_SEED'; - static const errorAlreadyExists = 'ALREADY_EXISTS'; - static const errorWalletWrongId = 'WALLET_WRONG_ID'; - static const errorBusy = 'BUSY'; -} \ No newline at end of file diff --git a/cw_zano/lib/api/model/asset_id_params.dart b/cw_zano/lib/api/model/asset_id_params.dart deleted file mode 100644 index 3856f5f4..00000000 --- a/cw_zano/lib/api/model/asset_id_params.dart +++ /dev/null @@ -1,9 +0,0 @@ -class AssetIdParams { - final String assetId; - - AssetIdParams({required this.assetId}); - - Map toJson() => { - 'asset_id': assetId, - }; -} \ No newline at end of file diff --git a/cw_zano/lib/api/model/balance.dart b/cw_zano/lib/api/model/balance.dart deleted file mode 100644 index b796338f..00000000 --- a/cw_zano/lib/api/model/balance.dart +++ /dev/null @@ -1,32 +0,0 @@ -import 'package:cw_core/zano_asset.dart'; -import 'package:cw_zano/model/zano_asset.dart'; -import 'package:cw_zano/zano_formatter.dart'; - -class Balance { - final ZanoAsset assetInfo; - final BigInt awaitingIn; - final BigInt awaitingOut; - final BigInt total; - final BigInt unlocked; - - Balance( - {required this.assetInfo, - required this.awaitingIn, - required this.awaitingOut, - required this.total, - required this.unlocked}); - - String get assetId => assetInfo.assetId; - - @override - String toString() => '$assetInfo: $total/$unlocked'; - - factory Balance.fromJson(Map json) => Balance( - assetInfo: - ZanoAsset.fromJson(json['asset_info'] as Map? ?? {}), - awaitingIn: ZanoFormatter.bigIntFromDynamic(json['awaiting_in']), - awaitingOut: ZanoFormatter.bigIntFromDynamic(json['awaiting_out']), - total: ZanoFormatter.bigIntFromDynamic(json['total']), - unlocked: ZanoFormatter.bigIntFromDynamic(json['unlocked']), - ); -} diff --git a/cw_zano/lib/api/model/create_wallet_result.dart b/cw_zano/lib/api/model/create_wallet_result.dart deleted file mode 100644 index 236911db..00000000 --- a/cw_zano/lib/api/model/create_wallet_result.dart +++ /dev/null @@ -1,52 +0,0 @@ -import 'package:cw_zano/api/model/recent_history.dart'; -import 'package:cw_zano/api/model/wi.dart'; -import 'package:cw_zano/zano_wallet.dart'; - -class CreateWalletResult { - final String name; - final String pass; - final RecentHistory recentHistory; - final bool recovered; - final int walletFileSize; - final int walletId; - final int walletLocalBcSize; - final Wi wi; - final String privateSpendKey; - final String privateViewKey; - final String publicSpendKey; - final String publicViewKey; - - CreateWalletResult( - {required this.name, - required this.pass, - required this.recentHistory, - required this.recovered, - required this.walletFileSize, - required this.walletId, - required this.walletLocalBcSize, - required this.wi, - required this.privateSpendKey, - required this.privateViewKey, - required this.publicSpendKey, - required this.publicViewKey}); - - factory CreateWalletResult.fromJson(Map json) => - CreateWalletResult( - name: json['name'] as String? ?? '', - pass: json['pass'] as String? ?? '', - recentHistory: RecentHistory.fromJson( - json['recent_history'] as Map? ?? {}), - recovered: json['recovered'] as bool? ?? false, - walletFileSize: json['wallet_file_size'] as int? ?? 0, - walletId: json['wallet_id'] as int? ?? 0, - walletLocalBcSize: json['wallet_local_bc_size'] as int? ?? 0, - wi: Wi.fromJson(json['wi'] as Map? ?? {}), - privateSpendKey: json['private_spend_key'] as String? ?? '', - privateViewKey: json['private_view_key'] as String? ?? '', - publicSpendKey: json['public_spend_key'] as String? ?? '', - publicViewKey: json['public_view_key'] as String? ?? '', - ); - Future seed(ZanoWalletBase api) { - return api.getSeed(); - } -} diff --git a/cw_zano/lib/api/model/destination.dart b/cw_zano/lib/api/model/destination.dart deleted file mode 100644 index 13f4673a..00000000 --- a/cw_zano/lib/api/model/destination.dart +++ /dev/null @@ -1,20 +0,0 @@ -class Destination { - final BigInt amount; // transferred as string - final String address; - final String assetId; - - Destination( - {required this.amount, required this.address, required this.assetId}); - - factory Destination.fromJson(Map json) => Destination( - amount: BigInt.parse(json['amount'] as String? ?? '0'), - address: json['address'] as String? ?? '', - assetId: json['asset_id'] as String? ?? '', - ); - - Map toJson() => { - 'amount': amount.toString(), - 'address': address, - 'asset_id': assetId, - }; -} diff --git a/cw_zano/lib/api/model/employed_entries.dart b/cw_zano/lib/api/model/employed_entries.dart deleted file mode 100644 index 59e5fe34..00000000 --- a/cw_zano/lib/api/model/employed_entries.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'package:cw_zano/api/model/receive.dart'; - -class EmployedEntries { - final List receive; - final List send; - - EmployedEntries({required this.receive, required this.send}); - - factory EmployedEntries.fromJson(Map json) => - EmployedEntries( - receive: json['receive'] == null ? [] : (json['receive'] as List) - .map((e) => Receive.fromJson(e as Map)) - .toList(), - send: json['spent'] == null ? [] : (json['spent'] as List) - .map((e) => Receive.fromJson(e as Map)) - .toList(), - ); -} diff --git a/cw_zano/lib/api/model/get_address_info_result.dart b/cw_zano/lib/api/model/get_address_info_result.dart deleted file mode 100644 index e8399adb..00000000 --- a/cw_zano/lib/api/model/get_address_info_result.dart +++ /dev/null @@ -1,16 +0,0 @@ -class GetAddressInfoResult { - final bool valid; - final bool auditable; - final bool paymentId; - final bool wrap; - - GetAddressInfoResult( - {required this.valid, required this.auditable, required this.paymentId, required this.wrap}); - - factory GetAddressInfoResult.fromJson(Map json) => GetAddressInfoResult( - valid: json['valid'] as bool? ?? false, - auditable: json['auditable'] as bool? ?? false, - paymentId: json['payment_id'] as bool? ?? false, - wrap: json['wrap'] as bool? ?? false, - ); -} diff --git a/cw_zano/lib/api/model/get_recent_txs_and_info_params.dart b/cw_zano/lib/api/model/get_recent_txs_and_info_params.dart deleted file mode 100644 index 1ad9fc15..00000000 --- a/cw_zano/lib/api/model/get_recent_txs_and_info_params.dart +++ /dev/null @@ -1,14 +0,0 @@ -class GetRecentTxsAndInfoParams { - final int offset; - final int count; - final bool updateProvisionInfo; - - GetRecentTxsAndInfoParams({required this.offset, required this.count, this.updateProvisionInfo = true}); - - Map toJson() => { - 'offset': offset, - 'count': count, - 'update_provision_info': updateProvisionInfo, - 'order': 'FROM_BEGIN_TO_END', - }; -} \ No newline at end of file diff --git a/cw_zano/lib/api/model/get_recent_txs_and_info_result.dart b/cw_zano/lib/api/model/get_recent_txs_and_info_result.dart deleted file mode 100644 index 6b725490..00000000 --- a/cw_zano/lib/api/model/get_recent_txs_and_info_result.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:cw_zano/api/model/transfer.dart'; - -class GetRecentTxsAndInfoResult { - final List transfers; - final int lastItemIndex; - final int totalTransfers; - - GetRecentTxsAndInfoResult({required this.transfers, required this.lastItemIndex, required this.totalTransfers}); - - GetRecentTxsAndInfoResult.empty(): this.transfers = [], this.lastItemIndex = 0, this.totalTransfers = 0; - -} \ No newline at end of file diff --git a/cw_zano/lib/api/model/get_wallet_info_result.dart b/cw_zano/lib/api/model/get_wallet_info_result.dart deleted file mode 100644 index e14d1937..00000000 --- a/cw_zano/lib/api/model/get_wallet_info_result.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'package:cw_zano/api/model/wi.dart'; -import 'package:cw_zano/api/model/wi_extended.dart'; - -class GetWalletInfoResult { - final Wi wi; - final WiExtended wiExtended; - - GetWalletInfoResult({required this.wi, required this.wiExtended}); - - factory GetWalletInfoResult.fromJson(Map json) => GetWalletInfoResult( - wi: Wi.fromJson(json['wi'] as Map? ?? {}), - wiExtended: WiExtended.fromJson(json['wi_extended'] as Map? ?? {}), - ); -} diff --git a/cw_zano/lib/api/model/get_wallet_status_result.dart b/cw_zano/lib/api/model/get_wallet_status_result.dart deleted file mode 100644 index da11c4c9..00000000 --- a/cw_zano/lib/api/model/get_wallet_status_result.dart +++ /dev/null @@ -1,26 +0,0 @@ -class GetWalletStatusResult { - final int currentDaemonHeight; - final int currentWalletHeight; - final bool isDaemonConnected; - final bool isInLongRefresh; - final int progress; - final int walletState; - - GetWalletStatusResult( - {required this.currentDaemonHeight, - required this.currentWalletHeight, - required this.isDaemonConnected, - required this.isInLongRefresh, - required this.progress, - required this.walletState}); - - factory GetWalletStatusResult.fromJson(Map json) => - GetWalletStatusResult( - currentDaemonHeight: json['current_daemon_height'] as int? ?? 0, - currentWalletHeight: json['current_wallet_height'] as int? ?? 0, - isDaemonConnected: json['is_daemon_connected'] as bool? ?? false, - isInLongRefresh: json['is_in_long_refresh'] as bool? ?? false, - progress: json['progress'] as int? ?? 0, - walletState: json['wallet_state'] as int? ?? 0, - ); -} diff --git a/cw_zano/lib/api/model/proxy_to_daemon_params.dart b/cw_zano/lib/api/model/proxy_to_daemon_params.dart deleted file mode 100644 index 328187cf..00000000 --- a/cw_zano/lib/api/model/proxy_to_daemon_params.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'dart:convert'; - -class ProxyToDaemonParams { - final String body; - final String uri; - - ProxyToDaemonParams({required this.body, required this.uri}); - - Map toJson() => { - 'base64_body': base64Encode(utf8.encode(body)), - 'uri': uri, - }; -} diff --git a/cw_zano/lib/api/model/proxy_to_daemon_result.dart b/cw_zano/lib/api/model/proxy_to_daemon_result.dart deleted file mode 100644 index bf8da7c8..00000000 --- a/cw_zano/lib/api/model/proxy_to_daemon_result.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'dart:convert'; - -class ProxyToDaemonResult { - final String body; - final int responseCode; - - ProxyToDaemonResult({required this.body, required this.responseCode}); - - factory ProxyToDaemonResult.fromJson(Map json) => ProxyToDaemonResult( - body: utf8.decode(base64Decode(json['base64_body'] as String? ?? '')), - responseCode: json['response_code'] as int? ?? 0, - ); -} diff --git a/cw_zano/lib/api/model/receive.dart b/cw_zano/lib/api/model/receive.dart deleted file mode 100644 index 6364bf18..00000000 --- a/cw_zano/lib/api/model/receive.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:cw_zano/zano_formatter.dart'; - -class Receive { - final BigInt amount; - final String assetId; - final int index; - - Receive({required this.amount, required this.assetId, required this.index}); - - factory Receive.fromJson(Map json) => Receive( - amount: ZanoFormatter.bigIntFromDynamic(json['amount']), - assetId: json['asset_id'] as String? ?? '', - index: json['index'] as int? ?? 0, - ); -} diff --git a/cw_zano/lib/api/model/recent_history.dart b/cw_zano/lib/api/model/recent_history.dart deleted file mode 100644 index 6591f426..00000000 --- a/cw_zano/lib/api/model/recent_history.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'package:cw_zano/api/model/transfer.dart'; - -class RecentHistory { - final List? history; - final int lastItemIndex; - final int totalHistoryItems; - - RecentHistory( - {required this.history, - required this.lastItemIndex, - required this.totalHistoryItems}); - - factory RecentHistory.fromJson(Map json) => RecentHistory( - history: json['history'] == null ? null : (json['history'] as List) - .map((e) => Transfer.fromJson(e as Map)) - .toList(), - lastItemIndex: json['last_item_index'] as int? ?? 0, - totalHistoryItems: json['total_history_items'] as int? ?? 0, - ); -} diff --git a/cw_zano/lib/api/model/store_result.dart b/cw_zano/lib/api/model/store_result.dart deleted file mode 100644 index 0ff6625c..00000000 --- a/cw_zano/lib/api/model/store_result.dart +++ /dev/null @@ -1,9 +0,0 @@ -class StoreResult { - final int walletFileSize; - - StoreResult({required this.walletFileSize}); - - factory StoreResult.fromJson(Map json) => StoreResult( - walletFileSize: json['wallet_file_size'] as int? ?? 0, - ); -} \ No newline at end of file diff --git a/cw_zano/lib/api/model/subtransfer.dart b/cw_zano/lib/api/model/subtransfer.dart deleted file mode 100644 index d92f1407..00000000 --- a/cw_zano/lib/api/model/subtransfer.dart +++ /dev/null @@ -1,16 +0,0 @@ -import 'package:cw_zano/zano_formatter.dart'; - -class Subtransfer { - final BigInt amount; - final String assetId; - final bool isIncome; - - Subtransfer( - {required this.amount, required this.assetId, required this.isIncome}); - - factory Subtransfer.fromJson(Map json) => Subtransfer( - amount: ZanoFormatter.bigIntFromDynamic(json['amount']), - assetId: json['asset_id'] as String? ?? '', - isIncome: json['is_income'] as bool? ?? false, - ); -} diff --git a/cw_zano/lib/api/model/transfer.dart b/cw_zano/lib/api/model/transfer.dart deleted file mode 100644 index 594490a4..00000000 --- a/cw_zano/lib/api/model/transfer.dart +++ /dev/null @@ -1,133 +0,0 @@ -import 'package:cw_core/utils/print_verbose.dart'; -import 'package:cw_core/zano_asset.dart'; -import 'package:cw_zano/api/model/employed_entries.dart'; -import 'package:cw_zano/api/model/subtransfer.dart'; -import 'package:collection/collection.dart'; -import 'package:cw_zano/model/zano_transaction_info.dart'; -import 'package:cw_zano/zano_wallet.dart'; - -class Transfer { - final String comment; - final EmployedEntries employedEntries; - final int fee; - final int height; - final bool isMining; - final bool isMixing; - final bool isService; - final String paymentId; - final List remoteAddresses; - final List remoteAliases; - final bool showSender; - final List subtransfers; - final int timestamp; - final int transferInternalIndex; - final int txBlobSize; - final String txHash; - final int txType; - final int unlockTime; - - Transfer({ - required this.comment, - required this.employedEntries, - required this.fee, - required this.height, - required this.isMining, - required this.isMixing, - required this.isService, - required this.paymentId, - required this.remoteAddresses, - required this.remoteAliases, - required this.showSender, - required this.subtransfers, - required this.timestamp, - required this.transferInternalIndex, - required this.txBlobSize, - required this.txHash, - required this.txType, - required this.unlockTime, - }); - - factory Transfer.fromJson(Map json) => - Transfer( - comment: json['comment'] as String? ?? '', - employedEntries: EmployedEntries.fromJson( - json['employed_entries'] as Map? ?? {}), - fee: json['fee'] as int? ?? 0, - height: json['height'] as int? ?? 0, - isMining: json['is_mining'] as bool? ?? false, - isMixing: json['is_mixing'] as bool? ?? false, - isService: json['is_service'] as bool? ?? false, - paymentId: json['payment_id'] as String? ?? '', - remoteAddresses: json['remote_addresses'] == null ? [] : (json['remote_addresses'] as List< - dynamic>).cast(), - remoteAliases: json['remote_aliases'] == null ? [] : (json['remote_aliases'] as List< - dynamic>).cast(), - showSender: json['show_sender'] as bool? ?? false, - subtransfers: (json['subtransfers'] as List? ?? []).map((e) => - Subtransfer.fromJson(e as Map)).toList(), - timestamp: json['timestamp'] as int? ?? 0, - transferInternalIndex: json['transfer_internal_index'] == null - ? 0 - : json['transfer_internal_index'] is double - ? (json['transfer_internal_index'] as double).toInt() - : json['transfer_internal_index'] as int, - txBlobSize: json['tx_blob_size'] as int? ?? 0, - txHash: json['tx_hash'] as String? ?? '', - txType: json['tx_type'] as int? ?? 0, - unlockTime: json['unlock_time'] as int? ?? 0, - ); - - static Map makeMap(List transfers, - Map zanoAssets, int currentDaemonHeight) { - return Map.fromIterable( - transfers, - key: (item) => (item as Transfer).txHash, - value: (transfer) { - transfer as Transfer; - // Simple (only one subtransfer OR two subtransfers and the second is Zano, outgoing and amount equals to fee) or complex? - Subtransfer? single = transfer.subtransfers.singleOrNull; - if (transfer.subtransfers.length == 2) { - final zano = transfer.subtransfers.firstWhereOrNull((element) => - element.assetId == ZanoWalletBase.zanoAssetId); - if (zano != null && !zano.isIncome && zano.amount == BigInt.from(transfer.fee)) { - single = transfer.subtransfers.firstWhere((element) => element.assetId != - ZanoWalletBase.zanoAssetId); - } - } - bool isSimple = single != null; - // TODO: for complex transactions we show zano or any other transaction, will fix it later - if (!isSimple) { - single = - transfer.subtransfers.firstWhereOrNull((element) => - element.assetId == ZanoWalletBase.zanoAssetId) ?? transfer.subtransfers.first; - } - if (single.assetId != ZanoWalletBase.zanoAssetId) { - final asset = zanoAssets[single.assetId]; - if (asset == null) { - printV('unknown asset ${single.assetId}'); - } - final ticker = asset == null ? '***' : asset.ticker; - final decimalPoint = asset == null ? 0 : asset.decimalPoint; - return ZanoTransactionInfo.fromTransfer( - transfer, - confirmations: currentDaemonHeight - transfer.height, - isIncome: single.isIncome, - assetId: single.assetId, - amount: single.amount, - tokenSymbol: isSimple ? ticker : '*${ticker}', - decimalPoint: decimalPoint, - ); - } - final amount = single.isIncome ? single.amount : single.amount - BigInt.from(transfer.fee); - return ZanoTransactionInfo.fromTransfer( - transfer, - confirmations: currentDaemonHeight - transfer.height, - isIncome: single.isIncome, - assetId: single.assetId, - amount: amount, - tokenSymbol: isSimple ? 'ZANO' : '*ZANO', - ); - }, - ); - } -} diff --git a/cw_zano/lib/api/model/transfer_params.dart b/cw_zano/lib/api/model/transfer_params.dart deleted file mode 100644 index 586d5ddb..00000000 --- a/cw_zano/lib/api/model/transfer_params.dart +++ /dev/null @@ -1,41 +0,0 @@ -import 'package:cw_zano/api/model/destination.dart'; - -class TransferParams { - final List destinations; - final BigInt fee; - final int mixin; - final String paymentId; - final String comment; - final bool pushPayer; - final bool hideReceiver; - - TransferParams({ - required this.destinations, - required this.fee, - required this.mixin, - required this.paymentId, - required this.comment, - required this.pushPayer, - required this.hideReceiver, - }); - - Map toJson() => { - 'destinations': destinations, - 'fee': fee.toInt(), - 'mixin': mixin, - 'payment_id': paymentId, - 'comment': comment, - 'push_payer': pushPayer, - 'hide_receiver': hideReceiver, - }; - - factory TransferParams.fromJson(Map json) => TransferParams( - destinations: (json['destinations'] as List?)?.map((e) => Destination.fromJson(e as Map)).toList() ?? [], - fee: BigInt.from(json['fee'] as int? ?? 0), - mixin: json['mixin'] as int? ?? 0, - paymentId: json['payment_id'] as String? ?? '', - comment: json['comment'] as String? ?? '', - pushPayer: json['push_payer'] as bool? ?? false, - hideReceiver: json['hide_receiver'] as bool? ?? false, - ); -} diff --git a/cw_zano/lib/api/model/transfer_result.dart b/cw_zano/lib/api/model/transfer_result.dart deleted file mode 100644 index e0259fec..00000000 --- a/cw_zano/lib/api/model/transfer_result.dart +++ /dev/null @@ -1,13 +0,0 @@ -class TransferResult { - final String txHash; - final int txSize; - final String txUnsignedHex; - - TransferResult({required this.txHash, required this.txSize, required this.txUnsignedHex}); - - factory TransferResult.fromJson(Map json) => TransferResult( - txHash: json['tx_hash'] as String? ?? '', - txSize: json['tx_size'] as int? ?? 0, - txUnsignedHex: json['tx_unsigned_hex'] as String? ?? '', - ); -} diff --git a/cw_zano/lib/api/model/wi.dart b/cw_zano/lib/api/model/wi.dart deleted file mode 100644 index 0375cdf9..00000000 --- a/cw_zano/lib/api/model/wi.dart +++ /dev/null @@ -1,32 +0,0 @@ -import 'package:cw_zano/api/model/balance.dart'; - -class Wi { - final String address; - final List balances; - final bool isAuditable; - final bool isWatchOnly; - final int minedTotal; - final String path; - final String viewSecKey; - - Wi( - {required this.address, - required this.balances, - required this.isAuditable, - required this.isWatchOnly, - required this.minedTotal, - required this.path, - required this.viewSecKey}); - - factory Wi.fromJson(Map json) => Wi( - address: json['address'] as String? ?? '', - balances: (json['balances'] as List? ?? []) - .map((e) => Balance.fromJson(e as Map)) - .toList(), - isAuditable: json['is_auditable'] as bool? ?? false, - isWatchOnly: json['is_watch_only'] as bool? ?? false, - minedTotal: json['mined_total'] as int? ?? 0, - path: json['path'] as String? ?? '', - viewSecKey: json['view_sec_key'] as String? ?? '', - ); -} diff --git a/cw_zano/lib/api/model/wi_extended.dart b/cw_zano/lib/api/model/wi_extended.dart deleted file mode 100644 index ef274599..00000000 --- a/cw_zano/lib/api/model/wi_extended.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:cw_zano/zano_wallet.dart'; - -class WiExtended { - final String spendPrivateKey; - final String spendPublicKey; - final String viewPrivateKey; - final String viewPublicKey; - - WiExtended({required this.spendPrivateKey, required this.spendPublicKey, required this.viewPrivateKey, required this.viewPublicKey}); - - factory WiExtended.fromJson(Map json) => WiExtended( - spendPrivateKey: json['spend_private_key'] as String? ?? '', - spendPublicKey: json['spend_public_key'] as String? ?? '', - viewPrivateKey: json['view_private_key'] as String? ?? '', - viewPublicKey: json['view_public_key'] as String? ?? '', - ); - - Future seed(ZanoWalletBase api) { - return api.getSeed(); - } -} \ No newline at end of file diff --git a/cw_zano/lib/mnemonics/english.dart b/cw_zano/lib/mnemonics/english.dart deleted file mode 100644 index 9749f974..00000000 --- a/cw_zano/lib/mnemonics/english.dart +++ /dev/null @@ -1,1630 +0,0 @@ -class EnglishMnemonics { - static const words = [ - "like", - "just", - "love", - "know", - "never", - "want", - "time", - "out", - "there", - "make", - "look", - "eye", - "down", - "only", - "think", - "heart", - "back", - "then", - "into", - "about", - "more", - "away", - "still", - "them", - "take", - "thing", - "even", - "through", - "long", - "always", - "world", - "too", - "friend", - "tell", - "try", - "hand", - "thought", - "over", - "here", - "other", - "need", - "smile", - "again", - "much", - "cry", - "been", - "night", - "ever", - "little", - "said", - "end", - "some", - "those", - "around", - "mind", - "people", - "girl", - "leave", - "dream", - "left", - "turn", - "myself", - "give", - "nothing", - "really", - "off", - "before", - "something", - "find", - "walk", - "wish", - "good", - "once", - "place", - "ask", - "stop", - "keep", - "watch", - "seem", - "everything", - "wait", - "got", - "yet", - "made", - "remember", - "start", - "alone", - "run", - "hope", - "maybe", - "believe", - "body", - "hate", - "after", - "close", - "talk", - "stand", - "own", - "each", - "hurt", - "help", - "home", - "god", - "soul", - "new", - "many", - "two", - "inside", - "should", - "true", - "first", - "fear", - "mean", - "better", - "play", - "another", - "gone", - "change", - "use", - "wonder", - "someone", - "hair", - "cold", - "open", - "best", - "any", - "behind", - "happen", - "water", - "dark", - "laugh", - "stay", - "forever", - "name", - "work", - "show", - "sky", - "break", - "came", - "deep", - "door", - "put", - "black", - "together", - "upon", - "happy", - "such", - "great", - "white", - "matter", - "fill", - "past", - "please", - "burn", - "cause", - "enough", - "touch", - "moment", - "soon", - "voice", - "scream", - "anything", - "stare", - "sound", - "red", - "everyone", - "hide", - "kiss", - "truth", - "death", - "beautiful", - "mine", - "blood", - "broken", - "very", - "pass", - "next", - "forget", - "tree", - "wrong", - "air", - "mother", - "understand", - "lip", - "hit", - "wall", - "memory", - "sleep", - "free", - "high", - "realize", - "school", - "might", - "skin", - "sweet", - "perfect", - "blue", - "kill", - "breath", - "dance", - "against", - "fly", - "between", - "grow", - "strong", - "under", - "listen", - "bring", - "sometimes", - "speak", - "pull", - "person", - "become", - "family", - "begin", - "ground", - "real", - "small", - "father", - "sure", - "feet", - "rest", - "young", - "finally", - "land", - "across", - "today", - "different", - "guy", - "line", - "fire", - "reason", - "reach", - "second", - "slowly", - "write", - "eat", - "smell", - "mouth", - "step", - "learn", - "three", - "floor", - "promise", - "breathe", - "darkness", - "push", - "earth", - "guess", - "save", - "song", - "above", - "along", - "both", - "color", - "house", - "almost", - "sorry", - "anymore", - "brother", - "okay", - "dear", - "game", - "fade", - "already", - "apart", - "warm", - "beauty", - "heard", - "notice", - "question", - "shine", - "began", - "piece", - "whole", - "shadow", - "secret", - "street", - "within", - "finger", - "point", - "morning", - "whisper", - "child", - "moon", - "green", - "story", - "glass", - "kid", - "silence", - "since", - "soft", - "yourself", - "empty", - "shall", - "angel", - "answer", - "baby", - "bright", - "dad", - "path", - "worry", - "hour", - "drop", - "follow", - "power", - "war", - "half", - "flow", - "heaven", - "act", - "chance", - "fact", - "least", - "tired", - "children", - "near", - "quite", - "afraid", - "rise", - "sea", - "taste", - "window", - "cover", - "nice", - "trust", - "lot", - "sad", - "cool", - "force", - "peace", - "return", - "blind", - "easy", - "ready", - "roll", - "rose", - "drive", - "held", - "music", - "beneath", - "hang", - "mom", - "paint", - "emotion", - "quiet", - "clear", - "cloud", - "few", - "pretty", - "bird", - "outside", - "paper", - "picture", - "front", - "rock", - "simple", - "anyone", - "meant", - "reality", - "road", - "sense", - "waste", - "bit", - "leaf", - "thank", - "happiness", - "meet", - "men", - "smoke", - "truly", - "decide", - "self", - "age", - "book", - "form", - "alive", - "carry", - "escape", - "damn", - "instead", - "able", - "ice", - "minute", - "throw", - "catch", - "leg", - "ring", - "course", - "goodbye", - "lead", - "poem", - "sick", - "corner", - "desire", - "known", - "problem", - "remind", - "shoulder", - "suppose", - "toward", - "wave", - "drink", - "jump", - "woman", - "pretend", - "sister", - "week", - "human", - "joy", - "crack", - "grey", - "pray", - "surprise", - "dry", - "knee", - "less", - "search", - "bleed", - "caught", - "clean", - "embrace", - "future", - "king", - "son", - "sorrow", - "chest", - "hug", - "remain", - "sat", - "worth", - "blow", - "daddy", - "final", - "parent", - "tight", - "also", - "create", - "lonely", - "safe", - "cross", - "dress", - "evil", - "silent", - "bone", - "fate", - "perhaps", - "anger", - "class", - "scar", - "snow", - "tiny", - "tonight", - "continue", - "control", - "dog", - "edge", - "mirror", - "month", - "suddenly", - "comfort", - "given", - "loud", - "quickly", - "gaze", - "plan", - "rush", - "stone", - "town", - "battle", - "ignore", - "spirit", - "stood", - "stupid", - "yours", - "brown", - "build", - "dust", - "hey", - "kept", - "pay", - "phone", - "twist", - "although", - "ball", - "beyond", - "hidden", - "nose", - "taken", - "fail", - "float", - "pure", - "somehow", - "wash", - "wrap", - "angry", - "cheek", - "creature", - "forgotten", - "heat", - "rip", - "single", - "space", - "special", - "weak", - "whatever", - "yell", - "anyway", - "blame", - "job", - "choose", - "country", - "curse", - "drift", - "echo", - "figure", - "grew", - "laughter", - "neck", - "suffer", - "worse", - "yeah", - "disappear", - "foot", - "forward", - "knife", - "mess", - "somewhere", - "stomach", - "storm", - "beg", - "idea", - "lift", - "offer", - "breeze", - "field", - "five", - "often", - "simply", - "stuck", - "win", - "allow", - "confuse", - "enjoy", - "except", - "flower", - "seek", - "strength", - "calm", - "grin", - "gun", - "heavy", - "hill", - "large", - "ocean", - "shoe", - "sigh", - "straight", - "summer", - "tongue", - "accept", - "crazy", - "everyday", - "exist", - "grass", - "mistake", - "sent", - "shut", - "surround", - "table", - "ache", - "brain", - "destroy", - "heal", - "nature", - "shout", - "sign", - "stain", - "choice", - "doubt", - "glance", - "glow", - "mountain", - "queen", - "stranger", - "throat", - "tomorrow", - "city", - "either", - "fish", - "flame", - "rather", - "shape", - "spin", - "spread", - "ash", - "distance", - "finish", - "image", - "imagine", - "important", - "nobody", - "shatter", - "warmth", - "became", - "feed", - "flesh", - "funny", - "lust", - "shirt", - "trouble", - "yellow", - "attention", - "bare", - "bite", - "money", - "protect", - "amaze", - "appear", - "born", - "choke", - "completely", - "daughter", - "fresh", - "friendship", - "gentle", - "probably", - "six", - "deserve", - "expect", - "grab", - "middle", - "nightmare", - "river", - "thousand", - "weight", - "worst", - "wound", - "barely", - "bottle", - "cream", - "regret", - "relationship", - "stick", - "test", - "crush", - "endless", - "fault", - "itself", - "rule", - "spill", - "art", - "circle", - "join", - "kick", - "mask", - "master", - "passion", - "quick", - "raise", - "smooth", - "unless", - "wander", - "actually", - "broke", - "chair", - "deal", - "favorite", - "gift", - "note", - "number", - "sweat", - "box", - "chill", - "clothes", - "lady", - "mark", - "park", - "poor", - "sadness", - "tie", - "animal", - "belong", - "brush", - "consume", - "dawn", - "forest", - "innocent", - "pen", - "pride", - "stream", - "thick", - "clay", - "complete", - "count", - "draw", - "faith", - "press", - "silver", - "struggle", - "surface", - "taught", - "teach", - "wet", - "bless", - "chase", - "climb", - "enter", - "letter", - "melt", - "metal", - "movie", - "stretch", - "swing", - "vision", - "wife", - "beside", - "crash", - "forgot", - "guide", - "haunt", - "joke", - "knock", - "plant", - "pour", - "prove", - "reveal", - "steal", - "stuff", - "trip", - "wood", - "wrist", - "bother", - "bottom", - "crawl", - "crowd", - "fix", - "forgive", - "frown", - "grace", - "loose", - "lucky", - "party", - "release", - "surely", - "survive", - "teacher", - "gently", - "grip", - "speed", - "suicide", - "travel", - "treat", - "vein", - "written", - "cage", - "chain", - "conversation", - "date", - "enemy", - "however", - "interest", - "million", - "page", - "pink", - "proud", - "sway", - "themselves", - "winter", - "church", - "cruel", - "cup", - "demon", - "experience", - "freedom", - "pair", - "pop", - "purpose", - "respect", - "shoot", - "softly", - "state", - "strange", - "bar", - "birth", - "curl", - "dirt", - "excuse", - "lord", - "lovely", - "monster", - "order", - "pack", - "pants", - "pool", - "scene", - "seven", - "shame", - "slide", - "ugly", - "among", - "blade", - "blonde", - "closet", - "creek", - "deny", - "drug", - "eternity", - "gain", - "grade", - "handle", - "key", - "linger", - "pale", - "prepare", - "swallow", - "swim", - "tremble", - "wheel", - "won", - "cast", - "cigarette", - "claim", - "college", - "direction", - "dirty", - "gather", - "ghost", - "hundred", - "loss", - "lung", - "orange", - "present", - "swear", - "swirl", - "twice", - "wild", - "bitter", - "blanket", - "doctor", - "everywhere", - "flash", - "grown", - "knowledge", - "numb", - "pressure", - "radio", - "repeat", - "ruin", - "spend", - "unknown", - "buy", - "clock", - "devil", - "early", - "false", - "fantasy", - "pound", - "precious", - "refuse", - "sheet", - "teeth", - "welcome", - "add", - "ahead", - "block", - "bury", - "caress", - "content", - "depth", - "despite", - "distant", - "marry", - "purple", - "threw", - "whenever", - "bomb", - "dull", - "easily", - "grasp", - "hospital", - "innocence", - "normal", - "receive", - "reply", - "rhyme", - "shade", - "someday", - "sword", - "toe", - "visit", - "asleep", - "bought", - "center", - "consider", - "flat", - "hero", - "history", - "ink", - "insane", - "muscle", - "mystery", - "pocket", - "reflection", - "shove", - "silently", - "smart", - "soldier", - "spot", - "stress", - "train", - "type", - "view", - "whether", - "bus", - "energy", - "explain", - "holy", - "hunger", - "inch", - "magic", - "mix", - "noise", - "nowhere", - "prayer", - "presence", - "shock", - "snap", - "spider", - "study", - "thunder", - "trail", - "admit", - "agree", - "bag", - "bang", - "bound", - "butterfly", - "cute", - "exactly", - "explode", - "familiar", - "fold", - "further", - "pierce", - "reflect", - "scent", - "selfish", - "sharp", - "sink", - "spring", - "stumble", - "universe", - "weep", - "women", - "wonderful", - "action", - "ancient", - "attempt", - "avoid", - "birthday", - "branch", - "chocolate", - "core", - "depress", - "drunk", - "especially", - "focus", - "fruit", - "honest", - "match", - "palm", - "perfectly", - "pillow", - "pity", - "poison", - "roar", - "shift", - "slightly", - "thump", - "truck", - "tune", - "twenty", - "unable", - "wipe", - "wrote", - "coat", - "constant", - "dinner", - "drove", - "egg", - "eternal", - "flight", - "flood", - "frame", - "freak", - "gasp", - "glad", - "hollow", - "motion", - "peer", - "plastic", - "root", - "screen", - "season", - "sting", - "strike", - "team", - "unlike", - "victim", - "volume", - "warn", - "weird", - "attack", - "await", - "awake", - "built", - "charm", - "crave", - "despair", - "fought", - "grant", - "grief", - "horse", - "limit", - "message", - "ripple", - "sanity", - "scatter", - "serve", - "split", - "string", - "trick", - "annoy", - "blur", - "boat", - "brave", - "clearly", - "cling", - "connect", - "fist", - "forth", - "imagination", - "iron", - "jock", - "judge", - "lesson", - "milk", - "misery", - "nail", - "naked", - "ourselves", - "poet", - "possible", - "princess", - "sail", - "size", - "snake", - "society", - "stroke", - "torture", - "toss", - "trace", - "wise", - "bloom", - "bullet", - "cell", - "check", - "cost", - "darling", - "during", - "footstep", - "fragile", - "hallway", - "hardly", - "horizon", - "invisible", - "journey", - "midnight", - "mud", - "nod", - "pause", - "relax", - "shiver", - "sudden", - "value", - "youth", - "abuse", - "admire", - "blink", - "breast", - "bruise", - "constantly", - "couple", - "creep", - "curve", - "difference", - "dumb", - "emptiness", - "gotta", - "honor", - "plain", - "planet", - "recall", - "rub", - "ship", - "slam", - "soar", - "somebody", - "tightly", - "weather", - "adore", - "approach", - "bond", - "bread", - "burst", - "candle", - "coffee", - "cousin", - "crime", - "desert", - "flutter", - "frozen", - "grand", - "heel", - "hello", - "language", - "level", - "movement", - "pleasure", - "powerful", - "random", - "rhythm", - "settle", - "silly", - "slap", - "sort", - "spoken", - "steel", - "threaten", - "tumble", - "upset", - "aside", - "awkward", - "bee", - "blank", - "board", - "button", - "card", - "carefully", - "complain", - "crap", - "deeply", - "discover", - "drag", - "dread", - "effort", - "entire", - "fairy", - "giant", - "gotten", - "greet", - "illusion", - "jeans", - "leap", - "liquid", - "march", - "mend", - "nervous", - "nine", - "replace", - "rope", - "spine", - "stole", - "terror", - "accident", - "apple", - "balance", - "boom", - "childhood", - "collect", - "demand", - "depression", - "eventually", - "faint", - "glare", - "goal", - "group", - "honey", - "kitchen", - "laid", - "limb", - "machine", - "mere", - "mold", - "murder", - "nerve", - "painful", - "poetry", - "prince", - "rabbit", - "shelter", - "shore", - "shower", - "soothe", - "stair", - "steady", - "sunlight", - "tangle", - "tease", - "treasure", - "uncle", - "begun", - "bliss", - "canvas", - "cheer", - "claw", - "clutch", - "commit", - "crimson", - "crystal", - "delight", - "doll", - "existence", - "express", - "fog", - "football", - "gay", - "goose", - "guard", - "hatred", - "illuminate", - "mass", - "math", - "mourn", - "rich", - "rough", - "skip", - "stir", - "student", - "style", - "support", - "thorn", - "tough", - "yard", - "yearn", - "yesterday", - "advice", - "appreciate", - "autumn", - "bank", - "beam", - "bowl", - "capture", - "carve", - "collapse", - "confusion", - "creation", - "dove", - "feather", - "girlfriend", - "glory", - "government", - "harsh", - "hop", - "inner", - "loser", - "moonlight", - "neighbor", - "neither", - "peach", - "pig", - "praise", - "screw", - "shield", - "shimmer", - "sneak", - "stab", - "subject", - "throughout", - "thrown", - "tower", - "twirl", - "wow", - "army", - "arrive", - "bathroom", - "bump", - "cease", - "cookie", - "couch", - "courage", - "dim", - "guilt", - "howl", - "hum", - "husband", - "insult", - "led", - "lunch", - "mock", - "mostly", - "natural", - "nearly", - "needle", - "nerd", - "peaceful", - "perfection", - "pile", - "price", - "remove", - "roam", - "sanctuary", - "serious", - "shiny", - "shook", - "sob", - "stolen", - "tap", - "vain", - "void", - "warrior", - "wrinkle", - "affection", - "apologize", - "blossom", - "bounce", - "bridge", - "cheap", - "crumble", - "decision", - "descend", - "desperately", - "dig", - "dot", - "flip", - "frighten", - "heartbeat", - "huge", - "lazy", - "lick", - "odd", - "opinion", - "process", - "puzzle", - "quietly", - "retreat", - "score", - "sentence", - "separate", - "situation", - "skill", - "soak", - "square", - "stray", - "taint", - "task", - "tide", - "underneath", - "veil", - "whistle", - "anywhere", - "bedroom", - "bid", - "bloody", - "burden", - "careful", - "compare", - "concern", - "curtain", - "decay", - "defeat", - "describe", - "double", - "dreamer", - "driver", - "dwell", - "evening", - "flare", - "flicker", - "grandma", - "guitar", - "harm", - "horrible", - "hungry", - "indeed", - "lace", - "melody", - "monkey", - "nation", - "object", - "obviously", - "rainbow", - "salt", - "scratch", - "shown", - "shy", - "stage", - "stun", - "third", - "tickle", - "useless", - "weakness", - "worship", - "worthless", - "afternoon", - "beard", - "boyfriend", - "bubble", - "busy", - "certain", - "chin", - "concrete", - "desk", - "diamond", - "doom", - "drawn", - "due", - "felicity", - "freeze", - "frost", - "garden", - "glide", - "harmony", - "hopefully", - "hunt", - "jealous", - "lightning", - "mama", - "mercy", - "peel", - "physical", - "position", - "pulse", - "punch", - "quit", - "rant", - "respond", - "salty", - "sane", - "satisfy", - "savior", - "sheep", - "slept", - "social", - "sport", - "tuck", - "utter", - "valley", - "wolf", - "aim", - "alas", - "alter", - "arrow", - "awaken", - "beaten", - "belief", - "brand", - "ceiling", - "cheese", - "clue", - "confidence", - "connection", - "daily", - "disguise", - "eager", - "erase", - "essence", - "everytime", - "expression", - "fan", - "flag", - "flirt", - "foul", - "fur", - "giggle", - "glorious", - "ignorance", - "law", - "lifeless", - "measure", - "mighty", - "muse", - "north", - "opposite", - "paradise", - "patience", - "patient", - "pencil", - "petal", - "plate", - "ponder", - "possibly", - "practice", - "slice", - "spell", - "stock", - "strife", - "strip", - "suffocate", - "suit", - "tender", - "tool", - "trade", - "velvet", - "verse", - "waist", - "witch", - "aunt", - "bench", - "bold", - "cap", - "certainly", - "click", - "companion", - "creator", - "dart", - "delicate", - "determine", - "dish", - "dragon", - "drama", - "drum", - "dude", - "everybody", - "feast", - "forehead", - "former", - "fright", - "fully", - "gas", - "hook", - "hurl", - "invite", - "juice", - "manage", - "moral", - "possess", - "raw", - "rebel", - "royal", - "scale", - "scary", - "several", - "slight", - "stubborn", - "swell", - "talent", - "tea", - "terrible", - "thread", - "torment", - "trickle", - "usually", - "vast", - "violence", - "weave", - "acid", - "agony", - "ashamed", - "awe", - "belly", - "blend", - "blush", - "character", - "cheat", - "common", - "company", - "coward", - "creak", - "danger", - "deadly", - "defense", - "define", - "depend", - "desperate", - "destination", - "dew", - "duck", - "dusty", - "embarrass", - "engine", - "example", - "explore", - "foe", - "freely", - "frustrate", - "generation", - "glove", - "guilty", - "health", - "hurry", - "idiot", - "impossible", - "inhale", - "jaw", - "kingdom", - "mention", - "mist", - "moan", - "mumble", - "mutter", - "observe", - "ode", - "pathetic", - "pattern", - "pie", - "prefer", - "puff", - "rape", - "rare", - "revenge", - "rude", - "scrape", - "spiral", - "squeeze", - "strain", - "sunset", - "suspend", - "sympathy", - "thigh", - "throne", - "total", - "unseen", - "weapon", - "weary" - ]; -} diff --git a/cw_zano/lib/model/pending_zano_transaction.dart b/cw_zano/lib/model/pending_zano_transaction.dart deleted file mode 100644 index 99706d3a..00000000 --- a/cw_zano/lib/model/pending_zano_transaction.dart +++ /dev/null @@ -1,55 +0,0 @@ -import 'package:cw_core/pending_transaction.dart'; -import 'package:cw_zano/api/model/destination.dart'; -import 'package:cw_zano/api/model/transfer_result.dart'; -import 'package:cw_zano/zano_formatter.dart'; -import 'package:cw_zano/zano_wallet.dart'; - -class PendingZanoTransaction with PendingTransaction { - PendingZanoTransaction({ - required this.zanoWallet, - required this.destinations, - required this.fee, - required this.comment, - required this.assetId, - required this.ticker, - this.decimalPoint = ZanoFormatter.defaultDecimalPoint, - required this.amount, - }); - - final ZanoWalletBase zanoWallet; - final List destinations; - final BigInt fee; - final String comment; - final String assetId; - final String ticker; - final int decimalPoint; - final BigInt amount; - - @override - String get id => transferResult?.txHash ?? ''; - - @override - String get hex => ''; - - @override - String get amountFormatted => ZanoFormatter.bigIntAmountToString(amount, decimalPoint); - - @override - String get feeFormatted => "$feeFormattedValue ZANO"; - - @override - String get feeFormattedValue => ZanoFormatter.bigIntAmountToString(fee); - - TransferResult? transferResult; - - @override - Future commit() async { - transferResult = await zanoWallet.transfer(destinations, fee, comment); - zanoWallet.fetchTransactions(); - } - - @override - Future> commitUR() { - throw UnimplementedError(); - } -} diff --git a/cw_zano/lib/model/zano_asset.dart b/cw_zano/lib/model/zano_asset.dart deleted file mode 100644 index e69de29b..00000000 diff --git a/cw_zano/lib/model/zano_balance.dart b/cw_zano/lib/model/zano_balance.dart deleted file mode 100644 index 0f1e5c81..00000000 --- a/cw_zano/lib/model/zano_balance.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:cw_core/balance.dart'; -import 'package:cw_zano/zano_formatter.dart'; - -class ZanoBalance extends Balance { - final BigInt total; - final BigInt unlocked; - final int decimalPoint; - ZanoBalance({required this.total, required this.unlocked, this.decimalPoint = ZanoFormatter.defaultDecimalPoint}) : super(unlocked, (total - unlocked)); - - ZanoBalance.empty({this.decimalPoint = ZanoFormatter.defaultDecimalPoint}): total = BigInt.zero, unlocked = BigInt.zero, super(BigInt.zero, BigInt.zero); - - @override - String get formattedAdditionalBalance => ZanoFormatter.bigIntAmountToString(total - unlocked, decimalPoint); - - @override - String get formattedAvailableBalance => ZanoFormatter.bigIntAmountToString(unlocked, decimalPoint); -} diff --git a/cw_zano/lib/model/zano_transaction_creation_exception.dart b/cw_zano/lib/model/zano_transaction_creation_exception.dart deleted file mode 100644 index 74a5f77c..00000000 --- a/cw_zano/lib/model/zano_transaction_creation_exception.dart +++ /dev/null @@ -1,8 +0,0 @@ -class ZanoTransactionCreationException implements Exception { - ZanoTransactionCreationException(this.message); - - final String message; - - @override - String toString() => message; -} \ No newline at end of file diff --git a/cw_zano/lib/model/zano_transaction_credentials.dart b/cw_zano/lib/model/zano_transaction_credentials.dart deleted file mode 100644 index dbbfe53c..00000000 --- a/cw_zano/lib/model/zano_transaction_credentials.dart +++ /dev/null @@ -1,11 +0,0 @@ -import 'package:cw_core/crypto_currency.dart'; -import 'package:cw_core/monero_transaction_priority.dart'; -import 'package:cw_core/output_info.dart'; - -class ZanoTransactionCredentials { - ZanoTransactionCredentials({required this.outputs, required this.priority, required this.currency}); - - final List outputs; - final MoneroTransactionPriority priority; - final CryptoCurrency currency; -} diff --git a/cw_zano/lib/model/zano_transaction_info.dart b/cw_zano/lib/model/zano_transaction_info.dart deleted file mode 100644 index d643e920..00000000 --- a/cw_zano/lib/model/zano_transaction_info.dart +++ /dev/null @@ -1,81 +0,0 @@ -import 'package:cw_core/format_amount.dart'; -import 'package:cw_core/transaction_direction.dart'; -import 'package:cw_core/transaction_info.dart'; -import 'package:cw_zano/api/model/transfer.dart'; -import 'package:cw_zano/zano_formatter.dart'; - -class ZanoTransactionInfo extends TransactionInfo { - ZanoTransactionInfo({ - required this.id, - required this.height, - required this.direction, - required this.date, - required this.isPending, - required this.zanoAmount, - required this.fee, - required this.confirmations, - required this.tokenSymbol, - required this.decimalPoint, - required String assetId, - }) : amount = zanoAmount.isValidInt ? zanoAmount.toInt() : 0 { - additionalInfo['assetId'] = assetId; - } - - ZanoTransactionInfo.fromTransfer(Transfer transfer, - {required int confirmations, - required bool isIncome, - required String assetId, - required BigInt amount, - this.tokenSymbol = 'ZANO', - this.decimalPoint = ZanoFormatter.defaultDecimalPoint}) - : id = transfer.txHash, - height = transfer.height, - direction = isIncome ? TransactionDirection.incoming : TransactionDirection.outgoing, - date = DateTime.fromMillisecondsSinceEpoch(transfer.timestamp * 1000), - zanoAmount = amount, - amount = amount.isValidInt ? amount.toInt() : 0, - fee = transfer.fee, - confirmations = confirmations, - isPending = confirmations < 10, - recipientAddress = transfer.remoteAddresses.isNotEmpty - ? transfer.remoteAddresses.first - : '' { - additionalInfo = { - 'comment': transfer.comment, - 'assetId': assetId, - }; - } - - String get assetId => additionalInfo["assetId"] as String; - - set assetId(String newId) => additionalInfo["assetId"] = newId; - final String id; - final int height; - final TransactionDirection direction; - final DateTime date; - final bool isPending; - final BigInt zanoAmount; - final int amount; - final int fee; - final int confirmations; - final int decimalPoint; - late String recipientAddress; - final String tokenSymbol; - String? _fiatAmount; - String? key; - - @override - String amountFormatted() => - '${formatAmount(ZanoFormatter.bigIntAmountToString(zanoAmount, decimalPoint))} $tokenSymbol'; - - @override - String fiatAmount() => _fiatAmount ?? ''; - - @override - void changeFiatAmount(String amount) => _fiatAmount = formatAmount(amount); - - @override - String feeFormatted() => '${formatAmount(ZanoFormatter.intAmountToString(fee))} $feeCurrency'; - - String get feeCurrency => 'ZANO'; -} diff --git a/cw_zano/lib/model/zano_wallet_keys.dart b/cw_zano/lib/model/zano_wallet_keys.dart deleted file mode 100644 index 5a224633..00000000 --- a/cw_zano/lib/model/zano_wallet_keys.dart +++ /dev/null @@ -1,12 +0,0 @@ -class ZanoWalletKeys { - const ZanoWalletKeys( - {required this.privateSpendKey, - required this.privateViewKey, - required this.publicSpendKey, - required this.publicViewKey}); - - final String publicViewKey; - final String privateViewKey; - final String publicSpendKey; - final String privateSpendKey; -} \ No newline at end of file diff --git a/cw_zano/lib/zano_formatter.dart b/cw_zano/lib/zano_formatter.dart deleted file mode 100644 index 4aa35b1b..00000000 --- a/cw_zano/lib/zano_formatter.dart +++ /dev/null @@ -1,79 +0,0 @@ -import 'dart:math'; - -import 'package:cw_core/utils/print_verbose.dart'; -import 'package:decimal/decimal.dart'; -import 'package:decimal/intl.dart'; -import 'package:fluttertoast/fluttertoast.dart'; -import 'package:intl/intl.dart'; - -class ZanoFormatter { - static const defaultDecimalPoint = 12; - - //static final numberFormat = NumberFormat() - // ..maximumFractionDigits = defaultDecimalPoint - // ..minimumFractionDigits = 1; - - static Decimal _bigIntDivision({required BigInt amount, required BigInt divider}) { - return (Decimal.fromBigInt(amount) / Decimal.fromBigInt(divider)).toDecimal(); - } - - static String intAmountToString(int amount, [int decimalPoint = defaultDecimalPoint]) { - final numberFormat = NumberFormat()..maximumFractionDigits = decimalPoint - ..minimumFractionDigits = 1; - return numberFormat.format( - DecimalIntl( - _bigIntDivision( - amount: BigInt.from(amount), - divider: BigInt.from(pow(10, decimalPoint)), - ), - ), - ) - .replaceAll(',', ''); - } - - static String bigIntAmountToString(BigInt amount, [int decimalPoint = defaultDecimalPoint]) { - if (decimalPoint == 0) { - return '0'; - } - final numberFormat = NumberFormat()..maximumFractionDigits = decimalPoint - ..minimumFractionDigits = 1; - return numberFormat.format( - DecimalIntl( - _bigIntDivision( - amount: amount, - divider: BigInt.from(pow(10, decimalPoint)), - ), - ), - ) - .replaceAll(',', ''); - } - - static double intAmountToDouble(int amount, [int decimalPoint = defaultDecimalPoint]) => _bigIntDivision( - amount: BigInt.from(amount), - divider: BigInt.from(pow(10, decimalPoint)), - ).toDouble(); - - static int parseAmount(String amount, [int decimalPoint = defaultDecimalPoint]) { - final resultBigInt = (Decimal.parse(amount) * Decimal.fromBigInt(BigInt.from(10).pow(decimalPoint))).toBigInt(); - if (!resultBigInt.isValidInt) { - try { - Fluttertoast.showToast(msg: 'Cannot transfer $amount. Maximum is ${intAmountToString(resultBigInt.toInt(), decimalPoint)}.'); - } catch (_) {} - } - return resultBigInt.toInt(); - } - - static BigInt bigIntFromDynamic(dynamic d) { - if (d is int) { - return BigInt.from(d); - } else if (d is BigInt) { - return d; - } else if (d == null) { - return BigInt.zero; - } else { - printV(('cannot cast value of type ${d.runtimeType} to BigInt')); - throw 'cannot cast value of type ${d.runtimeType} to BigInt'; - //return BigInt.zero; - } - } -} diff --git a/cw_zano/lib/zano_transaction_history.dart b/cw_zano/lib/zano_transaction_history.dart deleted file mode 100644 index 4c6a2d55..00000000 --- a/cw_zano/lib/zano_transaction_history.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'dart:core'; -import 'package:mobx/mobx.dart'; -import 'package:cw_core/transaction_history.dart'; -import 'package:cw_zano/model/zano_transaction_info.dart'; - -part 'zano_transaction_history.g.dart'; - -class ZanoTransactionHistory = ZanoTransactionHistoryBase - with _$ZanoTransactionHistory; - -abstract class ZanoTransactionHistoryBase - extends TransactionHistoryBase with Store { - ZanoTransactionHistoryBase() { - transactions = ObservableMap(); - } - - @override - Future save() async {} - - @override - void addOne(ZanoTransactionInfo transaction) => - transactions[transaction.id] = transaction; - - @override - void addMany(Map transactions) => - this.transactions.addAll(transactions); -} diff --git a/cw_zano/lib/zano_utils.dart b/cw_zano/lib/zano_utils.dart deleted file mode 100644 index f39f2046..00000000 --- a/cw_zano/lib/zano_utils.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'dart:convert'; - -import 'package:monero/zano.dart' as zano; -import 'package:cw_zano/api/model/get_address_info_result.dart'; - -class ZanoUtils { - static bool validateAddress(String address) { - try { - final result = GetAddressInfoResult.fromJson( - jsonDecode(zano.PlainWallet_getAddressInfo(address)) as Map, - ); - return result.valid; - } catch (err) { - return false; - } - } -} diff --git a/cw_zano/lib/zano_wallet.dart b/cw_zano/lib/zano_wallet.dart deleted file mode 100644 index 913bc083..00000000 --- a/cw_zano/lib/zano_wallet.dart +++ /dev/null @@ -1,587 +0,0 @@ -import 'dart:async'; -import 'dart:core'; -import 'dart:io'; -import 'dart:math'; - -import 'package:cw_core/cake_hive.dart'; -import 'package:cw_core/crypto_currency.dart'; -import 'package:cw_core/node.dart'; -import 'package:cw_core/pathForWallet.dart'; -import 'package:cw_core/pending_transaction.dart'; -import 'package:cw_core/sync_status.dart'; -import 'package:cw_core/transaction_priority.dart'; -import 'package:cw_core/utils/print_verbose.dart'; -import 'package:cw_core/wallet_base.dart'; -import 'package:cw_core/wallet_credentials.dart'; -import 'package:cw_core/wallet_info.dart'; -import 'package:cw_core/zano_asset.dart'; -import 'package:cw_zano/api/model/create_wallet_result.dart'; -import 'package:cw_zano/api/model/destination.dart'; -import 'package:cw_zano/api/model/get_recent_txs_and_info_result.dart'; -import 'package:cw_zano/api/model/get_wallet_status_result.dart'; -import 'package:cw_zano/api/model/transfer.dart'; -import 'package:cw_zano/model/pending_zano_transaction.dart'; -import 'package:cw_zano/model/zano_balance.dart'; -import 'package:cw_zano/model/zano_transaction_creation_exception.dart'; -import 'package:cw_zano/model/zano_transaction_credentials.dart'; -import 'package:cw_zano/model/zano_transaction_info.dart'; -import 'package:cw_zano/model/zano_wallet_keys.dart'; -import 'package:cw_zano/zano_formatter.dart'; -import 'package:cw_zano/zano_transaction_history.dart'; -import 'package:cw_zano/zano_wallet_addresses.dart'; -import 'package:cw_zano/zano_wallet_api.dart'; -import 'package:cw_zano/zano_wallet_exceptions.dart'; -import 'package:cw_zano/zano_wallet_service.dart'; -import 'package:cw_zano/api/model/balance.dart'; - -import 'package:mobx/mobx.dart'; - -part 'zano_wallet.g.dart'; - -class ZanoWallet = ZanoWalletBase with _$ZanoWallet; - -abstract class ZanoWalletBase - extends WalletBase - with Store, ZanoWalletApi { - static const int _autoSaveIntervalSeconds = 30; - static const int _pollIntervalMilliseconds = 5000; - static const int _maxLoadAssetsRetries = 5; - - @override - void setPassword(String password) { - _password = password; - super.setPassword(password); - } - - String _password; - - @override - String get password => _password; - - @override - Future signMessage(String message, {String? address = null}) => - super.signMessage(message, address: address); - - @override - Future verifyMessage(String message, String signature, {String? address = null}) { - throw UnimplementedError(); - } - - @override - ZanoWalletAddresses walletAddresses; - - @override - @observable - SyncStatus syncStatus; - - @override - @observable - ObservableMap balance; - - @override - String seed = ''; - - @override - String? passphrase = ''; - - @override - ZanoWalletKeys keys = ZanoWalletKeys( - privateSpendKey: '', privateViewKey: '', publicSpendKey: '', publicViewKey: ''); - - static const String zanoAssetId = - 'd6329b5b1f7c0805b5c345f4957554002a2f557845f64d7645dae0e051a6498a'; - - Map zanoAssets = {}; - - Timer? _updateSyncInfoTimer; - - int _lastKnownBlockHeight = 0; - int _initialSyncHeight = 0; - int currentDaemonHeight = 0; - bool _isTransactionUpdating; - bool _hasSyncAfterStartup; - Timer? _autoSaveTimer; - - /// number of transactions in each request - static final int _txChunkSize = (pow(2, 32) - 1).toInt(); - - ZanoWalletBase(WalletInfo walletInfo, DerivationInfo derivationInfo, String password) - : balance = ObservableMap.of({CryptoCurrency.zano: ZanoBalance.empty()}), - _isTransactionUpdating = false, - _hasSyncAfterStartup = false, - walletAddresses = ZanoWalletAddresses(walletInfo), - syncStatus = NotConnectedSyncStatus(), - _password = password, - super(walletInfo, derivationInfo) { - transactionHistory = ZanoTransactionHistory(); - if (!CakeHive.isAdapterRegistered(ZanoAsset.typeId)) { - CakeHive.registerAdapter(ZanoAssetAdapter()); - } - } - - @override - int calculateEstimatedFee(TransactionPriority priority, [int? amount = null]) => - getCurrentTxFee(priority); - - @override - Future changePassword(String password) async { - setPassword(password); - } - - static Future create({required WalletCredentials credentials}) async { - final wallet = ZanoWallet(credentials.walletInfo!, await credentials.walletInfo!.getDerivationInfo(), credentials.password!); - await wallet.initWallet(); - final path = await pathForWallet(name: credentials.name, type: credentials.walletInfo!.type); - final createWalletResult = await wallet.createWallet(path, credentials.password!); - await wallet.initWallet(); - await wallet.parseCreateWalletResult(createWalletResult); - if (credentials.passphrase != null) { - await wallet.setPassphrase(credentials.passphrase!); - wallet.seed = await createWalletResult.seed(wallet); - wallet.passphrase = await wallet.getPassphrase(); - } - await wallet.init(createWalletResult.wi.address); - return wallet; - } - - static Future restore( - {required ZanoRestoreWalletFromSeedCredentials credentials}) async { - final wallet = ZanoWallet(credentials.walletInfo!, await credentials.walletInfo!.getDerivationInfo(), credentials.password!); - await wallet.initWallet(); - final path = await pathForWallet(name: credentials.name, type: credentials.walletInfo!.type); - final createWalletResult = await wallet.restoreWalletFromSeed( - path, credentials.password!, credentials.mnemonic, credentials.passphrase); - await wallet.initWallet(); - await wallet.parseCreateWalletResult(createWalletResult); - if (credentials.passphrase != null) { - await wallet.setPassphrase(credentials.passphrase!); - wallet.seed = await createWalletResult.seed(wallet); - wallet.passphrase = await wallet.getPassphrase(); - } - await wallet.init(createWalletResult.wi.address); - return wallet; - } - - static Future open( - {required String name, required String password, required WalletInfo walletInfo}) async { - final path = await pathForWallet(name: name, type: walletInfo.type); - if (ZanoWalletApi.openWalletCache[path] != null) { - final wallet = ZanoWallet(walletInfo, await walletInfo.getDerivationInfo(), password); - await wallet.parseCreateWalletResult(ZanoWalletApi.openWalletCache[path]!).then((_) { - unawaited(wallet.init(ZanoWalletApi.openWalletCache[path]!.wi.address)); - }); - return wallet; - } else { - final wallet = ZanoWallet(walletInfo, await walletInfo.getDerivationInfo(), password); - await wallet.initWallet(); - final createWalletResult = await wallet.loadWallet(path, password); - await wallet.parseCreateWalletResult(createWalletResult).then((_) { - unawaited(wallet.init(createWalletResult.wi.address)); - }); - return wallet; - } - } - - Future parseCreateWalletResult(CreateWalletResult result) async { - hWallet = result.walletId; - seed = await result.seed(this); - keys = ZanoWalletKeys( - privateSpendKey: result.privateSpendKey, - privateViewKey: result.privateViewKey, - publicSpendKey: result.publicSpendKey, - publicViewKey: result.publicViewKey, - ); - passphrase = await getPassphrase(); - - printV('setting hWallet = ${result.walletId}'); - walletAddresses.address = result.wi.address; - await loadAssets(result.wi.balances, maxRetries: _maxLoadAssetsRetries); - for (final item in result.wi.balances) { - if (item.assetInfo.assetId == zanoAssetId) { - balance[CryptoCurrency.zano] = ZanoBalance( - total: item.total, - unlocked: item.unlocked, - ); - } - } - if (result.recentHistory.history != null) { - final transfers = result.recentHistory.history!; - final transactions = Transfer.makeMap(transfers, zanoAssets, currentDaemonHeight); - transactionHistory.addMany(transactions); - await transactionHistory.save(); - } - } - - @override - Future close({bool shouldCleanup = true}) async { - closeWallet(null); - _updateSyncInfoTimer?.cancel(); - _autoSaveTimer?.cancel(); - } - - @override - Future connectToNode({required Node node}) async { - syncStatus = ConnectingSyncStatus(); - await setupNode(node.uriRaw); - syncStatus = ConnectedSyncStatus(); - } - - @override - Future createTransaction(Object credentials) async { - credentials as ZanoTransactionCredentials; - final isZano = credentials.currency == CryptoCurrency.zano; - final outputs = credentials.outputs; - final hasMultiDestination = outputs.length > 1; - final unlockedBalanceZano = balance[CryptoCurrency.zano]?.unlocked ?? BigInt.zero; - final unlockedBalanceCurrency = balance[credentials.currency]?.unlocked ?? BigInt.zero; - final fee = BigInt.from(calculateEstimatedFee(credentials.priority)); - late BigInt totalAmount; - void checkForEnoughBalances() { - if (isZano) { - if (totalAmount + fee > unlockedBalanceZano) { - throw ZanoTransactionCreationException( - "You don't have enough coins (required: ${ZanoFormatter.bigIntAmountToString(totalAmount + fee)} ZANO, unlocked ${ZanoFormatter.bigIntAmountToString(unlockedBalanceZano)} ZANO)."); - } - } else { - if (fee > unlockedBalanceZano) { - throw ZanoTransactionCreationException( - "You don't have enough coins (required: ${ZanoFormatter.bigIntAmountToString(fee)} ZANO, unlocked ${ZanoFormatter.bigIntAmountToString(unlockedBalanceZano)} ZANO)."); - } - if (totalAmount > unlockedBalanceCurrency) { - throw ZanoTransactionCreationException( - "You don't have enough coins (required: ${ZanoFormatter.bigIntAmountToString(totalAmount, credentials.currency.decimals)} ${credentials.currency.title}, unlocked ${ZanoFormatter.bigIntAmountToString(unlockedBalanceCurrency, credentials.currency.decimals)} ${credentials.currency.title})."); - } - } - } - - final assetId = isZano ? zanoAssetId : (credentials.currency as ZanoAsset).assetId; - late List destinations; - if (hasMultiDestination) { - if (outputs.any((output) => output.sendAll || (output.formattedCryptoAmount ?? 0) <= 0)) { - throw ZanoTransactionCreationException("You don't have enough coins."); - } - totalAmount = outputs.fold( - BigInt.zero, (acc, value) => acc + BigInt.from(value.formattedCryptoAmount ?? 0)); - checkForEnoughBalances(); - destinations = outputs - .map((output) => Destination( - amount: BigInt.from(output.formattedCryptoAmount ?? 0), - address: output.isParsedAddress ? output.extractedAddress! : output.address, - assetId: assetId, - )) - .toList(); - } else { - final output = outputs.first; - if (output.sendAll) { - if (isZano) { - totalAmount = unlockedBalanceZano - fee; - } else { - totalAmount = unlockedBalanceCurrency; - } - } else { - totalAmount = BigInt.from(output.formattedCryptoAmount!); - } - checkForEnoughBalances(); - destinations = [ - Destination( - amount: totalAmount, - address: output.isParsedAddress ? output.extractedAddress! : output.address, - assetId: assetId, - ) - ]; - } - return PendingZanoTransaction( - zanoWallet: this, - destinations: destinations, - fee: fee, - comment: outputs.first.note ?? '', - assetId: assetId, - ticker: credentials.currency.title, - decimalPoint: credentials.currency.decimals, - amount: totalAmount, - ); - } - - @override - Future> fetchTransactions() async { - try { - final transfers = []; - late GetRecentTxsAndInfoResult result; - do { - result = await getRecentTxsAndInfo(offset: 0, count: _txChunkSize); - // _lastTxIndex += result.transfers.length; - transfers.addAll(result.transfers); - } while (result.lastItemIndex + 1 < result.totalTransfers); - return Transfer.makeMap(transfers, zanoAssets, currentDaemonHeight); - } catch (e) { - printV((e.toString())); - return {}; - } - } - - Future init(String address) async { - await walletAddresses.init(); - await walletAddresses.updateAddress(address); - await updateTransactions(); - _autoSaveTimer = Timer.periodic(Duration(seconds: _autoSaveIntervalSeconds), (_) async { - await save(); - }); - } - - @override - Future renameWalletFiles(String newWalletName) async { - final currentWalletPath = await pathForWallet(name: name, type: type); - final currentCacheFile = File(currentWalletPath); - final currentKeysFile = File('$currentWalletPath.keys'); - final currentAddressListFile = File('$currentWalletPath.address.txt'); - - final newWalletPath = await pathForWallet(name: newWalletName, type: type); - - // Copies current wallet files into new wallet name's dir and files - if (currentCacheFile.existsSync()) { - await currentCacheFile.copy(newWalletPath); - } - if (currentKeysFile.existsSync()) { - await currentKeysFile.copy('$newWalletPath.keys'); - } - if (currentAddressListFile.existsSync()) { - await currentAddressListFile.copy('$newWalletPath.address.txt'); - } - - // Delete old name's dir and files - await Directory(currentWalletPath).delete(recursive: true); - } - - @override - Future rescan({required int height}) => throw UnimplementedError(); - - @override - Future save() async { - try { - await store(); - await walletAddresses.updateAddressesInBox(); - } catch (e) { - printV(('Error while saving Zano wallet file ${e.toString()}')); - } - } - - Future loadAssets(List balances, {int maxRetries = 1}) async { - List assets = []; - int retryCount = 0; - - while (retryCount < maxRetries) { - try { - assets = await getAssetsWhitelist(); - break; - } on ZanoWalletBusyException { - if (retryCount < maxRetries - 1) { - retryCount++; - await Future.delayed(Duration(seconds: 1)); - } else { - printV(('failed to load assets after $retryCount retries')); - break; - } - } - } - zanoAssets = {}; - for (final asset in assets) { - final newAsset = ZanoAsset.copyWith( - asset, - enabled: balances.any((element) => element.assetId == asset.assetId), - ); - zanoAssets.putIfAbsent(asset.assetId, () => newAsset); - } - } - - @override - Future startSync() async { - try { - syncStatus = AttemptingSyncStatus(); - _lastKnownBlockHeight = 0; - _initialSyncHeight = 0; - _updateSyncInfoTimer ??= - Timer.periodic(Duration(milliseconds: _pollIntervalMilliseconds), (_) => _updateSyncInfo()); - } catch (e) { - syncStatus = FailedSyncStatus(); - printV((e.toString())); - } - } - - @override - Future? updateBalance() => null; - - @override - Future checkNodeHealth() async { - try { - final status = await getWalletStatus(); - - return status.isDaemonConnected; - } catch (_) { - return false; - } - } - - Future updateTransactions() async { - try { - if (_isTransactionUpdating) { - return; - } - _isTransactionUpdating = true; - final transactions = await fetchTransactions(); - transactionHistory.clear(); - transactionHistory.addMany(transactions); - await transactionHistory.save(); - _isTransactionUpdating = false; - } catch (e) { - printV("e: $e"); - printV((e.toString())); - _isTransactionUpdating = false; - } - } - - Future addZanoAssetById(String assetId) async { - if (zanoAssets.containsKey(assetId)) { - throw ZanoWalletException('zano asset with id $assetId already added'); - } - final assetDescriptor = await addAssetsWhitelist(assetId); - if (assetDescriptor == null) { - throw ZanoWalletException("there's no zano asset with id $assetId"); - } - final asset = ZanoAsset.copyWith( - assetDescriptor, - assetId: assetId, - enabled: true, - ); - zanoAssets[asset.assetId] = asset; - balance[asset] = ZanoBalance.empty(decimalPoint: asset.decimalPoint); - return asset; - } - - Future changeZanoAssetAvailability(ZanoAsset asset) async { - if (asset.enabled) { - final assetDescriptor = await addAssetsWhitelist(asset.assetId); - if (assetDescriptor == null) { - printV(('Error adding zano asset')); - } - } else { - final result = await removeAssetsWhitelist(asset.assetId); - if (result == false) { - printV(('Error removing zano asset')); - } - } - } - - Future deleteZanoAsset(ZanoAsset asset) async { - final _ = await removeAssetsWhitelist(asset.assetId); - } - - Future getZanoAsset(String assetId) async { - // wallet api is not available while the wallet is syncing so only call it if it's synced - if (syncStatus is SyncedSyncStatus) { - return await getAssetInfo(assetId); - } - return null; - } - - Future _askForUpdateTransactionHistory() async => await updateTransactions(); - - void _onNewBlock(int height, int blocksLeft, double ptc) async { - try { - if (blocksLeft < 1000) { - await _askForUpdateTransactionHistory(); - syncStatus = SyncedSyncStatus(); - - if (!_hasSyncAfterStartup) { - _hasSyncAfterStartup = true; - await save(); - } - } else { - syncStatus = SyncingSyncStatus(blocksLeft, ptc); - } - } catch (e) { - printV((e.toString())); - } - } - - void _updateSyncProgress(GetWalletStatusResult walletStatus) { - final syncHeight = walletStatus.currentWalletHeight; - if (_initialSyncHeight <= 0) { - _initialSyncHeight = syncHeight; - } - final bchHeight = walletStatus.currentDaemonHeight; - - if (_lastKnownBlockHeight == syncHeight) { - return; - } - - _lastKnownBlockHeight = syncHeight; - final track = bchHeight - _initialSyncHeight; - final diff = track - (bchHeight - syncHeight); - final ptc = diff <= 0 ? 0.0 : diff / track; - final left = bchHeight - syncHeight; - - if (syncHeight < 0 || left < 0) { - return; - } - - // 1. Actual new height; 2. Blocks left to finish; 3. Progress in percents; - _onNewBlock.call(syncHeight, left, ptc); - } - - void _updateSyncInfo() async { - GetWalletStatusResult walletStatus; - // ignoring get wallet status exception (in case of wrong wallet id) - try { - walletStatus = await getWalletStatus(); - } on ZanoWalletException { - return; - } - currentDaemonHeight = walletStatus.currentDaemonHeight; - _updateSyncProgress(walletStatus); - - // we can call getWalletInfo ONLY if getWalletStatus returns NOT is in long refresh and wallet state is 2 (ready) - if (!walletStatus.isInLongRefresh && walletStatus.walletState == 2) { - final walletInfo = await getWalletInfo(); - seed = await walletInfo.wiExtended.seed(this); - keys = ZanoWalletKeys( - privateSpendKey: walletInfo.wiExtended.spendPrivateKey, - privateViewKey: walletInfo.wiExtended.viewPrivateKey, - publicSpendKey: walletInfo.wiExtended.spendPublicKey, - publicViewKey: walletInfo.wiExtended.viewPublicKey, - ); - loadAssets(walletInfo.wi.balances); - // matching balances and whitelists - // 1. show only balances available in whitelists - // 2. set whitelists available in balances as 'enabled' ('disabled' by default) - for (final b in walletInfo.wi.balances) { - if (b.assetId == zanoAssetId) { - balance[CryptoCurrency.zano] = ZanoBalance(total: b.total, unlocked: b.unlocked); - } else { - final asset = zanoAssets[b.assetId]; - if (asset == null) { - printV('balance for an unknown asset ${b.assetInfo.assetId}'); - continue; - } - if (balance.keys.any( - (element) => element is ZanoAsset && element.assetId == b.assetInfo.assetId)) { - balance[balance.keys.firstWhere((element) => - element is ZanoAsset && element.assetId == b.assetInfo.assetId)] = - ZanoBalance( - total: b.total, unlocked: b.unlocked, decimalPoint: asset.decimalPoint); - } else { - balance[asset] = ZanoBalance( - total: b.total, unlocked: b.unlocked, decimalPoint: asset.decimalPoint); - } - } - } - await updateTransactions(); - // removing balances for assets missing in wallet info balances - balance.removeWhere( - (key, _) => - key != CryptoCurrency.zano && - !walletInfo.wi.balances - .any((element) => element.assetId == (key as ZanoAsset).assetId), - ); - } - } -} diff --git a/cw_zano/lib/zano_wallet_addresses.dart b/cw_zano/lib/zano_wallet_addresses.dart deleted file mode 100644 index 1562ea8e..00000000 --- a/cw_zano/lib/zano_wallet_addresses.dart +++ /dev/null @@ -1,44 +0,0 @@ -import 'package:cw_core/payment_uris.dart'; -import 'package:cw_core/utils/print_verbose.dart'; -import 'package:cw_core/wallet_addresses.dart'; -import 'package:cw_core/wallet_info.dart'; -import 'package:mobx/mobx.dart'; - -part 'zano_wallet_addresses.g.dart'; - -class ZanoWalletAddresses = ZanoWalletAddressesBase with _$ZanoWalletAddresses; - -abstract class ZanoWalletAddressesBase extends WalletAddresses with Store { - ZanoWalletAddressesBase(WalletInfo walletInfo) - : address = '', - super(walletInfo); - - @override - @observable - String address; - - @override - Future init() async { - address = walletInfo.address; - await updateAddressesInBox(); - } - - Future updateAddress(String address) async { - this.address = address; - await updateAddressesInBox(); - } - - @override - Future updateAddressesInBox() async { - try { - addressesMap.clear(); - addressesMap[address] = ''; - await saveAddressesInBox(); - } catch (e) { - printV(e.toString()); - } - } - - @override - PaymentURI getPaymentUri(String amount) => ZanoURI(amount: amount, address: address); -} diff --git a/cw_zano/lib/zano_wallet_api.dart b/cw_zano/lib/zano_wallet_api.dart deleted file mode 100644 index 0af9af2e..00000000 --- a/cw_zano/lib/zano_wallet_api.dart +++ /dev/null @@ -1,548 +0,0 @@ -import 'dart:convert' as convert; -import 'dart:ffi'; -import 'dart:io'; -import 'dart:isolate'; - -import 'package:cw_core/transaction_priority.dart'; -import 'package:cw_core/utils/print_verbose.dart'; -import 'package:cw_core/zano_asset.dart'; -import 'package:cw_zano/api/consts.dart'; -import 'package:cw_zano/api/model/asset_id_params.dart'; -import 'package:cw_zano/api/model/create_wallet_result.dart'; -import 'package:cw_zano/api/model/destination.dart'; -import 'package:cw_zano/api/model/get_address_info_result.dart'; -import 'package:cw_zano/api/model/get_recent_txs_and_info_params.dart'; -import 'package:cw_zano/api/model/get_recent_txs_and_info_result.dart'; -import 'package:cw_zano/api/model/get_wallet_info_result.dart'; -import 'package:cw_zano/api/model/get_wallet_status_result.dart'; -import 'package:cw_zano/api/model/proxy_to_daemon_params.dart'; -import 'package:cw_zano/api/model/proxy_to_daemon_result.dart'; -import 'package:cw_zano/api/model/store_result.dart'; -import 'package:cw_zano/api/model/transfer.dart'; -import 'package:cw_zano/api/model/transfer_params.dart'; -import 'package:cw_zano/api/model/transfer_result.dart'; -import 'package:cw_zano/zano_wallet_exceptions.dart'; -import 'package:ffi/ffi.dart'; -import 'package:json_bigint/json_bigint.dart'; -import 'package:monero/zano.dart' as zano; -import 'package:monero/src/generated_bindings_zano.g.dart' as zanoapi; -import 'package:path/path.dart' as p; - -mixin ZanoWalletApi { - static const _maxReopenAttempts = 5; - static const _logInfo = false; - static const int _zanoMixinValue = 10; - - int _hWallet = 0; - - int get hWallet => _hWallet; - - set hWallet(int value) { - _hWallet = value; - } - - int getCurrentTxFee(TransactionPriority priority) => zano.PlainWallet_getCurrentTxFee(priority.raw); - - void setPassword(String password) => zano.PlainWallet_resetWalletPassword(hWallet, password); - - void closeWallet(int? walletToClose, {bool force = false}) async { - printV('close_wallet ${walletToClose ?? hWallet}: $force'); - if (Platform.isWindows || force) { - final result = await _closeWallet(walletToClose ?? hWallet); - printV('close_wallet result $result'); - openWalletCache.removeWhere((_, cwr) => cwr.walletId == (walletToClose ?? hWallet)); - } - } - - static bool isInit = false; - - Future initWallet() async { - if (isInit) return true; - final result = zano.PlainWallet_init("", "", 0); - isInit = true; - return result == "OK"; - } - - Future setupNode(String nodeUrl) async { - await _setupNode(hWallet, nodeUrl); - return true; - } - - Future getWalletDir() async { - final walletInfoResult = await getWalletInfo(); - return Directory(p.dirname(walletInfoResult.wi.path)); - } - - Future _getWalletSecretsFile() async { - final dir = await getWalletDir(); - final file = File(p.join(dir.path, "zano-secrets.json.bin")); - return file; - } - - Future> _getSecrets() async { - final file = await _getWalletSecretsFile(); - if (!file.existsSync()) { - return {}; - } - final data = file.readAsBytesSync(); - final b64 = convert.base64.encode(data); - final respStr = await invokeMethod("decrypt_data", {"buff": "$b64"}); - final resp = convert.json.decode(respStr); - final dataBytes = convert.base64.decode(resp["result"]["res_buff"] as String); - final dataStr = convert.utf8.decode(dataBytes); - final dataObject = convert.json.decode(dataStr); - return dataObject as Map; - } - - Future _setSecrets(Map data) async { - final dataStr = convert.json.encode(data); - final b64 = convert.base64.encode(convert.utf8.encode(dataStr)); - final respStr = await invokeMethod("encrypt_data", {"buff": "$b64"}); - final resp = convert.json.decode(respStr); - final dataBytes = convert.base64.decode(resp["result"]["res_buff"] as String); - final file = await _getWalletSecretsFile(); - file.writeAsBytesSync(dataBytes); - } - - Future _getWalletSecret(String key) async { - final secrets = await _getSecrets(); - return secrets[key] as String?; - } - - Future _setWalletSecret(String key, String value) async { - final secrets = await _getSecrets(); - secrets[key] = value; - await _setSecrets(secrets); - } - - Future getPassphrase() async { - return await _getWalletSecret("passphrase"); - } - - Future setPassphrase(String passphrase) { - return _setWalletSecret("passphrase", passphrase); - } - - Future getSeed() async { - final passphrase = await getPassphrase(); - final respStr = await invokeMethod("get_restore_info", {"seed_password": passphrase??""}); - final resp = convert.json.decode(respStr); - return resp["result"]["seed_phrase"] as String; - } - - Future getWalletInfo() async { - final json = await _getWalletInfo(hWallet); - final result = GetWalletInfoResult.fromJson(jsonDecode(json)); - printV('get_wallet_info got ${result.wi.balances.length} balances: ${result.wi.balances}'); - return result; - } - - Future getWalletStatus() async { - final json = await _getWalletStatus(hWallet); - if (json == Consts.errorWalletWrongId) { - printV('wrong wallet id'); - throw ZanoWalletException('Wrong wallet id'); - } - final status = GetWalletStatusResult.fromJson(jsonDecode(json)); - if (_logInfo) - printV( - 'get_wallet_status connected: ${status.isDaemonConnected} in refresh: ${status.isInLongRefresh} progress: ${status.progress} wallet state: ${status.walletState} sync: ${status.currentWalletHeight}/${status.currentDaemonHeight} ${(status.currentWalletHeight/status.currentDaemonHeight*100).toStringAsFixed(2)}%'); - return status; - } - - Future invokeMethod(String methodName, Object params) async { - final request = jsonEncode({ - "method": methodName, - "params": params, - }); - final invokeResult = await callSyncMethod('invoke', hWallet, request); - try { - jsonDecode(invokeResult); - } catch (e) { - if (invokeResult.contains(Consts.errorWalletWrongId)) throw ZanoWalletException('Wrong wallet id'); - printV('exception in parsing json in invokeMethod: $invokeResult'); - rethrow; - } - return invokeResult; - } - - Future> getAssetsWhitelist() async { - try { - final json = await invokeMethod('assets_whitelist_get', '{}'); - final map = jsonDecode(json) as Map?; - _checkForErrors(map); - List assets(String type, bool isGlobalWhitelist) => - (map?['result']?[type] as List?) - ?.map((e) => ZanoAsset.fromJson(e as Map, isInGlobalWhitelist: isGlobalWhitelist)) - .toList() ?? - []; - final localWhitelist = assets('local_whitelist', false); - final globalWhitelist = assets('global_whitelist', true); - final ownAssets = assets('own_assets', false); - if (_logInfo) - printV('assets_whitelist_get got local whitelist: ${localWhitelist.length} ($localWhitelist); ' - 'global whitelist: ${globalWhitelist.length} ($globalWhitelist); ' - 'own assets: ${ownAssets.length} ($ownAssets)'); - return [...globalWhitelist, ...localWhitelist, ...ownAssets]; - } catch (e) { - printV('assets_whitelist_get $e'); - return []; - // rethrow; - } - } - - Future addAssetsWhitelist(String assetId) async { - try { - final json = await invokeMethod('assets_whitelist_add', AssetIdParams(assetId: assetId)); - final map = jsonDecode(json) as Map?; - _checkForErrors(map); - if (map!['result']!['status']! == 'OK') { - final assetDescriptor = ZanoAsset.fromJson(map['result']!['asset_descriptor']! as Map); - printV('assets_whitelist_add added ${assetDescriptor.fullName} ${assetDescriptor.ticker}'); - return assetDescriptor; - } else { - printV('assets_whitelist_add status ${map['result']!['status']!}'); - return null; - } - } catch (e) { - printV('assets_whitelist_add $e'); - return null; - } - } - - Future removeAssetsWhitelist(String assetId) async { - try { - final json = await invokeMethod('assets_whitelist_remove', AssetIdParams(assetId: assetId)); - final map = jsonDecode(json) as Map?; - _checkForErrors(map); - printV('assets_whitelist_remove status ${map!['result']!['status']!}'); - return (map['result']!['status']! == 'OK'); - } catch (e) { - printV('assets_whitelist_remove $e'); - return false; - } - } - - Future _proxyToDaemon(String uri, String body) async { - final json = await invokeMethod('proxy_to_daemon', ProxyToDaemonParams(body: body, uri: uri)); - final map = jsonDecode(json) as Map?; - _checkForErrors(map); - return ProxyToDaemonResult.fromJson(map!['result'] as Map); - } - - Future getAssetInfo(String assetId) async { - final methodName = 'get_asset_info'; - final params = AssetIdParams(assetId: assetId); - final result = await _proxyToDaemon('/json_rpc', '{"method": "$methodName","params": ${jsonEncode(params)}}'); - if (result == null) { - printV('get_asset_info empty result'); - return null; - } - try { - final map = jsonDecode(result.body) as Map?; - if (map!['error'] != null) { - printV( - 'get_asset_info $assetId error ${map['error']!['code']} ${map['error']!['message']}'); - return null; - } else if (map['result']!['status']! == 'OK') { - final assetDescriptor = ZanoAsset.fromJson( - map['result']!['asset_descriptor']! as Map); - printV('get_asset_info $assetId ${assetDescriptor.fullName} ${assetDescriptor.ticker}'); - return assetDescriptor; - } else { - printV('get_asset_info $assetId status ${map['result']!['status']!}'); - return null; - } - } catch (_) { - return null; - } - } - - Future store() async { - try { - final json = await invokeMethod('store', {}); - final map = jsonDecode(json) as Map?; - _checkForErrors(map); - return StoreResult.fromJson(map!['result'] as Map); - } catch (e) { - printV('store $e'); - return null; - } - } - - Future getRecentTxsAndInfo({required int offset, required int count}) async { - printV('get_recent_txs_and_info $offset $count'); - try { - final json = await invokeMethod('get_recent_txs_and_info', GetRecentTxsAndInfoParams(offset: offset, count: count)); - final map = jsonDecode(json) as Map?; - _checkForErrors(map); - final lastItemIndex = map?['result']?['last_item_index'] as int?; - final totalTransfers = map?['result']?['total_transfers'] as int?; - final transfers = map?['result']?['transfers'] as List?; - if (transfers == null || lastItemIndex == null || totalTransfers == null) { - printV('get_recent_txs_and_info empty transfers'); - return GetRecentTxsAndInfoResult.empty(); - } - printV('get_recent_txs_and_info transfers.length: ${transfers.length}'); - return GetRecentTxsAndInfoResult( - transfers: transfers.map((e) => Transfer.fromJson(e as Map)).toList(), - lastItemIndex: lastItemIndex, - totalTransfers: totalTransfers, - ); - } catch (e) { - printV('get_recent_txs_and_info $e'); - return GetRecentTxsAndInfoResult.empty(); - } - } - - GetAddressInfoResult getAddressInfo(String address) => GetAddressInfoResult.fromJson( - jsonDecode(zano.PlainWallet_getAddressInfo(address)), - ); - - String _shorten(String s) => s.length > 10 ? '${s.substring(0, 4)}...${s.substring(s.length - 4)}' : s; - - Future createWallet(String path, String password) async { - printV('create_wallet path $path password ${_shorten(password)}'); - final json = zano.PlainWallet_generate(path, password); - final map = jsonDecode(json) as Map?; - if (map?['error'] != null) { - final code = map!['error']?['code'] ?? ''; - final message = map['error']?['message'] ?? ''; - throw ZanoWalletException('Error creating wallet file, $message ($code)'); - } - if (map?['result'] == null) { - throw ZanoWalletException('Error creating wallet file, empty response'); - } - final result = CreateWalletResult.fromJson(map!['result'] as Map); - openWalletCache[path] = result; - printV('create_wallet ${result.name}'); - return result; - } - - Future restoreWalletFromSeed(String path, String password, String seed, String? passphrase) async { - printV('restore_wallet path $path'); - final json = zano.PlainWallet_restore(seed, path, password, passphrase??''); - final map = jsonDecode(json) as Map?; - if (map?['error'] != null) { - final code = map!['error']!['code'] ?? ''; - final message = map['error']!['message'] ?? ''; - if (code == Consts.errorWrongSeed) { - throw RestoreFromSeedsException('Error restoring wallet\nPlease check the seed words are correct. Additionally, if you created this wallet with a passphrase please add it under the Advanced Settings page.'); - } else if (code == Consts.errorAlreadyExists) { - throw RestoreFromSeedsException('Error restoring wallet, already exists'); - } - throw RestoreFromSeedsException('Error restoring wallet, $message ($code)'); - } - if (map?['result'] == null) { - throw RestoreFromSeedsException('Error restoring wallet, empty response'); - } - final result = CreateWalletResult.fromJson(map!['result'] as Map); - openWalletCache[path] = result; - printV('restore_wallet ${result.name} ${result.wi.address}'); - return result; - } - - Future loadWallet(String path, String password, [int attempt = 0]) async { - printV('load_wallet1 path $path'); - final String json; - try { - json = zano.PlainWallet_open(path, password); - } catch (e) { - printV('error in loadingWallet $e'); - rethrow; - } - - final map = jsonDecode(json) as Map?; - if (map?['error'] != null) { - final code = map?['error']!['code'] ?? ''; - final message = map?['error']!['message'] ?? ''; - if (code == Consts.errorAlreadyExists && attempt <= _maxReopenAttempts) { - // already connected to this wallet. closing and trying to reopen - printV('already connected. closing and reopen wallet (attempt $attempt)'); - closeWallet(attempt, force: true); - await Future.delayed(const Duration(milliseconds: 500)); - return await loadWallet(path, password, attempt + 1); - } - throw ZanoWalletException('Error loading wallet, $message ($code)'); - } - if (map?['result'] == null) { - throw ZanoWalletException('Error loading wallet, empty response'); - } - final result = CreateWalletResult.fromJson(map!['result'] as Map); - printV('load_wallet3 ${result.name} ${result.wi.address}'); - openWalletCache[path] = result; - return result; - } - - static Map openWalletCache = {}; - - Future transfer(List destinations, BigInt fee, String comment) async { - final params = TransferParams( - destinations: destinations, - fee: fee, - mixin: _zanoMixinValue, - paymentId: '', - comment: comment, - pushPayer: false, - hideReceiver: true, - ); - final json = await invokeMethod('transfer', params); - final map = jsonDecode(json); - final resultMap = map as Map?; - if (resultMap != null) { - final transferResultMap = resultMap['result'] as Map?; - if (transferResultMap != null) { - final transferResult = TransferResult.fromJson(transferResultMap); - printV('transfer success hash ${transferResult.txHash}'); - return transferResult; - } else { - final errorCode = resultMap['error']?['code']; - final code = errorCode is int ? errorCode.toString() : errorCode as String? ?? ''; - final message = resultMap['error']?['message'] as String? ?? ''; - printV('transfer error $code $message'); - throw TransferException('Transfer error, $message ($code)'); - } - } - printV('transfer error empty result'); - throw TransferException('Transfer error, empty result'); - } - - Future signMessage(String message, {String? address = null}) async { - try { - final messageBase64 = convert.base64.encode(convert.utf8.encode(message)); - final response = await invokeMethod('sign_message', {'buff': messageBase64}); - final responseData = convert.jsonDecode(response) as Map; - - if (responseData['error'] != null) { - printV('ZANO sign_message error: ${responseData['error']}'); - throw Exception('Zano sign_message failed: ${responseData['error']}'); - } - - final result = responseData['result'] as Map?; - if (result == null) { - throw Exception('Invalid response from sign_message'); - } - - final signature = result['sig'] as String?; - - if (signature == null) { - throw Exception('No signature in response'); - } - - return signature; - } catch (e) { - printV('ZANO signMessage error: $e'); - rethrow; - } - } - - void _checkForErrors(Map? map) { - if (map == null) { - throw ZanoWalletException('Empty response'); - } - final result = map['result']; - if (result == null) { - throw ZanoWalletException('Empty response'); - } - if (result['error'] != null) { - final code = result['error']!['code'] ?? ''; - final message = result['error']!['message'] ?? ''; - if (code == -1 && message == Consts.errorBusy) { - throw ZanoWalletBusyException(); - } - throw ZanoWalletException('Error, $message ($code)'); - } - } - -} - -Future callSyncMethod(String methodName, int hWallet, String params) async { - final params_ = params.toNativeUtf8().address; - final method_name_ = methodName.toNativeUtf8().address; - final invokeResult = await Isolate.run(() async { - final lib = zanoapi.ZanoC(DynamicLibrary.open(zano.libPath)); - final txid = lib.ZANO_PlainWallet_syncCall( - Pointer.fromAddress(method_name_).cast(), - hWallet, - Pointer.fromAddress(params_).cast() - ); - try { - final strPtr = txid.cast(); - final str = strPtr.toDartString(); - lib.ZANO_free(strPtr.cast()); - return str; - } catch (e) { - return ""; - } - }); - calloc.free(Pointer.fromAddress(method_name_)); - calloc.free(Pointer.fromAddress(params_)); - return invokeResult; -} - -Map jsonDecode(String json) { - try { - return decodeJson(json.replaceAll("\\/", "/")) as Map; - } catch (e) { - return convert.jsonDecode(json) as Map; - } -} - -String jsonEncode(Object? object) { - return convert.jsonEncode(object); -} - -Future _getWalletStatus(int hWallet) async { - final jsonPtr = await Isolate.run(() async { - final lib = zanoapi.ZanoC(DynamicLibrary.open(zano.libPath)); - final status = lib.ZANO_PlainWallet_getWalletStatus( - hWallet, - ); - return status.address; - }); - String json = ""; - try { - final strPtr = Pointer.fromAddress(jsonPtr).cast(); - final str = strPtr.toDartString(); - zano.ZANO_free(strPtr.cast()); - json = str; - } catch (e) { - json = ""; - } - return json; -} -Future _getWalletInfo(int hWallet) async { - final jsonPtr = await Isolate.run(() async { - final lib = zanoapi.ZanoC(DynamicLibrary.open(zano.libPath)); - final status = lib.ZANO_PlainWallet_getWalletInfo( - hWallet, - ); - return status.address; - }); - String json = ""; - try { - final strPtr = Pointer.fromAddress(jsonPtr).cast(); - final str = strPtr.toDartString(); - zano.ZANO_free(strPtr.cast()); - json = str; - } catch (e) { - json = ""; - } - return json; -} - -Future _setupNode(int hWallet, String nodeUrl) async { - await callSyncMethod("reset_connection_url", hWallet, nodeUrl); - await callSyncMethod("run_wallet", hWallet, ""); - return "OK"; -} - -Future _closeWallet(int hWallet) async { - final str = await Isolate.run(() async { - return zano.PlainWallet_closeWallet(hWallet); - }); - printV("Closing wallet: $str"); - return str; -} - -Map> debugCallLength() => zano.debugCallLength; diff --git a/cw_zano/lib/zano_wallet_exceptions.dart b/cw_zano/lib/zano_wallet_exceptions.dart deleted file mode 100644 index a0a7b493..00000000 --- a/cw_zano/lib/zano_wallet_exceptions.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:cw_core/exceptions.dart'; - -class ZanoWalletException implements Exception { - final String message; - - ZanoWalletException(this.message); - @override - String toString() => '${this.runtimeType} (message: $message)'; -} - -class RestoreFromSeedsException extends RestoreFromSeedException { - RestoreFromSeedsException(String message) : super(message); -} - -class TransferException extends ZanoWalletException { - TransferException(String message): super(message); -} - -class ZanoWalletBusyException extends ZanoWalletException { - ZanoWalletBusyException(): super(''); -} \ No newline at end of file diff --git a/cw_zano/lib/zano_wallet_service.dart b/cw_zano/lib/zano_wallet_service.dart deleted file mode 100644 index 98d350a4..00000000 --- a/cw_zano/lib/zano_wallet_service.dart +++ /dev/null @@ -1,131 +0,0 @@ -import 'dart:io'; - -import 'package:collection/collection.dart'; -import 'package:cw_core/pathForWallet.dart'; -import 'package:cw_core/utils/print_verbose.dart'; -import 'package:cw_core/wallet_base.dart'; -import 'package:cw_core/wallet_credentials.dart'; -import 'package:cw_core/wallet_info.dart'; -import 'package:cw_core/wallet_service.dart'; -import 'package:cw_core/wallet_type.dart'; -import 'package:cw_zano/zano_wallet.dart'; -import 'package:cw_zano/zano_wallet_api.dart'; -import 'package:hive/hive.dart'; -import 'package:monero/zano.dart' as zano; - -class ZanoNewWalletCredentials extends WalletCredentials { - ZanoNewWalletCredentials({required String name, String? password, required String? passphrase}) : super(name: name, password: password, passphrase: passphrase); -} - -class ZanoRestoreWalletFromSeedCredentials extends WalletCredentials { - ZanoRestoreWalletFromSeedCredentials({required String name, required String password, required String passphrase, required int height, required this.mnemonic}) - : super(name: name, password: password, passphrase: passphrase, height: height); - - final String mnemonic; -} - -class ZanoRestoreWalletFromKeysCredentials extends WalletCredentials { - ZanoRestoreWalletFromKeysCredentials( - {required String name, - required String password, - required this.language, - required this.address, - required this.viewKey, - required this.spendKey, - required int height}) - : super(name: name, password: password, height: height); - - final String language; - final String address; - final String viewKey; - final String spendKey; -} - -class ZanoWalletService extends WalletService { - ZanoWalletService(); - - static bool walletFilesExist(String path) => !File(path).existsSync() && !File('$path.keys').existsSync(); - - int hWallet = 0; - - @override - WalletType getType() => WalletType.zano; - - @override - Future create(WalletCredentials credentials, {bool? isTestnet}) async { - printV('zanowallet service create isTestnet $isTestnet'); - return await ZanoWalletBase.create(credentials: credentials); - } - - @override - Future isWalletExit(String name) async { - final path = await pathForWallet(name: name, type: getType()); - return zano.PlainWallet_isWalletExist(path); - } - - @override - Future openWallet(String name, String password) async { - final walletInfo = await WalletInfo.get(name, getType()); - if (walletInfo == null) { - throw Exception('Wallet not found'); - } - try { - final wallet = await ZanoWalletBase.open(name: name, password: password, walletInfo: walletInfo); - saveBackup(name); - return wallet; - } catch (e) { - await restoreWalletFilesFromBackup(name); - return await ZanoWalletBase.open(name: name, password: password, walletInfo: walletInfo); - } - } - - @override - Future remove(String wallet) async { - final path = await pathForWalletDir(name: wallet, type: getType()); - final file = Directory(path); - final isExist = file.existsSync(); - - if (isExist) { - await file.delete(recursive: true); - } - - final walletInfo = await WalletInfo.get(wallet, getType()); - if (walletInfo == null) { - throw Exception('Wallet not found'); - } - await WalletInfo.delete(walletInfo); - } - - @override - Future rename(String currentName, String password, String newName) async { - final currentWalletInfo = await WalletInfo.get(currentName, getType()); - if (currentWalletInfo == null) { - throw Exception('Wallet not found'); - } - final currentWallet = ZanoWallet(currentWalletInfo, await currentWalletInfo.getDerivationInfo(), password); - - await currentWallet.renameWalletFiles(newName); - - final newWalletInfo = currentWalletInfo; - newWalletInfo.id = WalletBase.idFor(newName, getType()); - newWalletInfo.name = newName; - - await newWalletInfo.save(); - } - - @override - Future restoreFromKeys(ZanoRestoreWalletFromKeysCredentials credentials, {bool? isTestnet}) async { - throw UnimplementedError(); - } - - @override - Future restoreFromSeed(ZanoRestoreWalletFromSeedCredentials credentials, {bool? isTestnet}) async { - return ZanoWalletBase.restore(credentials: credentials); - } - - @override - Future restoreFromHardwareWallet(ZanoNewWalletCredentials credentials) { - throw UnimplementedError("Restoring a Zano wallet from a hardware wallet is not yet supported!"); - } -} diff --git a/cw_zano/pubspec.lock b/cw_zano/pubspec.lock deleted file mode 100644 index 662ccded..00000000 --- a/cw_zano/pubspec.lock +++ /dev/null @@ -1,956 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - _fe_analyzer_shared: - dependency: transitive - description: - name: _fe_analyzer_shared - sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab" - url: "https://pub.dev" - source: hosted - version: "76.0.0" - _macros: - dependency: transitive - description: dart - source: sdk - version: "0.3.3" - analyzer: - dependency: transitive - description: - name: analyzer - sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e" - url: "https://pub.dev" - source: hosted - version: "6.11.0" - args: - dependency: transitive - description: - name: args - sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6 - url: "https://pub.dev" - source: hosted - version: "2.6.0" - asn1lib: - dependency: transitive - description: - name: asn1lib - sha256: "4bae5ae63e6d6dd17c4aac8086f3dec26c0236f6a0f03416c6c19d830c367cf5" - url: "https://pub.dev" - source: hosted - version: "1.5.8" - async: - dependency: transitive - description: - name: async - sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" - url: "https://pub.dev" - source: hosted - version: "2.13.0" - bech32: - dependency: transitive - description: - path: "." - ref: HEAD - resolved-ref: "05755063b593aa6cca0a4820a318e0ce17de6192" - url: "https://github.com/cake-tech/bech32.git" - source: git - version: "0.2.2" - blockchain_utils: - dependency: transitive - description: - path: "." - ref: cake-update-v2 - resolved-ref: "59fdf29d72068e0522a96a8953ed7272833a9f57" - url: "https://github.com/cake-tech/blockchain_utils" - source: git - version: "3.3.0" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - build: - dependency: transitive - description: - name: build - sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - build_config: - dependency: transitive - description: - name: build_config - sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 - url: "https://pub.dev" - source: hosted - version: "1.1.1" - build_daemon: - dependency: transitive - description: - name: build_daemon - sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9" - url: "https://pub.dev" - source: hosted - version: "4.0.2" - build_resolvers: - dependency: "direct dev" - description: - name: build_resolvers - sha256: b9e4fda21d846e192628e7a4f6deda6888c36b5b69ba02ff291a01fd529140f0 - url: "https://pub.dev" - source: hosted - version: "2.4.4" - build_runner: - dependency: "direct dev" - description: - name: build_runner - sha256: "058fe9dce1de7d69c4b84fada934df3e0153dd000758c4d65964d0166779aa99" - url: "https://pub.dev" - source: hosted - version: "2.4.15" - build_runner_core: - dependency: transitive - description: - name: build_runner_core - sha256: "22e3aa1c80e0ada3722fe5b63fd43d9c8990759d0a2cf489c8c5d7b2bdebc021" - url: "https://pub.dev" - source: hosted - version: "8.0.0" - built_collection: - dependency: transitive - description: - name: built_collection - sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" - url: "https://pub.dev" - source: hosted - version: "5.1.1" - built_value: - dependency: transitive - description: - name: built_value - sha256: "8b158ab94ec6913e480dc3f752418348b5ae099eb75868b5f4775f0572999c61" - url: "https://pub.dev" - source: hosted - version: "8.9.4" - cake_backup: - dependency: transitive - description: - path: "." - ref: main - resolved-ref: "3aba867dcab6737f6707782f5db15d71f303db38" - url: "https://github.com/cake-tech/cake_backup.git" - source: git - version: "1.0.0+1" - characters: - dependency: transitive - description: - name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 - url: "https://pub.dev" - source: hosted - version: "1.4.0" - checked_yaml: - dependency: transitive - description: - name: checked_yaml - sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff - url: "https://pub.dev" - source: hosted - version: "2.0.3" - clock: - dependency: transitive - description: - name: clock - sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b - url: "https://pub.dev" - source: hosted - version: "1.1.2" - code_builder: - dependency: transitive - description: - name: code_builder - sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e" - url: "https://pub.dev" - source: hosted - version: "4.10.1" - collection: - dependency: transitive - description: - name: collection - sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" - url: "https://pub.dev" - source: hosted - version: "1.19.1" - convert: - dependency: transitive - description: - name: convert - sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 - url: "https://pub.dev" - source: hosted - version: "3.1.2" - crypto: - dependency: transitive - description: - name: crypto - sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" - url: "https://pub.dev" - source: hosted - version: "3.0.6" - cryptography: - dependency: transitive - description: - name: cryptography - sha256: d146b76d33d94548cf035233fbc2f4338c1242fa119013bead807d033fc4ae05 - url: "https://pub.dev" - source: hosted - version: "2.7.0" - cupertino_icons: - dependency: transitive - description: - name: cupertino_icons - sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 - url: "https://pub.dev" - source: hosted - version: "1.0.8" - cw_core: - dependency: "direct main" - description: - path: "../cw_core" - relative: true - source: path - version: "0.0.1" - dart_style: - dependency: transitive - description: - name: dart_style - sha256: "7306ab8a2359a48d22310ad823521d723acfed60ee1f7e37388e8986853b6820" - url: "https://pub.dev" - source: hosted - version: "2.3.8" - decimal: - dependency: "direct main" - description: - name: decimal - sha256: "24a261d5d5c87e86c7651c417a5dbdf8bcd7080dd592533910e8d0505a279f21" - url: "https://pub.dev" - source: hosted - version: "2.3.3" - encrypt: - dependency: transitive - description: - name: encrypt - sha256: "62d9aa4670cc2a8798bab89b39fc71b6dfbacf615de6cf5001fb39f7e4a996a2" - url: "https://pub.dev" - source: hosted - version: "5.0.3" - fake_async: - dependency: transitive - description: - name: fake_async - sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" - url: "https://pub.dev" - source: hosted - version: "1.3.3" - ffi: - dependency: "direct main" - description: - name: ffi - sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" - url: "https://pub.dev" - source: hosted - version: "2.1.3" - file: - dependency: transitive - description: - name: file - sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 - url: "https://pub.dev" - source: hosted - version: "7.0.1" - fixnum: - dependency: transitive - description: - name: fixnum - sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be - url: "https://pub.dev" - source: hosted - version: "1.1.1" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_mobx: - dependency: "direct main" - description: - name: flutter_mobx - sha256: ba5e93467866a2991259dc51cffd41ef45f695c667c2b8e7b087bf24118b50fe - url: "https://pub.dev" - source: hosted - version: "2.3.0" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - flutter_web_plugins: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - fluttertoast: - dependency: "direct main" - description: - name: fluttertoast - sha256: "25e51620424d92d3db3832464774a6143b5053f15e382d8ffbfd40b6e795dcf1" - url: "https://pub.dev" - source: hosted - version: "8.2.12" - frontend_server_client: - dependency: transitive - description: - name: frontend_server_client - sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 - url: "https://pub.dev" - source: hosted - version: "4.0.0" - glob: - dependency: transitive - description: - name: glob - sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de - url: "https://pub.dev" - source: hosted - version: "2.1.3" - graphs: - dependency: transitive - description: - name: graphs - sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" - url: "https://pub.dev" - source: hosted - version: "2.3.2" - hive: - dependency: transitive - description: - name: hive - sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941" - url: "https://pub.dev" - source: hosted - version: "2.2.3" - hive_generator: - dependency: "direct dev" - description: - name: hive_generator - sha256: "06cb8f58ace74de61f63500564931f9505368f45f98958bd7a6c35ba24159db4" - url: "https://pub.dev" - source: hosted - version: "2.0.1" - http: - dependency: "direct main" - description: - name: http - sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f - url: "https://pub.dev" - source: hosted - version: "1.3.0" - http_multi_server: - dependency: transitive - description: - name: http_multi_server - sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8 - url: "https://pub.dev" - source: hosted - version: "3.2.2" - http_parser: - dependency: transitive - description: - name: http_parser - sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" - url: "https://pub.dev" - source: hosted - version: "4.0.2" - intl: - dependency: "direct main" - description: - name: intl - sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf - url: "https://pub.dev" - source: hosted - version: "0.19.0" - io: - dependency: transitive - description: - name: io - sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b - url: "https://pub.dev" - source: hosted - version: "1.0.5" - js: - dependency: transitive - description: - name: js - sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 - url: "https://pub.dev" - source: hosted - version: "0.6.7" - json_annotation: - dependency: transitive - description: - name: json_annotation - sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" - url: "https://pub.dev" - source: hosted - version: "4.9.0" - json_bigint: - dependency: "direct main" - description: - name: json_bigint - sha256: "9e613e731847ab2154d67160682adf104cbd9863741ec2f7abfcf6e77c70592f" - url: "https://pub.dev" - source: hosted - version: "3.1.0" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" - url: "https://pub.dev" - source: hosted - version: "10.0.9" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 - url: "https://pub.dev" - source: hosted - version: "3.0.9" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" - url: "https://pub.dev" - source: hosted - version: "3.0.1" - logging: - dependency: transitive - description: - name: logging - sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 - url: "https://pub.dev" - source: hosted - version: "1.3.0" - macros: - dependency: transitive - description: - name: macros - sha256: "1d9e801cd66f7ea3663c45fc708450db1fa57f988142c64289142c9b7ee80656" - url: "https://pub.dev" - source: hosted - version: "0.1.3-main.0" - matcher: - dependency: transitive - description: - name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 - url: "https://pub.dev" - source: hosted - version: "0.12.17" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec - url: "https://pub.dev" - source: hosted - version: "0.11.1" - meta: - dependency: transitive - description: - name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c - url: "https://pub.dev" - source: hosted - version: "1.16.0" - mime: - dependency: transitive - description: - name: mime - sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" - url: "https://pub.dev" - source: hosted - version: "2.0.0" - mobx: - dependency: "direct main" - description: - name: mobx - sha256: bf1a90e5bcfd2851fc6984e20eef69557c65d9e4d0a88f5be4cf72c9819ce6b0 - url: "https://pub.dev" - source: hosted - version: "2.5.0" - mobx_codegen: - dependency: "direct dev" - description: - name: mobx_codegen - sha256: e0abbbc651a69550440f6b65c99ec222a1e2a4afd7baec8ba0f3088c7ca582a8 - url: "https://pub.dev" - source: hosted - version: "2.7.1" - monero: - dependency: "direct main" - description: - path: "impls/monero.dart" - ref: bc8d1a0b75b97156d71579581b4cdfe58c777ed2 - resolved-ref: bc8d1a0b75b97156d71579581b4cdfe58c777ed2 - url: "https://github.com/mrcyjanek/monero_c" - source: git - version: "0.0.0" - nested: - dependency: transitive - description: - name: nested - sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" - url: "https://pub.dev" - source: hosted - version: "1.0.0" - on_chain: - dependency: transitive - description: - path: "." - ref: "096865a8c6b89c260beadfec04f7e184c40a3273" - resolved-ref: "096865a8c6b89c260beadfec04f7e184c40a3273" - url: "https://github.com/cake-tech/on_chain.git" - source: git - version: "3.7.0" - package_config: - dependency: transitive - description: - name: package_config - sha256: "92d4488434b520a62570293fbd33bb556c7d49230791c1b4bbd973baf6d2dc67" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - path: - dependency: transitive - description: - name: path - sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" - url: "https://pub.dev" - source: hosted - version: "1.9.1" - path_provider: - dependency: "direct main" - description: - name: path_provider - sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" - url: "https://pub.dev" - source: hosted - version: "2.1.5" - path_provider_android: - dependency: transitive - description: - name: path_provider_android - sha256: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2" - url: "https://pub.dev" - source: hosted - version: "2.2.15" - path_provider_foundation: - dependency: transitive - description: - name: path_provider_foundation - sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - path_provider_linux: - dependency: transitive - description: - name: path_provider_linux - sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 - url: "https://pub.dev" - source: hosted - version: "2.2.1" - path_provider_platform_interface: - dependency: transitive - description: - name: path_provider_platform_interface - sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - path_provider_windows: - dependency: transitive - description: - name: path_provider_windows - sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 - url: "https://pub.dev" - source: hosted - version: "2.3.0" - petitparser: - dependency: transitive - description: - name: petitparser - sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 - url: "https://pub.dev" - source: hosted - version: "6.0.2" - platform: - dependency: transitive - description: - name: platform - sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" - url: "https://pub.dev" - source: hosted - version: "3.1.6" - plugin_platform_interface: - dependency: transitive - description: - name: plugin_platform_interface - sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" - url: "https://pub.dev" - source: hosted - version: "2.1.8" - pointycastle: - dependency: transitive - description: - name: pointycastle - sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe" - url: "https://pub.dev" - source: hosted - version: "3.9.1" - pool: - dependency: transitive - description: - name: pool - sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" - url: "https://pub.dev" - source: hosted - version: "1.5.1" - provider: - dependency: transitive - description: - name: provider - sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c - url: "https://pub.dev" - source: hosted - version: "6.1.2" - pub_semver: - dependency: transitive - description: - name: pub_semver - sha256: "7b3cfbf654f3edd0c6298ecd5be782ce997ddf0e00531b9464b55245185bbbbd" - url: "https://pub.dev" - source: hosted - version: "2.1.5" - pubspec_parse: - dependency: transitive - description: - name: pubspec_parse - sha256: "81876843eb50dc2e1e5b151792c9a985c5ed2536914115ed04e9c8528f6647b0" - url: "https://pub.dev" - source: hosted - version: "1.4.0" - rational: - dependency: transitive - description: - name: rational - sha256: cb808fb6f1a839e6fc5f7d8cb3b0a10e1db48b3be102de73938c627f0b636336 - url: "https://pub.dev" - source: hosted - version: "2.2.3" - shelf: - dependency: transitive - description: - name: shelf - sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 - url: "https://pub.dev" - source: hosted - version: "1.4.1" - shelf_web_socket: - dependency: transitive - description: - name: shelf_web_socket - sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67 - url: "https://pub.dev" - source: hosted - version: "2.0.1" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - socks5_proxy: - dependency: transitive - description: - path: "." - ref: "27ad7c2efae8d7460325c74b90f660085cbd0685" - resolved-ref: "27ad7c2efae8d7460325c74b90f660085cbd0685" - url: "https://github.com/LacticWhale/socks_dart" - source: git - version: "2.1.0" - socks_socket: - dependency: transitive - description: - path: "." - ref: e6232c53c1595469931ababa878759a067c02e94 - resolved-ref: e6232c53c1595469931ababa878759a067c02e94 - url: "https://github.com/sneurlax/socks_socket" - source: git - version: "1.1.1" - source_gen: - dependency: transitive - description: - name: source_gen - sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832" - url: "https://pub.dev" - source: hosted - version: "1.5.0" - source_helper: - dependency: transitive - description: - name: source_helper - sha256: "86d247119aedce8e63f4751bd9626fc9613255935558447569ad42f9f5b48b3c" - url: "https://pub.dev" - source: hosted - version: "1.3.5" - source_span: - dependency: transitive - description: - name: source_span - sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" - url: "https://pub.dev" - source: hosted - version: "1.10.1" - sqflite: - dependency: transitive - description: - name: sqflite - sha256: "2d7299468485dca85efeeadf5d38986909c5eb0cd71fd3db2c2f000e6c9454bb" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - sqflite_android: - dependency: transitive - description: - name: sqflite_android - sha256: "78f489aab276260cdd26676d2169446c7ecd3484bbd5fead4ca14f3ed4dd9ee3" - url: "https://pub.dev" - source: hosted - version: "2.4.0" - sqflite_common: - dependency: transitive - description: - name: sqflite_common - sha256: "761b9740ecbd4d3e66b8916d784e581861fd3c3553eda85e167bc49fdb68f709" - url: "https://pub.dev" - source: hosted - version: "2.5.4+6" - sqflite_common_ffi: - dependency: transitive - description: - name: sqflite_common_ffi - sha256: "883dd810b2b49e6e8c3b980df1829ef550a94e3f87deab5d864917d27ca6bf36" - url: "https://pub.dev" - source: hosted - version: "2.3.4+4" - sqflite_darwin: - dependency: transitive - description: - name: sqflite_darwin - sha256: "22adfd9a2c7d634041e96d6241e6e1c8138ca6817018afc5d443fef91dcefa9c" - url: "https://pub.dev" - source: hosted - version: "2.4.1+1" - sqflite_platform_interface: - dependency: transitive - description: - name: sqflite_platform_interface - sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920" - url: "https://pub.dev" - source: hosted - version: "2.4.0" - sqlite3: - dependency: transitive - description: - name: sqlite3 - sha256: f393d92c71bdcc118d6203d07c991b9be0f84b1a6f89dd4f7eed348131329924 - url: "https://pub.dev" - source: hosted - version: "2.9.0" - sqlite3_flutter_libs: - dependency: transitive - description: - name: sqlite3_flutter_libs - sha256: "69c80d812ef2500202ebd22002cbfc1b6565e9ff56b2f971e757fac5d42294df" - url: "https://pub.dev" - source: hosted - version: "0.5.40" - stack_trace: - dependency: transitive - description: - name: stack_trace - sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" - url: "https://pub.dev" - source: hosted - version: "1.12.1" - stream_channel: - dependency: transitive - description: - name: stream_channel - sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - stream_transform: - dependency: transitive - description: - name: stream_transform - sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 - url: "https://pub.dev" - source: hosted - version: "2.1.1" - string_scanner: - dependency: transitive - description: - name: string_scanner - sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" - url: "https://pub.dev" - source: hosted - version: "1.4.1" - synchronized: - dependency: transitive - description: - name: synchronized - sha256: "69fe30f3a8b04a0be0c15ae6490fc859a78ef4c43ae2dd5e8a623d45bfcf9225" - url: "https://pub.dev" - source: hosted - version: "3.3.0+3" - term_glyph: - dependency: transitive - description: - name: term_glyph - sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" - url: "https://pub.dev" - source: hosted - version: "1.2.2" - test_api: - dependency: transitive - description: - name: test_api - sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd - url: "https://pub.dev" - source: hosted - version: "0.7.4" - timing: - dependency: transitive - description: - name: timing - sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" - url: "https://pub.dev" - source: hosted - version: "1.0.2" - torch_dart: - dependency: transitive - description: - path: "../scripts/torch_dart" - relative: true - source: path - version: "0.0.1" - tuple: - dependency: transitive - description: - name: tuple - sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151 - url: "https://pub.dev" - source: hosted - version: "2.0.2" - typed_data: - dependency: transitive - description: - name: typed_data - sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 - url: "https://pub.dev" - source: hosted - version: "1.4.0" - unorm_dart: - dependency: transitive - description: - name: unorm_dart - sha256: "23d8bf65605401a6a32cff99435fed66ef3dab3ddcad3454059165df46496a3b" - url: "https://pub.dev" - source: hosted - version: "0.3.0" - vector_math: - dependency: transitive - description: - name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 - url: "https://pub.dev" - source: hosted - version: "15.0.0" - watcher: - dependency: "direct overridden" - description: - name: watcher - sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104" - url: "https://pub.dev" - source: hosted - version: "1.1.1" - web: - dependency: transitive - description: - name: web - sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" - url: "https://pub.dev" - source: hosted - version: "1.1.1" - web_socket: - dependency: transitive - description: - name: web_socket - sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" - url: "https://pub.dev" - source: hosted - version: "0.1.6" - web_socket_channel: - dependency: transitive - description: - name: web_socket_channel - sha256: "0b8e2457400d8a859b7b2030786835a28a8e80836ef64402abef392ff4f1d0e5" - url: "https://pub.dev" - source: hosted - version: "3.0.2" - xdg_directories: - dependency: transitive - description: - name: xdg_directories - sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - yaml: - dependency: transitive - description: - name: yaml - sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce - url: "https://pub.dev" - source: hosted - version: "3.1.3" -sdks: - dart: ">=3.7.0-0 <4.0.0" - flutter: ">=3.24.0" diff --git a/cw_zano/pubspec.yaml b/cw_zano/pubspec.yaml deleted file mode 100644 index 6911dd4c..00000000 --- a/cw_zano/pubspec.yaml +++ /dev/null @@ -1,79 +0,0 @@ -name: cw_zano -description: A new flutter plugin project. -version: 0.0.1 -publish_to: none -homepage: https://github.com/Such-Software/hash-wallet - -environment: - sdk: ">=2.19.0 <3.0.0" - flutter: ">=1.20.0" - -dependencies: - flutter: - sdk: flutter - ffi: ^2.0.1 - http: ^1.1.0 - path_provider: ^2.0.11 - mobx: ^2.1.4 - flutter_mobx: ^2.0.6+1 - intl: any - decimal: ^2.3.3 - cw_core: - path: ../cw_core - json_bigint: ^3.0.0 - fluttertoast: ^8.2.12 - monero: - git: - url: https://github.com/mrcyjanek/monero_c - ref: bc8d1a0b75b97156d71579581b4cdfe58c777ed2 # monero_c hash - path: impls/monero.dart -dev_dependencies: - flutter_test: - sdk: flutter - build_runner: ^2.4.15 - mobx_codegen: ^2.1.1 - build_resolvers: ^2.4.4 - hive_generator: ^2.0.1 - -dependency_overrides: - watcher: ^1.1.0 - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter. -flutter: - # This section identifies this Flutter project as a plugin project. - # The 'pluginClass' and Android 'package' identifiers should not ordinarily - # be modified. They are used by the tooling to maintain consistency when - # adding or updating assets for this project. - # To add assets to your plugin package, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - # - # For details regarding assets in packages, see - # https://flutter.dev/assets-and-images/#from-packages - # - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware. - - # To add custom fonts to your plugin package, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts in packages, see - # https://flutter.dev/custom-fonts/#from-packages diff --git a/scripts/android/.gitignore b/scripts/android/.gitignore index 3a2b4c98..f7e94b7c 100644 --- a/scripts/android/.gitignore +++ b/scripts/android/.gitignore @@ -1,2 +1 @@ -mwebd -decred \ No newline at end of file +mwebd \ No newline at end of file diff --git a/scripts/android/build_all.sh b/scripts/android/build_all.sh index 4f369513..fd38abf0 100755 --- a/scripts/android/build_all.sh +++ b/scripts/android/build_all.sh @@ -12,6 +12,5 @@ $DIR/build_torch.sh case $APP_ANDROID_TYPE in "monero.com") $DIR/build_monero_all.sh ;; "cakewallet") $DIR/build_monero_all.sh - $DIR/build_mwebd.sh - $DIR/build_decred.sh ;; + $DIR/build_mwebd.sh ;; esac diff --git a/scripts/android/build_decred.sh b/scripts/android/build_decred.sh deleted file mode 100755 index 1ade0f8c..00000000 --- a/scripts/android/build_decred.sh +++ /dev/null @@ -1,85 +0,0 @@ -#!/bin/bash - -set -e -x -cd "$(dirname "$0")" -# . ./config.sh - -CW_DECRED_DIR=$(realpath ../..)/cw_decred -LIBWALLET_PATH="${PWD}/decred/libwallet" -LIBWALLET_URL="https://github.com/decred/libwallet.git" -LIBWALLET_VERSION="05f8d7374999400fe4d525eb365c39b77d307b14" - -if [[ -e $LIBWALLET_PATH ]]; then - rm -fr $LIBWALLET_PATH || true -fi -mkdir -p $LIBWALLET_PATH || true - -git clone $LIBWALLET_URL $LIBWALLET_PATH -cd $LIBWALLET_PATH -git checkout $LIBWALLET_VERSION - -if [[ "x$ANDROID_HOME" == "x" ]]; -then - echo "ANDROID_HOME is missing, please declare it before building (on macos it is usually $HOME/Library/Android/sdk)" - echo "echo > ~/.zprofile" - echo "echo 'export ANDROID_HOME=\"\$HOME/Library/Android/sdk\" > ~/.zprofile" - exit 1 -fi - -if [[ "x$ANDROID_NDK_VERSION" == "x" ]]; -then - echo "ANDROID_NDK_VERSION is missing, please declare it before building" - echo "You have these versions installed on your system currently:" - ls ${ANDROID_HOME}/ndk/ | cat | awk '{ print "- " $1 }' - echo "echo > ~/.zprofile" - echo "echo 'export ANDROID_NDK_VERSION=..... > ~/.zprofile" - exit 1 -fi - -export NDK_BIN_PATH="${ANDROID_HOME}/ndk/${ANDROID_NDK_VERSION}/toolchains/llvm/prebuilt/$(uname | tr '[:upper:]' '[:lower:]')-x86_64/bin" -export ANDROID_API_VERSION=21 -# export CPATH="$(clang -v 2>&1 | grep "Selected GCC installation" | rev | cut -d' ' -f1 | rev)/include" - -for arch in "aarch" "aarch64" "x86_64" -do - TRIPLET="" - TARGET="" - ARCH_ABI="" - - case $arch in - "aarch") - TRIPLET="armv7a-linux-androideabi" - TARGET="arm" - ARCH_ABI="armeabi-v7a";; - "aarch64") - TRIPLET="aarch64-linux-android" - TARGET="arm64" - ARCH_ABI="arm64-v8a";; - "x86_64") - TRIPLET="x86_64-linux-android" - TARGET="amd64" - ARCH_ABI="x86_64";; - *) - echo "Unknown arch: $arch" - exit 1;; - esac - - # PATH="${TOOLCHAIN_BASE_DIR}_${arch}/bin:${ORIGINAL_PATH}" - if [[ -e ./build ]]; then - rm -fr ./build - fi - - export CGO_LDFLAGS="-O2 -g -s -w -Wl,-z,max-page-size=16384" - CLANG_PATH="${NDK_BIN_PATH}/${TRIPLET}${ANDROID_API_VERSION}-clang" - CGO_ENABLED=1 GOOS=android GOARCH=${TARGET} CC=${CLANG_PATH} CXX=${CLANG_PATH}++ \ - go build -v -buildmode=c-shared -o ./build/${TRIPLET}-libdcrwallet.so ./cgo - - DEST_LIB_DIR=${CW_DECRED_DIR}/android/libs/${ARCH_ABI} - mkdir -p $DEST_LIB_DIR - cp ${LIBWALLET_PATH}/build/${TRIPLET}-libdcrwallet.so $DEST_LIB_DIR/libdcrwallet.so -done - -HEADER_DIR=$CW_DECRED_DIR/lib/api -cp ${LIBWALLET_PATH}/build/${TRIPLET}-libdcrwallet.h $HEADER_DIR/libdcrwallet.h -cd $CW_DECRED_DIR -dart run ffigen diff --git a/scripts/android/copy_monero_deps.sh b/scripts/android/copy_monero_deps.sh index ab1a9afc..6fffb08b 100755 --- a/scripts/android/copy_monero_deps.sh +++ b/scripts/android/copy_monero_deps.sh @@ -5,7 +5,6 @@ CW_DIR=${WORKDIR}/hash_wallet CW_EXRTERNAL_DIR=${CW_DIR}/cw_shared_external/ios/External/android CW_HAVEN_EXTERNAL_DIR=${CW_DIR}/cw_haven/ios/External/android CW_MONERO_EXTERNAL_DIR=${CW_DIR}/cw_monero/ios/External/android -CW_ZANO_EXTERNAL_DIR=${CW_DIR}/cw_zano/ios/External/android for arch in "aarch" "aarch64" "i686" "x86_64" do @@ -41,6 +40,5 @@ done mkdir -p ${CW_HAVEN_EXTERNAL_DIR}/include mkdir -p ${CW_MONERO_EXTERNAL_DIR}/include -mkdir -p ${CW_ZANO_EXTERNAL_DIR}/include cp $CW_EXRTERNAL_DIR/x86/include/haven/wallet2_api.h ${CW_HAVEN_EXTERNAL_DIR}/include diff --git a/scripts/android/docker/Dockerfile.decred b/scripts/android/docker/Dockerfile.decred deleted file mode 100644 index 5eb6fd32..00000000 --- a/scripts/android/docker/Dockerfile.decred +++ /dev/null @@ -1,17 +0,0 @@ -ARG BASE_IMAGE -ARG TORCH_IMAGE - -FROM ${TORCH_IMAGE} AS torch_source - -FROM --platform=linux/amd64 ${BASE_IMAGE} AS build - -RUN mkdir -p /w/scripts/android -RUN mkdir -p /w/cw_decred/lib/api -COPY --from=torch_source /w/scripts/torch_dart /w/scripts/torch_dart -COPY cw_core/pubspec.yaml /w/cw_core/pubspec.yaml -COPY cw_decred/pubspec.yaml /w/cw_decred/pubspec.yaml -COPY scripts/android/build_decred.sh /w/scripts/android/build_decred.sh -RUN /w/scripts/android/build_decred.sh - -FROM --platform=linux/amd64 alpine -COPY --from=build /w /w diff --git a/scripts/android/docker/Dockerfile.final b/scripts/android/docker/Dockerfile.final index d9f130f9..13337aca 100644 --- a/scripts/android/docker/Dockerfile.final +++ b/scripts/android/docker/Dockerfile.final @@ -3,14 +3,12 @@ ARG TORCH_IMAGE ARG REOWN_IMAGE ARG BITBOX_IMAGE ARG MONERO_IMAGE -ARG DECRED_IMAGE ARG MWEBD_IMAGE FROM ${TORCH_IMAGE} AS torch_src FROM ${REOWN_IMAGE} AS reown_src FROM ${BITBOX_IMAGE} AS bitbox_src FROM ${MONERO_IMAGE} AS monero_src -FROM ${DECRED_IMAGE} AS decred_src FROM ${MWEBD_IMAGE} AS mwebd_src FROM --platform=linux/amd64 alpine @@ -19,5 +17,4 @@ COPY --from=torch_src /w /w.top COPY --from=reown_src /w /w.top COPY --from=bitbox_src /w /w.top COPY --from=monero_src /w /w.top -COPY --from=decred_src /w /w.top COPY --from=mwebd_src /w /w.top diff --git a/scripts/android/docker/build.sh b/scripts/android/docker/build.sh index e6cb1d37..8e09a497 100755 --- a/scripts/android/docker/build.sh +++ b/scripts/android/docker/build.sh @@ -56,8 +56,7 @@ reown_ver=$(tinysha $SCRIPT_DIR/Dockerfile.reown $REPO_ROOT/scripts/prepare_reow bitbox_ver=$(tinysha $SCRIPT_DIR/Dockerfile.bitbox $REPO_ROOT/scripts/build_bitbox_flutter.sh) monero_ver=$(tinysha $SCRIPT_DIR/Dockerfile.monero $REPO_ROOT/scripts/prepare_moneroc.sh $REPO_ROOT/scripts/android/build_monero_all.sh) mwebd_ver=$(tinysha $SCRIPT_DIR/Dockerfile.mwebd $(find $REPO_ROOT/cw_mweb/go -type f)) -decred_ver=$(tinysha $SCRIPT_DIR/Dockerfile.torch $SCRIPT_DIR/Dockerfile.decred $REPO_ROOT/scripts/android/build_decred.sh) -echo $base_ver $torch_ver $reown_ver $bitbox_ver $monero_ver $mwebd_ver $decred_ver > /tmp/docker_build_versions +echo $base_ver $torch_ver $reown_ver $bitbox_ver $monero_ver $mwebd_ver > /tmp/docker_build_versions final_ver=$(tinysha /tmp/docker_build_versions) docker create --name temp_extract $(img final $final_ver) \ @@ -85,17 +84,12 @@ build monero "$monero_ver" --build-arg BASE_IMAGE="$(img base "$base_ver")" build torch "$torch_ver" \ --build-arg BASE_IMAGE="$(img base "$base_ver")" -build decred "$decred_ver" \ - --build-arg BASE_IMAGE="$(img base "$base_ver")" \ - --build-arg TORCH_IMAGE="$(img torch "$torch_ver")" - build final $final_ver \ --build-arg BASE_IMAGE="$(img base $base_ver)" \ --build-arg TORCH_IMAGE="$(img torch $torch_ver)" \ --build-arg REOWN_IMAGE="$(img reown $reown_ver)" \ --build-arg BITBOX_IMAGE="$(img bitbox $bitbox_ver)" \ --build-arg MONERO_IMAGE="$(img monero $monero_ver)" \ - --build-arg DECRED_IMAGE="$(img decred $decred_ver)" \ --build-arg MWEBD_IMAGE="$(img mwebd $mwebd_ver)" echo "done: $(img final $final_ver)" diff --git a/scripts/ios/build_all.sh b/scripts/ios/build_all.sh index f620413b..d2ea9da7 100755 --- a/scripts/ios/build_all.sh +++ b/scripts/ios/build_all.sh @@ -11,5 +11,5 @@ $DIR/build_torch.sh case $APP_IOS_TYPE in "monero.com") $DIR/build_monero_all.sh ;; - "cakewallet") $DIR/build_monero_all.sh && $DIR/build_mwebd.sh && $DIR/build_decred.sh ;; + "cakewallet") $DIR/build_monero_all.sh && $DIR/build_mwebd.sh ;; esac diff --git a/scripts/ios/build_decred.sh b/scripts/ios/build_decred.sh deleted file mode 100755 index 37384f4e..00000000 --- a/scripts/ios/build_decred.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/bash -set -e -. ./config.sh -LIBWALLET_PATH="${EXTERNAL_IOS_SOURCE_DIR}/libwallet" -LIBWALLET_URL="https://github.com/decred/libwallet.git" -LIBWALLET_VERSION="05f8d7374999400fe4d525eb365c39b77d307b14" - -if [[ -e $LIBWALLET_PATH ]]; then - rm -fr $LIBWALLET_PATH -fi -mkdir -p $LIBWALLET_PATH -git clone $LIBWALLET_URL $LIBWALLET_PATH -cd $LIBWALLET_PATH -git checkout $LIBWALLET_VERSION - -SYSROOT=`xcrun --sdk iphoneos --show-sdk-path` -CLANG="clang -target arm64-apple-ios -isysroot ${SYSROOT}" -CLANGXX="clang++ -target arm64-apple-ios -isysroot ${SYSROOT}" - -if [[ -e ./build ]]; then - rm -fr ./build -fi -CGO_ENABLED=1 GOOS=ios GOARCH=arm64 CC=$CLANG CXX=$CLANGXX \ -go build -v -buildmode=c-archive -o ./build/libdcrwallet.a ./cgo || exit 1 - -CW_DECRED_DIR=${CW_ROOT}/cw_decred -HEADER_DIR=$CW_DECRED_DIR/lib/api -mv ${LIBWALLET_PATH}/build/libdcrwallet.h $HEADER_DIR - -DEST_LIB_DIR=${CW_DECRED_DIR}/ios/External/lib -mkdir -p $DEST_LIB_DIR -mv ${LIBWALLET_PATH}/build/libdcrwallet.a $DEST_LIB_DIR - -cd $CW_DECRED_DIR -dart run ffigen diff --git a/scripts/ios/build_zano.sh b/scripts/ios/build_zano.sh deleted file mode 100755 index d37ed226..00000000 --- a/scripts/ios/build_zano.sh +++ /dev/null @@ -1,106 +0,0 @@ -#!/bin/sh - -. ./config.sh - -ZANO_URL="https://github.com/hyle-team/zano.git" -ZANO_DIR_PATH="${EXTERNAL_IOS_SOURCE_DIR}/zano" -ZANO_VERSION=fde28efdc5d7efe8741dcb0e62ea0aebc805a373 - - -IOS_TOOLCHAIN_DIR_PATH="${EXTERNAL_IOS_SOURCE_DIR}/ios_toolchain" -IOS_TOOLCHAIN_URL="https://github.com/leetal/ios-cmake.git" -IOS_TOOLCHAIN_VERSION=06465b27698424cf4a04a5ca4904d50a3c966c45 - -export NO_DEFAULT_PATH - -BUILD_TYPE=release -PREFIX=${EXTERNAL_IOS_DIR} -DEST_LIB_DIR=${EXTERNAL_IOS_LIB_DIR}/zano -DEST_INCLUDE_DIR=${EXTERNAL_IOS_INCLUDE_DIR}/zano - -ZANO_MOBILE_IOS_BUILD_FOLDER_ARM64="${ZANO_DIR_PATH}/build" -ZANO_MOBILE_IOS_INSTALL_FOLDER_ARM64="${ZANO_DIR_PATH}/install" - -echo "ZANO_URL: $ZANO_URL" -echo "IOS_TOOLCHAIN_DIR_PATH: $IOS_TOOLCHAIN_DIR_PATH" -echo "ZANO_MOBILE_IOS_BUILD_FOLDER_ARM64: $ZANO_MOBILE_IOS_BUILD_FOLDER_ARM64" -echo "ZANO_MOBILE_IOS_INSTALL_FOLDER_ARM64: $ZANO_MOBILE_IOS_INSTALL_FOLDER_ARM64" -echo "PREFIX: $PREFIX" -echo "DEST_LIB_DIR: $DEST_LIB_DIR" -echo "DEST_INCLUDE_DIR: $DEST_INCLUDE_DIR" -echo "ZANO_DIR_PATH: $ZANO_DIR_PATH" - -echo "Cloning ios_toolchain from - $IOS_TOOLCHAIN_URL to - $IOS_TOOLCHAIN_DIR_PATH" -git clone $IOS_TOOLCHAIN_URL $IOS_TOOLCHAIN_DIR_PATH -cd $IOS_TOOLCHAIN_DIR_PATH -git checkout $IOS_TOOLCHAIN_VERSION -git submodule update --init --force -cd .. - -echo "Cloning zano from - $ZANO_URL to - $ZANO_DIR_PATH" -git clone $ZANO_URL $ZANO_DIR_PATH -cd $ZANO_DIR_PATH -git fetch origin -if [ $? -ne 0 ]; then - echo "Failed to perform command" - exit 1 -fi -git checkout $ZANO_VERSION -if [ $? -ne 0 ]; then - echo "Failed to perform command" - exit 1 -fi -git submodule update --init --force -if [ $? -ne 0 ]; then - echo "Failed to perform command" - exit 1 -fi -mkdir -p build -cd .. - - -export CMAKE_INCLUDE_PATH="${PREFIX}/include" -export CMAKE_LIBRARY_PATH="${PREFIX}/lib" - - -rm -rf ${ZANO_MOBILE_IOS_BUILD_FOLDER_ARM64} > /dev/null -rm -rf ${ZANO_MOBILE_IOS_INSTALL_FOLDER_ARM64} > /dev/null - -echo "CMAKE_INCLUDE_PATH: $CMAKE_INCLUDE_PATH" -echo "CMAKE_LIBRARY_PATH: $CMAKE_LIBRARY_PATH" -echo "ROOT_DIR: $ROOT_DIR" - - -cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE \ - -DCMAKE_TOOLCHAIN_FILE="${IOS_TOOLCHAIN_DIR_PATH}/ios.toolchain.cmake" \ - -DPLATFORM=OS64 \ - -S"${ZANO_DIR_PATH}" \ - -B"${ZANO_MOBILE_IOS_BUILD_FOLDER_ARM64}" \ - -GXcode \ - -DCAKEWALLET=TRUE \ - -DSKIP_BOOST_FATLIB_LIB=TRUE \ - -DCMAKE_SYSTEM_NAME=iOS \ - -DCMAKE_INSTALL_PREFIX="${ZANO_MOBILE_IOS_INSTALL_FOLDER_ARM64}" \ - -DCMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH=NO \ - -DCMAKE_CXX_FLAGS="-Wno-enum-constexpr-conversion" \ - -DDISABLE_TOR=TRUE - -# -DCMAKE_OSX_ARCHITECTURES="arm64" -# -DCMAKE_IOS_INSTALL_COMBINED=YES - -if [ $? -ne 0 ]; then - echo "Failed to perform command" - exit 1 -fi - -cmake --build "${ZANO_MOBILE_IOS_BUILD_FOLDER_ARM64}" --config $BUILD_TYPE --target install -- -j 4 -if [ $? -ne 0 ]; then - echo "Failed to perform command" - exit 1 -fi - -mkdir -p $DEST_LIB_DIR -mkdir -p $DEST_INCLUDE_DIR - -cp ${ZANO_MOBILE_IOS_INSTALL_FOLDER_ARM64}/lib/* $DEST_LIB_DIR -cp ${ZANO_DIR_PATH}/src/wallet/plain_wallet_api.h $DEST_INCLUDE_DIR diff --git a/scripts/ios/build_zano_all.sh b/scripts/ios/build_zano_all.sh deleted file mode 100755 index 2e5ef81d..00000000 --- a/scripts/ios/build_zano_all.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -. ./config.sh -./install_missing_headers.sh -./build_openssl.sh -./build_boost.sh -./build_zano.sh diff --git a/scripts/ios/gen_framework.sh b/scripts/ios/gen_framework.sh index fda1e197..3442f8dd 100755 --- a/scripts/ios/gen_framework.sh +++ b/scripts/ios/gen_framework.sh @@ -132,8 +132,8 @@ create_xcframework() { echo "Created XCFramework: ${xcframework_output}" } -wallets=("monero" "wownero" "zano") -framework_names=("MoneroWallet" "WowneroWallet" "ZanoWallet") +wallets=("monero" "wownero") +framework_names=("MoneroWallet" "WowneroWallet") for i in "${!wallets[@]}"; do wallet="${wallets[$i]}" diff --git a/scripts/ios/setup.sh b/scripts/ios/setup.sh index b17b3718..8fb35c36 100755 --- a/scripts/ios/setup.sh +++ b/scripts/ios/setup.sh @@ -13,21 +13,16 @@ fi libtool -static -o libboost.a ./libboost_*.a libtool -static -o libhaven.a ./haven/*.a libtool -static -o libmonero.a ./monero/*.a -libtool -static -o libzano.a ./zano/*.a CW_HAVEN_EXTERNAL_LIB=../../../../../cw_haven/ios/External/ios/lib CW_HAVEN_EXTERNAL_INCLUDE=../../../../../cw_haven/ios/External/ios/include CW_MONERO_EXTERNAL_LIB=../../../../../cw_monero/ios/External/ios/lib CW_MONERO_EXTERNAL_INCLUDE=../../../../../cw_monero/ios/External/ios/include -CW_ZANO_EXTERNAL_LIB=../../../../../cw_zano/ios/External/ios/lib -CW_ZANO_EXTERNAL_INCLUDE=../../../../../cw_zano/ios/External/ios/include mkdir -p $CW_HAVEN_EXTERNAL_INCLUDE mkdir -p $CW_MONERO_EXTERNAL_INCLUDE -mkdir -p $CW_ZANO_EXTERNAL_INCLUDE mkdir -p $CW_HAVEN_EXTERNAL_LIB mkdir -p $CW_MONERO_EXTERNAL_LIB -mkdir -p $CW_ZANO_EXTERNAL_LIB ln ./libboost.a ${CW_HAVEN_EXTERNAL_LIB}/libboost.a ln ./libcrypto.a ${CW_HAVEN_EXTERNAL_LIB}/libcrypto.a @@ -44,8 +39,3 @@ ln ./libunbound.a ${CW_MONERO_EXTERNAL_LIB}/libunbound.a cp ./libmonero.a $CW_MONERO_EXTERNAL_LIB cp ../include/monero/* $CW_MONERO_EXTERNAL_INCLUDE -ln ./libboost.a ${CW_ZANO_EXTERNAL_LIB}/libboost.a -ln ./libcrypto.a ${CW_ZANO_EXTERNAL_LIB}/libcrypto.a -ln ./libssl.a ${CW_ZANO_EXTERNAL_LIB}/libssl.a -cp ./libzano.a $CW_ZANO_EXTERNAL_LIB -cp ../include/zano/* $CW_ZANO_EXTERNAL_INCLUDE diff --git a/scripts/macos/build_all.sh b/scripts/macos/build_all.sh index 4cd710fc..67a2189a 100755 --- a/scripts/macos/build_all.sh +++ b/scripts/macos/build_all.sh @@ -2,4 +2,4 @@ ./build_torch.sh -./build_monero_all.sh universal && ./build_decred.sh +./build_monero_all.sh universal diff --git a/scripts/macos/build_decred.sh b/scripts/macos/build_decred.sh deleted file mode 100755 index b1bbfbc4..00000000 --- a/scripts/macos/build_decred.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/sh - -. ./config.sh - -LIBWALLET_PATH="${EXTERNAL_MACOS_SOURCE_DIR}/libwallet" -LIBWALLET_URL="https://github.com/decred/libwallet.git" -LIBWALLET_VERSION="05f8d7374999400fe4d525eb365c39b77d307b14" - -echo "======================= DECRED LIBWALLET =========================" - -echo "Cloning DECRED LIBWALLET from - $LIBWALLET_URL" -if [ -e $LIBWALLET_PATH ]; then - rm -fr $LIBWALLET_PATH -fi -mkdir -p $LIBWALLET_PATH -git clone $LIBWALLET_URL $LIBWALLET_PATH -cd $LIBWALLET_PATH -git checkout $LIBWALLET_VERSION - -if [ -e ./build ]; then - rm -fr ./build -fi -go build -buildmode=c-archive -o ./build/libdcrwallet.a ./cgo - -CW_DECRED_DIR=${CW_ROOT}/cw_decred -HEADER_DIR=$CW_DECRED_DIR/lib/api -mv ${LIBWALLET_PATH}/build/libdcrwallet.h $HEADER_DIR - -DEST_LIB_DIR=${CW_DECRED_DIR}/macos/External/lib -mkdir -p $DEST_LIB_DIR -mv ${LIBWALLET_PATH}/build/libdcrwallet.a $DEST_LIB_DIR - -cd $CW_DECRED_DIR -dart run ffigen diff --git a/tool/configure.dart b/tool/configure.dart index 3b265b49..c0727642 100644 --- a/tool/configure.dart +++ b/tool/configure.dart @@ -4,14 +4,9 @@ const bitcoinOutputPath = 'lib/bitcoin/bitcoin.dart'; const moneroOutputPath = 'lib/monero/monero.dart'; const bitcoinCashOutputPath = 'lib/bitcoin_cash/bitcoin_cash.dart'; const nanoOutputPath = 'lib/nano/nano.dart'; -const solanaOutputPath = 'lib/solana/solana.dart'; -const tronOutputPath = 'lib/tron/tron.dart'; const wowneroOutputPath = 'lib/wownero/wownero.dart'; -const zanoOutputPath = 'lib/zano/zano.dart'; -const decredOutputPath = 'lib/decred/decred.dart'; const dogecoinOutputPath = 'lib/dogecoin/dogecoin.dart'; const evmOutputPath = 'lib/evm/evm.dart'; -const zcashOutputPath = 'lib/zcash/zcash.dart'; const walletTypesPath = 'lib/wallet_types.g.dart'; const secureStoragePath = 'lib/core/secure_storage.dart'; const pubspecDefaultPath = 'pubspec_default.yaml'; @@ -26,16 +21,11 @@ Future main(List args) async { final hasNano = args.contains('${prefix}nano'); final hasBanano = args.contains('${prefix}banano'); final hasPolygon = args.contains('${prefix}polygon'); - final hasSolana = args.contains('${prefix}solana'); - final hasTron = args.contains('${prefix}tron'); final hasWownero = args.contains('${prefix}wownero'); - final hasZano = args.contains('${prefix}zano'); - final hasDecred = args.contains('${prefix}decred'); final hasDogecoin = args.contains('${prefix}dogecoin'); final hasBase = args.contains('${prefix}base'); final hasArbitrum = args.contains('${prefix}arbitrum'); final hasBsc = args.contains('${prefix}bsc'); - final hasZcash = args.contains('${prefix}zcash'); final hasEVM = hasEthereum || hasPolygon || hasBase || hasArbitrum || hasBsc; final excludeFlutterSecureStorage = args.contains('${prefix}excludeFlutterSecureStorage'); @@ -43,15 +33,10 @@ Future main(List args) async { await generateMonero(hasMonero); await generateBitcoinCash(hasBitcoinCash); await generateNano(hasNano); - await generateSolana(hasSolana); - await generateTron(hasTron); await generateWownero(hasWownero); - await generateZano(hasZano); // await generateBanano(hasEthereum); - await generateDecred(hasDecred); await generateDogecoin(hasDogecoin); await generateEVM(hasEVM); - await generateZcash(hasZcash); await generatePubspec( hasMonero: hasMonero, @@ -62,16 +47,11 @@ Future main(List args) async { hasBitcoinCash: hasBitcoinCash, hasFlutterSecureStorage: !excludeFlutterSecureStorage, hasPolygon: hasPolygon, - hasSolana: hasSolana, - hasTron: hasTron, hasWownero: hasWownero, - hasZano: hasZano, - hasDecred: hasDecred, hasDogecoin: hasDogecoin, hasBase: hasBase, hasArbitrum: hasArbitrum, hasBsc: hasBsc, - hasZcash: hasZcash, ); await generateWalletTypes( hasMonero: hasMonero, @@ -81,16 +61,11 @@ Future main(List args) async { hasBanano: hasBanano, hasBitcoinCash: hasBitcoinCash, hasPolygon: hasPolygon, - hasSolana: hasSolana, - hasTron: hasTron, hasWownero: hasWownero, - hasZano: hasZano, - hasDecred: hasDecred, hasDogecoin: hasDogecoin, hasBase: hasBase, hasArbitrum: hasArbitrum, hasBsc: hasBsc, - hasZcash: hasZcash, ); await injectSecureStorage(!excludeFlutterSecureStorage); } @@ -917,385 +892,6 @@ abstract class NanoUtil { await outputFile.writeAsString(output); } -Future generateSolana(bool hasImplementation) async { - final outputFile = File(solanaOutputPath); - const solanaCommonHeaders = """ -import 'package:hash_wallet/view_model/send/output.dart'; -import 'package:hash_wallet/exchange/provider/jupiter_exchange_provider.dart'; -import 'package:cw_core/crypto_currency.dart'; -import 'package:cw_core/output_info.dart'; -import 'package:cw_core/pending_transaction.dart'; -import 'package:cw_core/transaction_info.dart'; -import 'package:cw_core/wallet_base.dart'; -import 'package:cw_core/wallet_credentials.dart'; -import 'package:cw_core/wallet_info.dart'; -import 'package:cw_core/wallet_service.dart'; -import 'package:cw_core/spl_token.dart'; - -"""; - const solanaCWHeaders = """ -import 'package:cw_solana/solana_wallet.dart'; -import 'package:cw_solana/solana_mnemonics.dart'; -import 'package:cw_solana/solana_wallet_service.dart'; -import 'package:cw_solana/solana_transaction_info.dart'; -import 'package:cw_solana/pending_solana_transaction.dart'; -import 'package:cw_solana/solana_transaction_credentials.dart'; -import 'package:cw_solana/solana_wallet_creation_credentials.dart'; -import 'package:cw_solana/default_spl_tokens.dart'; -import 'package:hash_wallet/core/fiat_conversion_service.dart'; -import 'package:hash_wallet/di.dart'; -import 'package:hash_wallet/entities/fiat_api_mode.dart'; -import 'package:hash_wallet/entities/fiat_currency.dart'; -import 'package:hash_wallet/store/settings_store.dart'; - -import 'dart:convert'; -import 'dart:typed_data'; -import 'package:on_chain/solana/solana.dart' hide Store; -"""; - const solanaCwPart = "part 'cw_solana.dart';"; - const solanaContent = """ -abstract class Solana { - List getSolanaWordList(String language); - WalletService createSolanaWalletService(bool isDirect); - WalletCredentials createSolanaNewWalletCredentials( - {required String name, WalletInfo? walletInfo, String? password, String? mnemonic, String? passphrase}); - WalletCredentials createSolanaRestoreWalletFromSeedCredentials( - {required String name, required String mnemonic, required String password, String? passphrase}); - WalletCredentials createSolanaRestoreWalletFromPrivateKey( - {required String name, required String privateKey, required String password}); - - String getAddress(WalletBase wallet); - String getPrivateKey(WalletBase wallet); - String getPublicKey(WalletBase wallet); - - Object createSolanaTransactionCredentials( - List outputs, { - required CryptoCurrency currency, - }); - - Object createSolanaTransactionCredentialsRaw( - List outputs, { - required CryptoCurrency currency, - }); - List getSPLTokenCurrencies(WalletBase wallet); - Future addSPLToken( - WalletBase wallet, - CryptoCurrency token, - String contractAddress, - ); - Future deleteSPLToken(WalletBase wallet, CryptoCurrency token); - Future getSPLToken(WalletBase wallet, String contractAddress); - - CryptoCurrency assetOfTransaction(WalletBase wallet, TransactionInfo transaction); - double getTransactionAmountRaw(TransactionInfo transactionInfo); - String getTokenAddress(CryptoCurrency asset); - List? getValidationLength(CryptoCurrency type); - double? getEstimateFees(WalletBase wallet); - List getDefaultSPLTokens(); - List getDefaultTokenContractAddresses(); - List getDefaultTokenSymbols(); - bool isTokenAlreadyAdded(WalletBase wallet, String contractAddress); - - // Jupiter swap transaction handling - // Signs and prepares a base64-encoded unsigned transaction for sending - Future signAndPrepareJupiterSwapTransaction( - WalletBase wallet, - String base64Transaction, - String requestId, - String destinationAddress, - double amount, - double fee, - ); - - // Fast transaction update after sending - // Polls for a specific transaction by signature with exponential backoff - // Falls back to full refresh if transaction is not found after max retries - Future pollForTransaction( - WalletBase wallet, - String signature, { - Duration initialDelay = const Duration(seconds: 1), - int maxRetries = 5, - }); - - // Updates balances for specific tokens by mint addresses - // Also updates native SOL balance - // If tokenMints is null or empty, updates all tokens (full refresh) - Future updateTokenBalances( - WalletBase wallet, { - List? tokenMints, - }); - - Future discoverAndAddWalletTokens(WalletBase wallet); -} - -class JupiterSwapFailedException implements Exception { - final String message; - final String signature; - final num? errorCode; - final String? errorMessage; - - JupiterSwapFailedException({ - required this.message, - required this.signature, - this.errorCode, - this.errorMessage, - }); - - @override - String toString() => message; -} - - """; - - const solanaEmptyDefinition = 'Solana? solana;\n'; - const solanaCWDefinition = 'Solana? solana = CWSolana();\n'; - - final output = '$solanaCommonHeaders\n' + - (hasImplementation ? '$solanaCWHeaders\n' : '\n') + - (hasImplementation ? '$solanaCwPart\n\n' : '\n') + - (hasImplementation ? solanaCWDefinition : solanaEmptyDefinition) + - '\n' + - solanaContent; - - if (outputFile.existsSync()) { - await outputFile.delete(); - } - - await outputFile.writeAsString(output); -} - -Future generateTron(bool hasImplementation) async { - final outputFile = File(tronOutputPath); - const tronCommonHeaders = """ -import 'package:hash_wallet/view_model/send/output.dart'; -import 'package:cw_core/crypto_currency.dart'; -import 'package:cw_core/output_info.dart'; -import 'package:cw_core/transaction_info.dart'; -import 'package:cw_core/wallet_base.dart'; -import 'package:cw_core/wallet_credentials.dart'; -import 'package:cw_core/wallet_info.dart'; -import 'package:cw_core/wallet_service.dart'; -import 'package:cw_core/tron_token.dart'; -import 'package:hive/hive.dart'; - -"""; - const tronCWHeaders = """ -import 'package:cw_evm/evm_chain_mnemonics.dart'; -import 'package:cw_tron/tron_transaction_credentials.dart'; -import 'package:cw_tron/tron_transaction_info.dart'; -import 'package:cw_tron/tron_wallet_creation_credentials.dart'; - -import 'package:cw_tron/tron_client.dart'; -import 'package:cw_tron/tron_wallet.dart'; -import 'package:cw_tron/tron_wallet_service.dart'; -import 'package:cw_tron/default_tron_tokens.dart'; - -"""; - const tronCwPart = "part 'cw_tron.dart';"; - const tronContent = """ -abstract class Tron { - List getTronWordList(String language); - WalletService createTronWalletService(bool isDirect); - WalletCredentials createTronNewWalletCredentials({required String name, WalletInfo? walletInfo, String? password, String? mnemonic, String? passphrase}); - WalletCredentials createTronRestoreWalletFromSeedCredentials({required String name, required String mnemonic, required String password, String? passphrase}); - WalletCredentials createTronRestoreWalletFromPrivateKey({required String name, required String privateKey, required String password}); - String getAddress(WalletBase wallet); - - Object createTronTransactionCredentials( - List outputs, { - required CryptoCurrency currency, - }); - - List getTronTokenCurrencies(WalletBase wallet); - Future addTronToken(WalletBase wallet, CryptoCurrency token, String contractAddress); - Future deleteTronToken(WalletBase wallet, CryptoCurrency token); - Future getTronToken(WalletBase wallet, String contractAddress); - - double getTransactionAmountRaw(TransactionInfo transactionInfo); - CryptoCurrency assetOfTransaction(WalletBase wallet, TransactionInfo transaction); - String getTokenAddress(CryptoCurrency asset); - String getTronBase58Address(String hexAddress, WalletBase wallet); - - String? getTronNativeEstimatedFee(WalletBase wallet); - String? getTronTRC20EstimatedFee(WalletBase wallet); - - void updateTronGridUsageState(WalletBase wallet, bool isEnabled); - List getDefaultTronTokens(); - List getDefaultTokenContractAddresses(); - List getDefaultTokenSymbols(); - bool isTokenAlreadyAdded(WalletBase wallet, String contractAddress); -} - """; - - const tronEmptyDefinition = 'Tron? tron;\n'; - const tronCWDefinition = 'Tron? tron = CWTron();\n'; - - final output = '$tronCommonHeaders\n' + - (hasImplementation ? '$tronCWHeaders\n' : '\n') + - (hasImplementation ? '$tronCwPart\n\n' : '\n') + - (hasImplementation ? tronCWDefinition : tronEmptyDefinition) + - '\n' + - tronContent; - - if (outputFile.existsSync()) { - await outputFile.delete(); - } - - await outputFile.writeAsString(output); -} - -Future generateZano(bool hasImplementation) async { - final outputFile = File(zanoOutputPath); - const zanoCommonHeaders = """ -import 'package:hash_wallet/utils/language_list.dart'; -import 'package:hash_wallet/view_model/send/output.dart'; -import 'package:collection/collection.dart'; -import 'package:cw_core/crypto_currency.dart'; -import 'package:cw_core/monero_transaction_priority.dart'; -import 'package:cw_core/output_info.dart'; -import 'package:cw_core/transaction_history.dart'; -import 'package:cw_core/transaction_info.dart'; -import 'package:cw_core/transaction_priority.dart'; -import 'package:cw_core/wallet_base.dart'; -import 'package:cw_core/wallet_credentials.dart'; -import 'package:cw_core/wallet_info.dart'; -import 'package:cw_core/wallet_service.dart'; -import 'package:cw_core/zano_asset.dart'; -import 'package:hive/hive.dart'; -"""; - const zanoCWHeaders = """ -import 'package:cw_zano/mnemonics/english.dart'; -import 'package:cw_zano/model/zano_transaction_credentials.dart'; -import 'package:cw_zano/model/zano_transaction_info.dart'; -import 'package:cw_zano/zano_formatter.dart'; -import 'package:cw_zano/zano_wallet.dart'; -import 'package:cw_zano/zano_wallet_service.dart'; -import 'package:cw_zano/zano_wallet_api.dart' as api; -import 'package:cw_zano/zano_utils.dart'; -"""; - const zanoCwPart = "part 'cw_zano.dart';"; - const zanoContent = """ -abstract class Zano { - TransactionPriority getDefaultTransactionPriority(); - TransactionPriority deserializeMoneroTransactionPriority({required int raw}); - List getTransactionPriorities(); - List getWordList(String language); - - WalletCredentials createZanoRestoreWalletFromSeedCredentials({required String name, required String password, required String passphrase, required int height, required String mnemonic}); - WalletCredentials createZanoNewWalletCredentials({required String name, required String? password, required String? passphrase}); - Map getKeys(Object wallet); - Object createZanoTransactionCredentials({required List outputs, required TransactionPriority priority, required CryptoCurrency currency}); - double formatterIntAmountToDouble({required int amount, required CryptoCurrency currency, required bool forFee}); - int formatterParseAmount({required String amount, required CryptoCurrency currency}); - WalletService createZanoWalletService(); - CryptoCurrency? assetOfTransaction(WalletBase wallet, TransactionInfo tx); - List getZanoAssets(WalletBase wallet); - String getZanoAssetAddress(CryptoCurrency asset); - Future changeZanoAssetAvailability(WalletBase wallet, CryptoCurrency token); - Future addZanoAssetById(WalletBase wallet, String assetId); - Future deleteZanoAsset(WalletBase wallet, CryptoCurrency token); - Future getZanoAsset(WalletBase wallet, String contractAddress); - String getAddress(WalletBase wallet); - bool validateAddress(String address); - Map> debugCallLength(); - bool isTokenAlreadyAdded(WalletBase wallet, String contractAddress); -} -"""; - const zanoEmptyDefinition = 'Zano? zano;\n'; - const zanoCWDefinition = 'Zano? zano = CWZano();\n'; - - final output = '$zanoCommonHeaders\n' + - (hasImplementation ? '$zanoCWHeaders\n' : '\n') + - (hasImplementation ? '$zanoCwPart\n\n' : '\n') + - (hasImplementation ? zanoCWDefinition : zanoEmptyDefinition) + - '\n' + - zanoContent; - - if (outputFile.existsSync()) { - await outputFile.delete(); - } - - await outputFile.writeAsString(output); -} - -Future generateDecred(bool hasImplementation) async { - final outputFile = File(decredOutputPath); - const decredCommonHeaders = """ -import 'package:cw_core/wallet_credentials.dart'; -import 'package:cw_core/address_info.dart'; -import 'package:cw_core/wallet_info.dart'; -import 'package:cw_core/transaction_priority.dart'; -import 'package:cw_core/output_info.dart'; -import 'package:cw_core/wallet_service.dart'; -import 'package:cw_core/unspent_transaction_output.dart'; -import 'package:cw_core/unspent_coins_info.dart'; -import 'package:hash_wallet/view_model/send/output.dart'; -import 'package:hive/hive.dart'; -"""; - const decredCWHeaders = """ -import 'package:cw_decred/transaction_priority.dart'; -import 'package:cw_decred/wallet.dart'; -import 'package:cw_decred/wallet_service.dart'; -import 'package:cw_decred/wallet_creation_credentials.dart'; -import 'package:cw_decred/amount_format.dart'; -import 'package:cw_decred/transaction_credentials.dart'; -import 'package:cw_decred/mnemonic.dart'; -"""; - const decredCwPart = "part 'cw_decred.dart';"; - const decredContent = """ - -abstract class Decred { - WalletCredentials createDecredNewWalletCredentials( - {required String name, WalletInfo? walletInfo}); - WalletCredentials createDecredRestoreWalletFromSeedCredentials( - {required String name, required String mnemonic, required String password}); - WalletCredentials createDecredRestoreWalletFromPubkeyCredentials( - {required String name, required String pubkey, required String password}); - WalletService createDecredWalletService(Box unspentCoinSource); - - List getTransactionPriorities(); - TransactionPriority getDecredTransactionPriorityMedium(); - TransactionPriority getDecredTransactionPrioritySlow(); - TransactionPriority deserializeDecredTransactionPriority(int raw); - - Object createDecredTransactionCredentials(List outputs, TransactionPriority priority); - - List getAddressInfos(Object wallet); - Future updateAddress(Object wallet, String address, String label); - Future generateNewAddress(Object wallet, String label); - - String formatterDecredAmountToString({required int amount}); - double formatterDecredAmountToDouble({required int amount}); - int formatterStringDoubleToDecredAmount(String amount); - - List getUnspents(Object wallet); - void updateUnspents(Object wallet); - - int heightByDate(DateTime date); - - List getDecredWordList(); - - String pubkey(Object wallet); -} -"""; - - const decredEmptyDefinition = 'Decred? decred;\n'; - const decredCWDefinition = 'Decred? decred = CWDecred();\n'; - - final output = '$decredCommonHeaders\n' + - (hasImplementation ? '$decredCWHeaders\n' : '\n') + - (hasImplementation ? '$decredCwPart\n\n' : '\n') + - (hasImplementation ? decredCWDefinition : decredEmptyDefinition) + - '\n' + - decredContent; - - if (outputFile.existsSync()) { - await outputFile.delete(); - } - - await outputFile.writeAsString(output); -} - Future generateDogecoin(bool hasImplementation) async { final outputFile = File(dogecoinOutputPath); const dogecoinCommonHeaders = """ @@ -1667,105 +1263,6 @@ class BridgeQuote { await outputFile.writeAsString(output); } -Future generateZcash(bool hasImplementation) async { - final outputFile = File(zcashOutputPath); - const zcashCommonHeaders = """ -import 'package:hash_wallet/view_model/send/output.dart'; -import 'package:cw_core/balance.dart'; -import 'package:cw_core/crypto_amount_format.dart'; -import 'package:cw_core/crypto_currency.dart'; -import 'package:cw_core/output_info.dart'; -import 'package:cw_core/transaction_history.dart'; -import 'package:cw_core/transaction_info.dart'; -import 'package:cw_core/transaction_priority.dart'; -import 'package:cw_core/monero_transaction_priority.dart'; -import 'package:cw_core/wallet_base.dart'; -import 'package:cw_core/wallet_credentials.dart'; -import 'package:cw_core/wallet_info.dart'; -import 'package:cw_core/wallet_service.dart'; -import 'package:cw_core/receive_page_option.dart'; - -"""; - const zcashCWHeaders = """ -import 'package:cw_zcash/cw_zcash.dart'; -import 'package:cw_zcash/src/zcash_wallet_addresses.dart'; - -"""; - const zcashCwPart = "part 'cw_zcash.dart';"; - const zcashContent = """ -abstract class Zcash { - List getZcashWordList(String language); - WalletService createZcashWalletService(bool isDirect); - WalletCredentials createZcashNewWalletCredentials( - {required String name, - WalletInfo? walletInfo, - String? password, - String? mnemonic, - required String? passphrase}); - WalletCredentials createZcashRestoreWalletFromSeedCredentials( - {required String name, - required String mnemonic, - required String password, - String? passphrase, - required int? height}); - WalletCredentials createZcashRestoreWalletFromPrivateKey( - {required String name, required String privateKey, required String password, required int height}); - String getAddress(WalletBase wallet); - String getPrivateKey(WalletBase wallet); - String getPublicKey(WalletBase wallet); - Map getKeys(Object wallet); - - Object createZcashTransactionCredentials( - List outputs, { - required CryptoCurrency currency, - int? feeRate, - }); - - Object createZcashTransactionCredentialsRaw( - List outputs, { - required CryptoCurrency currency, - required int feeRate, - }); - - int formatterZcashParseAmount(String amount); - double formatterZcashAmountToDouble({TransactionInfo? transaction, BigInt? amount}); - String formatterZcashAmountToString({required int amount}); - - List getAddressInfos(Object wallet); - - TransactionPriority getDefaultTransactionPriority(); - TransactionPriority getZcashTransactionPriorityAutomatic(); - TransactionPriority deserializeZcashTransactionPriority({required int raw}); - List getTransactionPriorities(); - ReceivePageOption getSelectedAddressType(Object wallet); - dynamic getZcashAddressType(ReceivePageOption option); - bool hasSelectedTransparentAddress(Object wallet); - Future setAddressType(Object wallet, dynamic option); - dynamic getOptionToType(ReceivePageOption option); - void unlockDatabase(String password); - Future getHeightByDate(DateTime date); - bool showMissingFundsCard(WalletBase wallet); - Future rescanInternalChange(WalletBase wallet); -} - """; - - const zcashEmptyDefinition = 'Zcash? zcash;\n'; - const zcashCWDefinition = 'Zcash? zcash = CWZcash();\n'; - - final output = '$zcashCommonHeaders\n' + - (hasImplementation ? '$zcashCWHeaders\n' : '\n') + - (hasImplementation ? '$zcashCwPart\n\n' : '\n') + - (hasImplementation ? zcashCWDefinition : zcashEmptyDefinition) + - '\n' + - zcashContent; - - if (outputFile.existsSync()) { - await outputFile.delete(); - } - - await outputFile.writeAsString(output); -} - Future generatePubspec({ required bool hasMonero, required bool hasBitcoin, @@ -1775,16 +1272,11 @@ Future generatePubspec({ required bool hasBitcoinCash, required bool hasFlutterSecureStorage, required bool hasPolygon, - required bool hasSolana, - required bool hasTron, required bool hasWownero, - required bool hasZano, - required bool hasDecred, required bool hasDogecoin, required bool hasBase, required bool hasArbitrum, required bool hasBsc, - required bool hasZcash, }) async { const cwCore = """ cw_core: @@ -1817,38 +1309,18 @@ Future generatePubspec({ cw_banano: path: ./cw_banano """; - const cwSolana = """ - cw_solana: - path: ./cw_solana - """; const cwEVM = """ cw_evm: path: ./cw_evm """; - const cwTron = """ - cw_tron: - path: ./cw_tron - """; const cwWownero = """ cw_wownero: path: ./cw_wownero """; - const cwZano = """ - cw_zano: - path: ./cw_zano - """; - const cwDecred = """ - cw_decred: - path: ./cw_decred - """; const cwDogecoin = """ cw_dogecoin: path: ./cw_dogecoin """; - const cwZcash = """ - cw_zcash: - path: ./cw_zcash - """; final inputFile = File(pubspecOutputPath); final inputText = await inputFile.readAsString(); @@ -1879,18 +1351,6 @@ Future generatePubspec({ output += '\n$cwBitcoinCash'; } - if (hasSolana) { - output += '\n$cwSolana'; - } - - if (hasTron) { - output += '\n$cwTron'; - } - - if (hasDecred) { - output += '\n$cwDecred'; - } - if (hasFlutterSecureStorage) { output += '\n$flutterSecureStorage\n'; } @@ -1903,18 +1363,10 @@ Future generatePubspec({ output += '\n$cwWownero'; } - if (hasZano) { - output += '\n$cwZano'; - } - if (hasDogecoin) { output += '\n$cwDogecoin'; } - if (hasZcash) { - output += '\n$cwZcash'; - } - final outputLines = output.split('\n'); inputLines.insertAll(dependenciesIndex + 1, outputLines); final outputContent = inputLines.join('\n'); @@ -1935,16 +1387,11 @@ Future generateWalletTypes({ required bool hasBanano, required bool hasBitcoinCash, required bool hasPolygon, - required bool hasSolana, - required bool hasTron, required bool hasWownero, - required bool hasZano, - required bool hasDecred, required bool hasDogecoin, required bool hasBase, required bool hasArbitrum, required bool hasBsc, - required bool hasZcash, }) async { final walletTypesFile = File(walletTypesPath); @@ -1977,18 +1424,6 @@ Future generateWalletTypes({ outputContent += '\tWalletType.bsc,\n'; } - if (hasSolana) { - outputContent += '\tWalletType.solana,\n'; - } - - if (hasZcash) { - outputContent += '\tWalletType.zcash,\n'; - } - - if (hasTron) { - outputContent += '\tWalletType.tron,\n'; - } - if (hasDogecoin) { outputContent += '\tWalletType.dogecoin,\n'; } @@ -2017,14 +1452,6 @@ Future generateWalletTypes({ outputContent += '\tWalletType.nano,\n'; } - if (hasDecred) { - outputContent += '\tWalletType.decred,\n'; - } - - if (hasZano) { - outputContent += '\tWalletType.zano,\n'; - } - if (hasBanano) { outputContent += '\tWalletType.banano,\n'; } diff --git a/tool/import_secrets_config.dart b/tool/import_secrets_config.dart index db038876..bc2ac620 100644 --- a/tool/import_secrets_config.dart +++ b/tool/import_secrets_config.dart @@ -8,12 +8,6 @@ const outputPath = 'lib/.secrets.g.dart'; const evmChainsConfigPath = 'tool/.evm-secrets-config.json'; const evmChainsOutputPath = 'cw_evm/lib/.secrets.g.dart'; -const solanaConfigPath = 'tool/.solana-secrets-config.json'; -const solanaOutputPath = 'cw_solana/lib/.secrets.g.dart'; - -const tronConfigPath = 'tool/.tron-secrets-config.json'; -const tronOutputPath = 'cw_tron/lib/.secrets.g.dart'; - const bitcoinConfigPath = 'tool/.bitcoin-secrets-config.json'; const bitcoinOutputPath = 'cw_bitcoin/lib/.secrets.g.dart'; @@ -33,17 +27,6 @@ Future importSecretsConfig() async { final evmChainsOutput = evmChainsInput.keys .fold('', (String acc, String val) => acc + generateConst(val, evmChainsInput)); - final solanaOutputFile = File(solanaOutputPath); - final solanaInput = - json.decode(File(solanaConfigPath).readAsStringSync()) as Map; - final solanaOutput = - solanaInput.keys.fold('', (String acc, String val) => acc + generateConst(val, solanaInput)); - - final tronOutputFile = File(tronOutputPath); - final tronInput = json.decode(File(tronConfigPath).readAsStringSync()) as Map; - final tronOutput = - tronInput.keys.fold('', (String acc, String val) => acc + generateConst(val, tronInput)); - final nanoOutputFile = File(nanoOutputPath); final nanoInput = json.decode(File(nanoConfigPath).readAsStringSync()) as Map; final nanoOutput = @@ -70,18 +53,6 @@ Future importSecretsConfig() async { await evmChainsOutputFile.writeAsString(evmChainsOutput); - if (solanaOutputFile.existsSync()) { - await solanaOutputFile.delete(); - } - - await solanaOutputFile.writeAsString(solanaOutput); - - if (tronOutputFile.existsSync()) { - await tronOutputFile.delete(); - } - - await tronOutputFile.writeAsString(tronOutput); - if (nanoOutputFile.existsSync()) { await nanoOutputFile.delete(); } -- 2.50.1 (Apple Git-155) From ef895994aee9b52aa5e7dc4884e3ef998fe658c2 Mon Sep 17 00:00:00 2001 From: jwinterm Date: Sun, 17 May 2026 08:22:08 -0400 Subject: [PATCH 7/8] Remove Wyre buy-provider integration (shut down 2023) Delete the WyreBuyProvider + WyreOrderProviderAdapter source files, strip imports and call sites from buy/order view models and the buy webview, force isBitcoinBuyEnabled = false in di.dart, and drop the three wyreSecretKey/wyreApiKey/wyreAccountId entries from tool/utils/secret_key.dart. BuyProviderDescription.wyre (raw: 0) is kept as a no-op legacy entry so any old Hive-persisted order with that raw value still deserializes without throwing. Don't wire it back to UI/services. --- lib/buy/buy_provider_description.dart | 2 + lib/buy/wyre/wyre_buy_provider.dart | 173 ------------------ lib/di.dart | 4 +- .../wyre_order_provider_adapter.dart | 23 --- lib/src/screens/buy/buy_webview_page.dart | 5 - lib/view_model/buy/buy_view_model.dart | 11 +- lib/view_model/order_details_view_model.dart | 5 +- tool/utils/secret_key.dart | 3 - 8 files changed, 5 insertions(+), 221 deletions(-) delete mode 100644 lib/buy/wyre/wyre_buy_provider.dart delete mode 100644 lib/order/order_provider_adapter/wyre_order_provider_adapter.dart diff --git a/lib/buy/buy_provider_description.dart b/lib/buy/buy_provider_description.dart index d395c9df..ad00bf1e 100644 --- a/lib/buy/buy_provider_description.dart +++ b/lib/buy/buy_provider_description.dart @@ -6,6 +6,8 @@ class BuyProviderDescription extends EnumerableItem with Serializable final String image; + // raw: 0 was Wyre, removed (provider shut down 2023). Kept the constant + // for legacy Hive deserialization; do not wire it back into UI/services. static const wyre = BuyProviderDescription(title: 'Wyre', raw: 0, image: ''); static const moonPay = BuyProviderDescription(title: 'MoonPay', raw: 1, image: ''); diff --git a/lib/buy/wyre/wyre_buy_provider.dart b/lib/buy/wyre/wyre_buy_provider.dart deleted file mode 100644 index 46d08964..00000000 --- a/lib/buy/wyre/wyre_buy_provider.dart +++ /dev/null @@ -1,173 +0,0 @@ -import 'dart:convert'; -import 'package:hash_wallet/buy/buy_exception.dart'; -import 'package:hash_wallet/order/order_source_description.dart'; -import 'package:hash_wallet/buy/pairs_utils.dart'; -import 'package:hash_wallet/entities/fiat_currency.dart'; -import 'package:cw_core/crypto_currency.dart'; -import 'package:cw_core/currency_for_wallet_type.dart'; -import 'package:cw_core/utils/proxy_wrapper.dart'; -import 'package:hash_wallet/buy/buy_amount.dart'; -import 'package:hash_wallet/buy/buy_provider.dart'; -import 'package:hash_wallet/buy/buy_provider_description.dart'; -import 'package:hash_wallet/order/order.dart'; -import 'package:cw_core/wallet_base.dart'; -import 'package:cw_core/wallet_type.dart'; -import 'package:hash_wallet/exchange/trade_state.dart'; -import 'package:hash_wallet/.secrets.g.dart' as secrets; - -class WyreBuyProvider extends BuyProvider { - WyreBuyProvider({required WalletBase wallet, bool isTestEnvironment = false}) - : baseApiUrl = isTestEnvironment ? _baseTestApiUrl : _baseProductApiUrl, - super( - wallet: wallet, - isTestEnvironment: isTestEnvironment, - hardwareWalletVM: null, - supportedCryptoList: supportedCryptoToFiatPairs( - notSupportedCrypto: _notSupportedCrypto, notSupportedFiat: _notSupportedFiat), - supportedFiatList: supportedFiatToCryptoPairs( - notSupportedFiat: _notSupportedFiat, notSupportedCrypto: _notSupportedCrypto)); - - 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; - - static const List _notSupportedCrypto = []; - static const List _notSupportedFiat = []; - - @override - String get title => 'Wyre'; - - @override - String get providerDescription => ''; - - @override - String get lightIcon => 'assets/images/robinhood_light.png'; - - @override - String get darkIcon => 'assets/images/robinhood_dark.png'; - - @override - bool get isAggregator => false; - - String get trackUrl => isTestEnvironment ? _trackTestUrl : _trackProductUrl; - - String baseApiUrl; - - Future requestUrl(String amount, String sourceCurrency) async { - final timestamp = DateTime.now().millisecondsSinceEpoch.toString(); - final url = baseApiUrl + _ordersSuffix + _reserveSuffix + _timeStampSuffix + timestamp; - final uri = Uri.parse(url); - final body = { - 'amount': amount, - 'sourceCurrency': sourceCurrency, - 'destCurrency': walletTypeToCryptoCurrency(wallet.type, chainId: wallet.chainId).title, - 'dest': walletTypeToString(wallet.type).toLowerCase() + ':' + wallet.walletAddresses.address, - 'referrerAccountId': _accountId, - 'lockFields': ['amount', 'sourceCurrency', 'destCurrency', 'dest'] - }; - final response = await ProxyWrapper().post( - clearnetUri: uri, - headers: { - 'Authorization': 'Bearer $_secretKey', - 'Content-Type': 'application/json', - 'cache-control': 'no-cache' - }, - body: json.encode(body), - ); - - if (response.statusCode != 200) { - throw BuyException(title: providerDescription, content: 'Url $url is not found!'); - } - - - final responseJSON = json.decode(response.body) as Map; - final urlFromResponse = responseJSON['url'] as String; - return urlFromResponse; - } - - Future calculateAmount(String amount, String sourceCurrency) async { - final quoteUrl = _baseProductApiUrl + _ordersSuffix + _quoteSuffix; - final body = { - 'amount': amount, - 'sourceCurrency': sourceCurrency, - 'destCurrency': walletTypeToCryptoCurrency(wallet.type, chainId: wallet.chainId).title, - 'dest': walletTypeToString(wallet.type).toLowerCase() + ':' + wallet.walletAddresses.address, - 'accountId': _accountId, - 'country': _countryCode - }; - final uri = Uri.parse(quoteUrl); - final response = await ProxyWrapper().post( - clearnetUri: uri, - headers: { - 'Authorization': 'Bearer $_secretKey', - 'Content-Type': 'application/json', - 'cache-control': 'no-cache' - }, - body: json.encode(body), - ); - - if (response.statusCode != 200) { - throw BuyException(title: providerDescription, content: 'Quote is not found!'); - } - - - final responseJSON = json.decode(response.body) as Map; - final sourceAmount = responseJSON['sourceAmount'] as double; - final destAmount = responseJSON['destAmount'] as double; - final achAmount = responseJSON['sourceAmountWithoutFees'] as double; - - return BuyAmount( - sourceAmount: sourceAmount, destAmount: destAmount, achSourceAmount: achAmount); - } - - Future findOrderById(String id) async { - final orderUrl = baseApiUrl + _ordersSuffix + '/$id'; - final orderUri = Uri.parse(orderUrl); - final orderResponse = await ProxyWrapper().get(clearnetUri: orderUri); - if (orderResponse.statusCode != 200) { - throw BuyException(title: providerDescription, content: 'Order $id is not found!'); - } - - final orderResponseJSON = json.decode(orderResponse.body) as Map; - final transferId = orderResponseJSON['transferId'] as String; - final from = orderResponseJSON['sourceCurrency'] as String; - final to = orderResponseJSON['destCurrency'] as String; - final status = orderResponseJSON['status'] as String; - final state = TradeState.deserialize(raw: status.toLowerCase()); - final createdAtRaw = orderResponseJSON['createdAt'] as int; - final createdAt = DateTime.fromMillisecondsSinceEpoch(createdAtRaw).toLocal(); - - final transferUrl = baseApiUrl + _transferSuffix + transferId + _trackSuffix; - final transferUri = Uri.parse(transferUrl); - final transferResponse = await ProxyWrapper().get(clearnetUri: transferUri); - if (transferResponse.statusCode != 200) { - throw BuyException(title: providerDescription, content: 'Transfer $transferId is not found!'); - } - - final transferResponseJSON = json.decode(transferResponse.body) as Map; - final amount = transferResponseJSON['destAmount'] as double; - - return Order( - id: id, - source: OrderSourceDescription.buy, - buyProvider: BuyProviderDescription.wyre, - transferId: transferId, - from: from, - to: to, - state: state, - createdAt: createdAt, - amount: amount.toString(), - receiveAddress: wallet.walletAddresses.address, - walletId: wallet.id); - } -} diff --git a/lib/di.dart b/lib/di.dart index 23edfd38..2ea86274 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -371,9 +371,7 @@ Future setup({ }); } - final isBitcoinBuyEnabled = (secrets.wyreSecretKey.isNotEmpty) && - (secrets.wyreApiKey.isNotEmpty) && - (secrets.wyreAccountId.isNotEmpty); + const isBitcoinBuyEnabled = false; final settingsStore = await SettingsStoreBase.load( nodeSource: _nodeSource, diff --git a/lib/order/order_provider_adapter/wyre_order_provider_adapter.dart b/lib/order/order_provider_adapter/wyre_order_provider_adapter.dart deleted file mode 100644 index 5df6ab59..00000000 --- a/lib/order/order_provider_adapter/wyre_order_provider_adapter.dart +++ /dev/null @@ -1,23 +0,0 @@ -import 'package:hash_wallet/buy/wyre/wyre_buy_provider.dart'; -import 'package:hash_wallet/order/order.dart'; -import 'package:hash_wallet/order/order_provider.dart'; -import 'package:cw_core/wallet_base.dart'; - -class WyreOrderProviderAdapter implements OrderProvider { - WyreOrderProviderAdapter({required WalletBase wallet}) - : _wyreProvider = WyreBuyProvider(wallet: wallet); - - final WyreBuyProvider _wyreProvider; - - @override - Future<(Order, Object?)> findOrderById(String id) async { - final order = await _wyreProvider.findOrderById(id); - return (order, null); - } - - @override - String get title => _wyreProvider.title; - - @override - String get trackUrl => _wyreProvider.trackUrl; -} diff --git a/lib/src/screens/buy/buy_webview_page.dart b/lib/src/screens/buy/buy_webview_page.dart index 6d73e45b..45f9e5ba 100644 --- a/lib/src/screens/buy/buy_webview_page.dart +++ b/lib/src/screens/buy/buy_webview_page.dart @@ -1,6 +1,5 @@ import 'dart:async'; import 'package:hash_wallet/buy/moonpay/moonpay_provider.dart'; -import 'package:hash_wallet/buy/wyre/wyre_buy_provider.dart'; import 'package:hash_wallet/generated/i18n.dart'; import 'package:hash_wallet/src/screens/base_page.dart'; import 'package:hash_wallet/store/dashboard/orders_store.dart'; @@ -54,10 +53,6 @@ class BuyWebViewPageBodyState extends State { _isSaving = false; widget.ordersStore.orderId = ''; - if (widget.buyViewModel.selectedProvider is WyreBuyProvider) { - _saveOrder(keyword: 'completed', splitSymbol: '/'); - } - if (widget.buyViewModel.selectedProvider is MoonPayProvider) { _saveOrder(keyword: 'transactionId', splitSymbol: '='); } diff --git a/lib/view_model/buy/buy_view_model.dart b/lib/view_model/buy/buy_view_model.dart index ac38dde9..9de4ae61 100644 --- a/lib/view_model/buy/buy_view_model.dart +++ b/lib/view_model/buy/buy_view_model.dart @@ -1,5 +1,4 @@ import 'package:hash_wallet/buy/buy_provider.dart'; -import 'package:hash_wallet/buy/wyre/wyre_buy_provider.dart'; import 'package:cw_core/crypto_currency.dart'; import 'package:hash_wallet/entities/fiat_currency.dart'; import 'package:cw_core/utils/print_verbose.dart'; @@ -87,14 +86,6 @@ abstract class BuyViewModelBase with Store { } Future _fetchBuyItems() async { - final List _providerList = []; - - if (wallet.type == WalletType.bitcoin) { - _providerList.add(WyreBuyProvider(wallet: wallet)); - } - - items = _providerList - .map((provider) => BuyItem(provider: provider, buyAmountViewModel: buyAmountViewModel)) - .toList(); + items = const []; } } diff --git a/lib/view_model/order_details_view_model.dart b/lib/view_model/order_details_view_model.dart index af22da78..635daedb 100644 --- a/lib/view_model/order_details_view_model.dart +++ b/lib/view_model/order_details_view_model.dart @@ -8,7 +8,6 @@ import 'package:hash_wallet/generated/i18n.dart'; import 'package:hash_wallet/order/order.dart'; import 'package:hash_wallet/order/order_provider.dart'; import 'package:hash_wallet/order/order_provider_adapter/cake_pay_order_provider_adapter.dart'; -import 'package:hash_wallet/order/order_provider_adapter/wyre_order_provider_adapter.dart'; import 'package:hash_wallet/order/order_provider_description.dart'; import 'package:hash_wallet/order/order_source_description.dart'; import 'package:hash_wallet/src/screens/order_details/cake_pay_detail_list_card_item.dart'; @@ -39,9 +38,7 @@ abstract class OrderDetailsViewModelBase with Store { order = orderForDetails { switch (order.source) { case OrderSourceDescription.buy: - if (order.buyProvider == BuyProviderDescription.wyre) { - _provider = WyreOrderProviderAdapter(wallet: wallet); - } else if (order.buyProvider == BuyProviderDescription.moonPay) { + if (order.buyProvider == BuyProviderDescription.moonPay) { //_provider = MoonPayOrderProviderAdapter(appStore: null /* provide if needed */, wallet: wallet); } break; diff --git a/tool/utils/secret_key.dart b/tool/utils/secret_key.dart index ebde2f07..2ed57347 100644 --- a/tool/utils/secret_key.dart +++ b/tool/utils/secret_key.dart @@ -14,9 +14,6 @@ class SecretKey { SecretKey('backupKeychainSalt', () => hex.encode(encrypt.Key.fromSecureRandom(12).bytes)), SecretKey('changeNowCakeWalletApiKey', () => ''), SecretKey('changeNowMoneroApiKey', () => ''), - SecretKey('wyreSecretKey', () => ''), - SecretKey('wyreApiKey', () => ''), - SecretKey('wyreAccountId', () => ''), SecretKey('moonPayApiKey', () => ''), SecretKey('moonPaySecretKey', () => ''), SecretKey('sideShiftAffiliateId', () => ''), -- 2.50.1 (Apple Git-155) From ac7830e181d64dd7836e099046479be304580e1c Mon Sep 17 00:00:00 2001 From: jwinterm Date: Sun, 17 May 2026 08:24:16 -0400 Subject: [PATCH 8/8] Add CONTRIBUTING.md; fix README prep-script ref CONTRIBUTING.md explains the fork relationship, branch model, generated- code workflow, and what changes we will and won't accept (no re-enabling Solana/Tron/Zano/Decred/Zcash, no Cake-domain endpoints, no Lightning yet, no telemetry). README.md: removed the stale ./scripts/prepare_zcash.sh reference (file doesn't exist) and added a link to CONTRIBUTING. .gitignore: untrack docs/UPSTREAM_SYNC.md (internal merge-strategy playbook, kept locally alongside docs/links.md). --- .gitignore | 3 +- CONTRIBUTING.md | 78 +++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 5 ++-- 3 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/.gitignore b/.gitignore index 5625711b..e08ae072 100644 --- a/.gitignore +++ b/.gitignore @@ -230,5 +230,6 @@ scripts/android/yttrium scripts/bitbox_flutter scripts/reown_flutter -# Hash Wallet: untracked notes +# Hash Wallet: untracked notes / internal playbooks docs/links.md +docs/UPSTREAM_SYNC.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..93c0ea3c --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,78 @@ +# Contributing to Hash Wallet + +Thanks for the interest. Before opening a PR, please read this. + +## Project shape + +Hash Wallet is a **friendly fork** of [Cake Wallet](https://github.com/cake-tech/cake_wallet). We periodically merge upstream changes and try to keep our divergence narrow. Every change you propose should be evaluated through that lens: will this make future upstream syncs harder, and if so, is the value worth the cost? + +## Branch model + +- `dev` is the integration branch — open PRs against `dev`. +- `main` is reserved for tagged releases. +- We do not use long-lived feature branches. Iterate on `dev` directly via small focused PRs. + +## Build environment + +See the build section of [`README.md`](README.md). Flutter version is pinned (`.tool-versions` + `Dockerfile`). Don't use a newer Flutter SDK — Cake's `hive_generator` / `build_resolvers` deps fail on Dart 3.10+ because the `_macros` pseudo-package was removed. + +If you use `mise` or `asdf`, the right Flutter version will activate automatically. + +## Generated code + +Several layers use code generation (MobX stores, Hive type adapters, JSON serializers, configure.dart-generated wallet entry points). Regenerate with: + +```bash +dart pub run build_runner build --delete-conflicting-outputs +``` + +For the wallet-types and pubspec generation: + +```bash +dart run tool/configure.dart --monero --wownero --bitcoin --bitcoinCash \ + --ethereum --polygon --base --arbitrum --bsc --nano --dogecoin +``` + +(That's the canonical Hash Wallet build flag set. Don't pass `--solana`, `--tron`, `--zano`, `--decred`, or `--zcash` — those packages were deleted.) + +## Code style + +- Match the surrounding style. We have not introduced new lints beyond Cake's. +- New observable state goes through MobX; persisted state through Hive. +- Don't add new top-level analytics. Hash Wallet ships with no telemetry by design. +- Don't import `package:cw_zano/`, `package:cw_tron/`, `package:cw_solana/`, `package:cw_decred/` — those packages are deleted. The corresponding `WalletType.*` enum values still exist in `cw_core/lib/wallet_type.dart` for backwards-compat but are never instantiated. +- Avoid adding `cake_*`-prefixed file or symbol names in new code. Use `hash_wallet`-prefixed where the symbol is ours, and leave Cake-prefixed names alone where they're inherited (so upstream merges still apply cleanly). + +## What we generally won't accept + +- Re-enabling Solana, Tron, Zano, Decred, or Zcash. The fork exists in part to drop these — opening that door defeats the purpose. +- New buy/sell provider integrations that require routing through Cake's `exchange-helper.cakewallet.com` proxy. Direct provider APIs are fine if we can register Hash Wallet / Such Software LLC as the partner. +- Lightning Network integration. Greenlight (and self-hosted alternatives) require running infrastructure we're not in a position to operate yet. +- Cake Pay re-enable. The infrastructure is Cake Labs's; we can't run it. +- New defaults that point at `cakewallet.com` hosts. We're moving away from depending on Cake's infrastructure — community nodes, our own proxies (`exchange-helper.such.software`, `prices.neroswap.com`), or both, are preferred. +- Anything that adds telemetry, push notifications via third-party SDKs, or remote bulletin services that the user can't audit. + +## What we want + +- Wownero polish (every paper cut counts — it's the reason this fork exists). +- Build reproducibility improvements (especially Docker / CI parity). +- Privacy-leaning defaults (own-node guidance, Tor/I2P integration improvements, fewer outbound calls). +- Wallet-core bug fixes — these we will happily upstream to Cake. +- Documentation, especially around the build pipeline and the Cake → Hash Wallet diff. + +## Reporting bugs + +Open an issue at https://github.com/Such-Software/hash-wallet/issues. Please include: + +- Build artifact ID (the CI workflow names the artifact by commit SHA). +- Platform + OS version. +- Terminal output if you built and ran from a terminal — many error popups don't print to stderr; check `/error.txt` (typically `~/.config/hash_wallet/error.txt` on Linux). +- Whether the bug also reproduces in the latest Cake Wallet build (so we know whether it's a Cake-upstream bug or a Hash Wallet regression). + +## Security disclosures + +See [`docs/SECURITY.md`](docs/SECURITY.md). Email `support@such.software` for anything sensitive; do not open a public issue for unpatched vulnerabilities. + +## License + +By contributing, you agree your contribution is licensed under the [MIT License](LICENSE.md), the same as the rest of Hash Wallet. diff --git a/README.md b/README.md index 96ce1116..8c85df5c 100644 --- a/README.md +++ b/README.md @@ -58,10 +58,9 @@ flutter --version # confirm 3.32.0 / Dart 3.8.0 ```bash ./scripts/prepare_torch.sh ./scripts/prepare_moneroc.sh -./scripts/prepare_zcash.sh # still required by build, even though Zcash is disabled ./scripts/build_bitbox_flutter.sh # Then fetch the prebuilt reown_flutter tarball (CI does this; reproduce locally -# with the URL in .github/workflows/pr_test_build_linux.yml if you have it). +# with the URL in .github/workflows/build-linux.yml). ``` Then run the platform-specific configure script, e.g.: @@ -72,7 +71,7 @@ APP_LINUX_TYPE=cakewallet ./configure_hash_wallet.sh linux ## Contributing -Issues and PRs welcome at https://github.com/Such-Software/hash-wallet. +Issues and PRs welcome at https://github.com/Such-Software/hash-wallet. See [`CONTRIBUTING.md`](CONTRIBUTING.md) for ground rules. ## License -- 2.50.1 (Apple Git-155)