import 'dart:io'; const bitcoinOutputPath = 'lib/bitcoin/bitcoin.dart'; const moneroOutputPath = 'lib/monero/monero.dart'; const havenOutputPath = 'lib/haven/haven.dart'; const ethereumOutputPath = 'lib/ethereum/ethereum.dart'; const bitcoinCashOutputPath = 'lib/bitcoin_cash/bitcoin_cash.dart'; const nanoOutputPath = 'lib/nano/nano.dart'; const walletTypesPath = 'lib/wallet_types.g.dart'; const secureStoragePath = 'lib/core/secure_storage.dart'; const pubspecDefaultPath = 'pubspec_default.yaml'; const pubspecOutputPath = 'pubspec.yaml'; Future main(List args) async { const prefix = '--'; final hasBitcoin = args.contains('${prefix}bitcoin'); final hasMonero = args.contains('${prefix}monero'); final hasHaven = args.contains('${prefix}haven'); final hasEthereum = args.contains('${prefix}ethereum'); final hasBitcoinCash = args.contains('${prefix}bitcoinCash'); final hasNano = args.contains('${prefix}nano'); final hasBanano = args.contains('${prefix}banano'); final excludeFlutterSecureStorage = args.contains('${prefix}excludeFlutterSecureStorage'); await generateBitcoin(hasBitcoin); await generateMonero(hasMonero); await generateHaven(hasHaven); await generateEthereum(hasEthereum); await generateBitcoinCash(hasBitcoinCash); await generateNano(hasNano); // await generateBanano(hasEthereum); await generatePubspec( hasMonero: hasMonero, hasBitcoin: hasBitcoin, hasHaven: hasHaven, hasEthereum: hasEthereum, hasNano: hasNano, hasBanano: hasBanano, hasBitcoinCash: hasBitcoinCash, hasFlutterSecureStorage: !excludeFlutterSecureStorage, ); await generateWalletTypes( hasMonero: hasMonero, hasBitcoin: hasBitcoin, hasHaven: hasHaven, hasEthereum: hasEthereum, hasNano: hasNano, hasBanano: hasBanano, hasBitcoinCash: hasBitcoinCash, ); await injectSecureStorage(!excludeFlutterSecureStorage); } Future generateBitcoin(bool hasImplementation) async { final outputFile = File(bitcoinOutputPath); const bitcoinCommonHeaders = """ import 'package:cw_core/unspent_transaction_output.dart'; import 'package:cw_core/wallet_credentials.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/unspent_coins_info.dart'; import 'package:cw_core/wallet_service.dart'; import 'package:cake_wallet/view_model/send/output.dart'; import 'package:hive/hive.dart';"""; const bitcoinCWHeaders = """ import 'package:cw_bitcoin/electrum_wallet.dart'; import 'package:cw_bitcoin/bitcoin_unspent.dart'; import 'package:cw_bitcoin/bitcoin_mnemonic.dart'; import 'package:cw_bitcoin/bitcoin_transaction_priority.dart'; import 'package:cw_bitcoin/bitcoin_wallet_service.dart'; import 'package:cw_bitcoin/bitcoin_wallet_creation_credentials.dart'; import 'package:cw_bitcoin/bitcoin_amount_format.dart'; import 'package:cw_bitcoin/bitcoin_address_record.dart'; import 'package:cw_bitcoin/bitcoin_transaction_credentials.dart'; import 'package:cw_bitcoin/litecoin_wallet_service.dart'; import 'package:bitcoin_flutter/bitcoin_flutter.dart' as btc; """; const bitcoinCwPart = "part 'cw_bitcoin.dart';"; const bitcoinContent = """ abstract class Bitcoin { TransactionPriority getMediumTransactionPriority(); WalletCredentials createBitcoinRestoreWalletFromSeedCredentials({required String name, required String mnemonic, required String password}); WalletCredentials createBitcoinRestoreWalletFromWIFCredentials({required String name, required String password, required String wif, WalletInfo? walletInfo}); WalletCredentials createBitcoinNewWalletCredentials({required String name, WalletInfo? walletInfo, String? password}); List getWordList(); Map getWalletKeys(Object wallet); List getTransactionPriorities(); List getLitecoinTransactionPriorities(); TransactionPriority deserializeBitcoinTransactionPriority(int raw); TransactionPriority deserializeLitecoinTransactionPriority(int raw); int getFeeRate(Object wallet, TransactionPriority priority); Future generateNewAddress(Object wallet, {String? label}); Object createBitcoinTransactionCredentials(List outputs, {required TransactionPriority priority, int? feeRate}); Object createBitcoinTransactionCredentialsRaw(List outputs, {TransactionPriority? priority, required int feeRate}); List getAddresses(Object wallet); String getAddress(Object wallet); String getReceiveAddress(Object wallet); btc.SilentPaymentAddress? getSilentAddress(Object wallet); List getSilentAddresses(Object wallet); String formatterBitcoinAmountToString({required int amount}); double formatterBitcoinAmountToDouble({required int amount}); int formatterStringDoubleToBitcoinAmount(String amount); String bitcoinTransactionPriorityWithLabel(TransactionPriority priority, int rate); List getUnspents(Object wallet); void updateUnspents(Object wallet); WalletService createBitcoinWalletService(Box walletInfoSource, Box unspentCoinSource, bool isDirect); WalletService createLitecoinWalletService(Box walletInfoSource, Box unspentCoinSource, bool isDirect); TransactionPriority getBitcoinTransactionPriorityMedium(); TransactionPriority getLitecoinTransactionPriorityMedium(); TransactionPriority getBitcoinTransactionPrioritySlow(); TransactionPriority getLitecoinTransactionPrioritySlow(); } """; const bitcoinEmptyDefinition = 'Bitcoin? bitcoin;\n'; const bitcoinCWDefinition = 'Bitcoin? bitcoin = CWBitcoin();\n'; final output = '$bitcoinCommonHeaders\n' + (hasImplementation ? '$bitcoinCWHeaders\n' : '\n') + (hasImplementation ? '$bitcoinCwPart\n\n' : '\n') + (hasImplementation ? bitcoinCWDefinition : bitcoinEmptyDefinition) + '\n' + bitcoinContent; if (outputFile.existsSync()) { await outputFile.delete(); } await outputFile.writeAsString(output); } Future generateMonero(bool hasImplementation) async { final outputFile = File(moneroOutputPath); const moneroCommonHeaders = """ import 'package:cw_core/unspent_transaction_output.dart'; import 'package:cw_core/unspent_coins_info.dart'; import 'package:cw_monero/monero_unspent.dart'; import 'package:mobx/mobx.dart'; import 'package:flutter/foundation.dart'; import 'package:cw_core/wallet_credentials.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/transaction_priority.dart'; import 'package:cw_core/transaction_history.dart'; import 'package:cw_core/transaction_info.dart'; import 'package:cw_core/balance.dart'; import 'package:cw_core/output_info.dart'; import 'package:cake_wallet/view_model/send/output.dart'; import 'package:cw_core/wallet_service.dart'; import 'package:hive/hive.dart';"""; const moneroCWHeaders = """ import 'package:cw_core/get_height_by_date.dart'; import 'package:cw_core/monero_amount_format.dart'; import 'package:cw_core/monero_transaction_priority.dart'; import 'package:cw_monero/monero_wallet_service.dart'; import 'package:cw_monero/monero_wallet.dart'; import 'package:cw_monero/monero_transaction_info.dart'; import 'package:cw_monero/monero_transaction_history.dart'; import 'package:cw_monero/monero_transaction_creation_credentials.dart'; import 'package:cw_core/account.dart' as monero_account; import 'package:cw_monero/api/wallet.dart' as monero_wallet_api; import 'package:cw_monero/mnemonics/english.dart'; import 'package:cw_monero/mnemonics/chinese_simplified.dart'; import 'package:cw_monero/mnemonics/dutch.dart'; import 'package:cw_monero/mnemonics/german.dart'; import 'package:cw_monero/mnemonics/japanese.dart'; import 'package:cw_monero/mnemonics/russian.dart'; import 'package:cw_monero/mnemonics/spanish.dart'; import 'package:cw_monero/mnemonics/portuguese.dart'; import 'package:cw_monero/mnemonics/french.dart'; import 'package:cw_monero/mnemonics/italian.dart'; import 'package:cw_monero/pending_monero_transaction.dart'; """; const moneroCwPart = "part 'cw_monero.dart';"; const moneroContent = """ class Account { Account({required this.id, required this.label, this.balance}); final int id; final String label; final String? balance; } class Subaddress { Subaddress({ required this.id, required this.label, required this.address}); final int id; final String label; final String address; } class MoneroBalance extends Balance { MoneroBalance({required this.fullBalance, required this.unlockedBalance}) : formattedFullBalance = monero!.formatterMoneroAmountToString(amount: fullBalance), formattedUnlockedBalance = monero!.formatterMoneroAmountToString(amount: unlockedBalance), super(unlockedBalance, fullBalance); MoneroBalance.fromString( {required this.formattedFullBalance, required this.formattedUnlockedBalance}) : fullBalance = monero!.formatterMoneroParseAmount(amount: formattedFullBalance), unlockedBalance = monero!.formatterMoneroParseAmount(amount: formattedUnlockedBalance), super(monero!.formatterMoneroParseAmount(amount: formattedUnlockedBalance), monero!.formatterMoneroParseAmount(amount: formattedFullBalance)); final int fullBalance; final int unlockedBalance; final String formattedFullBalance; final String formattedUnlockedBalance; @override String get formattedAvailableBalance => formattedUnlockedBalance; @override String get formattedAdditionalBalance => formattedFullBalance; } abstract class MoneroWalletDetails { @observable late Account account; @observable late MoneroBalance balance; } abstract class Monero { MoneroAccountList getAccountList(Object wallet); MoneroSubaddressList getSubaddressList(Object wallet); TransactionHistoryBase getTransactionHistory(Object wallet); MoneroWalletDetails getMoneroWalletDetails(Object wallet); String getTransactionAddress(Object wallet, int accountIndex, int addressIndex); String getSubaddressLabel(Object wallet, int accountIndex, int addressIndex); int getHeightByDate({required DateTime date}); TransactionPriority getDefaultTransactionPriority(); TransactionPriority getMoneroTransactionPrioritySlow(); TransactionPriority getMoneroTransactionPriorityAutomatic(); TransactionPriority deserializeMoneroTransactionPriority({required int raw}); List getTransactionPriorities(); List getMoneroWordList(String language); List getUnspents(Object wallet); void updateUnspents(Object wallet); WalletCredentials createMoneroRestoreWalletFromKeysCredentials({ required String name, required String spendKey, required String viewKey, required String address, required String password, required String language, required int height}); WalletCredentials createMoneroRestoreWalletFromSeedCredentials({required String name, required String password, required int height, required String mnemonic}); WalletCredentials createMoneroNewWalletCredentials({required String name, required String language, String? password,}); Map getKeys(Object wallet); Object createMoneroTransactionCreationCredentials({required List outputs, required TransactionPriority priority}); Object createMoneroTransactionCreationCredentialsRaw({required List outputs, required TransactionPriority priority}); String formatterMoneroAmountToString({required int amount}); double formatterMoneroAmountToDouble({required int amount}); int formatterMoneroParseAmount({required String amount}); Account getCurrentAccount(Object wallet); void setCurrentAccount(Object wallet, int id, String label, String? balance); void onStartup(); int getTransactionInfoAccountId(TransactionInfo tx); WalletService createMoneroWalletService(Box walletInfoSource, Box unspentCoinSource); Map pendingTransactionInfo(Object transaction); } abstract class MoneroSubaddressList { ObservableList get subaddresses; void update(Object wallet, {required int accountIndex}); void refresh(Object wallet, {required int accountIndex}); List getAll(Object wallet); Future addSubaddress(Object wallet, {required int accountIndex, required String label}); Future setLabelSubaddress(Object wallet, {required int accountIndex, required int addressIndex, required String label}); } abstract class MoneroAccountList { ObservableList get accounts; void update(Object wallet); void refresh(Object wallet); List getAll(Object wallet); Future addAccount(Object wallet, {required String label}); Future setLabelAccount(Object wallet, {required int accountIndex, required String label}); } """; const moneroEmptyDefinition = 'Monero? monero;\n'; const moneroCWDefinition = 'Monero? monero = CWMonero();\n'; final output = '$moneroCommonHeaders\n' + (hasImplementation ? '$moneroCWHeaders\n' : '\n') + (hasImplementation ? '$moneroCwPart\n\n' : '\n') + (hasImplementation ? moneroCWDefinition : moneroEmptyDefinition) + '\n' + moneroContent; if (outputFile.existsSync()) { await outputFile.delete(); } await outputFile.writeAsString(output); } Future generateHaven(bool hasImplementation) async { final outputFile = File(havenOutputPath); const havenCommonHeaders = """ import 'package:mobx/mobx.dart'; import 'package:flutter/foundation.dart'; import 'package:cw_core/wallet_credentials.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/transaction_priority.dart'; import 'package:cw_core/transaction_history.dart'; import 'package:cw_core/transaction_info.dart'; import 'package:cw_core/balance.dart'; import 'package:cw_core/output_info.dart'; import 'package:cake_wallet/view_model/send/output.dart'; import 'package:cw_core/wallet_service.dart'; import 'package:hive/hive.dart'; import 'package:cw_core/crypto_currency.dart';"""; const havenCWHeaders = """ import 'package:cw_core/get_height_by_date.dart'; import 'package:cw_core/monero_amount_format.dart'; import 'package:cw_core/monero_transaction_priority.dart'; import 'package:cw_haven/haven_wallet_service.dart'; import 'package:cw_haven/haven_wallet.dart'; import 'package:cw_haven/haven_transaction_info.dart'; import 'package:cw_haven/haven_transaction_history.dart'; import 'package:cw_core/account.dart' as monero_account; import 'package:cw_haven/api/wallet.dart' as monero_wallet_api; import 'package:cw_haven/mnemonics/english.dart'; import 'package:cw_haven/mnemonics/chinese_simplified.dart'; import 'package:cw_haven/mnemonics/dutch.dart'; import 'package:cw_haven/mnemonics/german.dart'; import 'package:cw_haven/mnemonics/japanese.dart'; import 'package:cw_haven/mnemonics/russian.dart'; import 'package:cw_haven/mnemonics/spanish.dart'; import 'package:cw_haven/mnemonics/portuguese.dart'; import 'package:cw_haven/mnemonics/french.dart'; import 'package:cw_haven/mnemonics/italian.dart'; import 'package:cw_haven/haven_transaction_creation_credentials.dart'; import 'package:cw_haven/api/balance_list.dart'; """; const havenCwPart = "part 'cw_haven.dart';"; const havenContent = """ class Account { Account({required this.id, required this.label}); final int id; final String label; } class Subaddress { Subaddress({ required this.id, required this.label, required this.address}); final int id; final String label; final String address; } class HavenBalance extends Balance { HavenBalance({required this.fullBalance, required this.unlockedBalance}) : formattedFullBalance = haven!.formatterMoneroAmountToString(amount: fullBalance), formattedUnlockedBalance = haven!.formatterMoneroAmountToString(amount: unlockedBalance), super(unlockedBalance, fullBalance); HavenBalance.fromString( {required this.formattedFullBalance, required this.formattedUnlockedBalance}) : fullBalance = haven!.formatterMoneroParseAmount(amount: formattedFullBalance), unlockedBalance = haven!.formatterMoneroParseAmount(amount: formattedUnlockedBalance), super(haven!.formatterMoneroParseAmount(amount: formattedUnlockedBalance), haven!.formatterMoneroParseAmount(amount: formattedFullBalance)); final int fullBalance; final int unlockedBalance; final String formattedFullBalance; final String formattedUnlockedBalance; @override String get formattedAvailableBalance => formattedUnlockedBalance; @override String get formattedAdditionalBalance => formattedFullBalance; } class AssetRate { AssetRate(this.asset, this.rate); final String asset; final int rate; } abstract class HavenWalletDetails { // FIX-ME: it's abstruct class @observable late Account account; // FIX-ME: it's abstruct class @observable late HavenBalance balance; } abstract class Haven { HavenAccountList getAccountList(Object wallet); MoneroSubaddressList getSubaddressList(Object wallet); TransactionHistoryBase getTransactionHistory(Object wallet); HavenWalletDetails getMoneroWalletDetails(Object wallet); String getTransactionAddress(Object wallet, int accountIndex, int addressIndex); int getHeightByDate({required DateTime date}); Future getCurrentHeight(); TransactionPriority getDefaultTransactionPriority(); TransactionPriority deserializeMoneroTransactionPriority({required int raw}); List getTransactionPriorities(); List getMoneroWordList(String language); WalletCredentials createHavenRestoreWalletFromKeysCredentials({ required String name, required String spendKey, required String viewKey, required String address, required String password, required String language, required int height}); WalletCredentials createHavenRestoreWalletFromSeedCredentials({required String name, required String password, required int height, required String mnemonic}); WalletCredentials createHavenNewWalletCredentials({required String name, required String language, String? password}); Map getKeys(Object wallet); Object createHavenTransactionCreationCredentials({required List outputs, required TransactionPriority priority, required String assetType}); String formatterMoneroAmountToString({required int amount}); double formatterMoneroAmountToDouble({required int amount}); int formatterMoneroParseAmount({required String amount}); Account getCurrentAccount(Object wallet); void setCurrentAccount(Object wallet, int id, String label); void onStartup(); int getTransactionInfoAccountId(TransactionInfo tx); WalletService createHavenWalletService(Box walletInfoSource); CryptoCurrency assetOfTransaction(TransactionInfo tx); List getAssetRate(); } abstract class MoneroSubaddressList { ObservableList get subaddresses; void update(Object wallet, {required int accountIndex}); void refresh(Object wallet, {required int accountIndex}); List getAll(Object wallet); Future addSubaddress(Object wallet, {required int accountIndex, required String label}); Future setLabelSubaddress(Object wallet, {required int accountIndex, required int addressIndex, required String label}); } abstract class HavenAccountList { ObservableList get accounts; void update(Object wallet); void refresh(Object wallet); List getAll(Object wallet); Future addAccount(Object wallet, {required String label}); Future setLabelAccount(Object wallet, {required int accountIndex, required String label}); } """; const havenEmptyDefinition = 'Haven? haven;\n'; const havenCWDefinition = 'Haven? haven = CWHaven();\n'; final output = '$havenCommonHeaders\n' + (hasImplementation ? '$havenCWHeaders\n' : '\n') + (hasImplementation ? '$havenCwPart\n\n' : '\n') + (hasImplementation ? havenCWDefinition : havenEmptyDefinition) + '\n' + havenContent; if (outputFile.existsSync()) { await outputFile.delete(); } await outputFile.writeAsString(output); } Future generateEthereum(bool hasImplementation) async { final outputFile = File(ethereumOutputPath); const ethereumCommonHeaders = """ import 'package:cake_wallet/view_model/send/output.dart'; import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/erc20_token.dart'; import 'package:cw_core/output_info.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:eth_sig_util/util/utils.dart'; import 'package:hive/hive.dart'; import 'package:web3dart/web3dart.dart'; """; const ethereumCWHeaders = """ import 'package:cw_ethereum/ethereum_formatter.dart'; import 'package:cw_ethereum/ethereum_mnemonics.dart'; import 'package:cw_ethereum/ethereum_transaction_credentials.dart'; import 'package:cw_ethereum/ethereum_transaction_info.dart'; import 'package:cw_ethereum/ethereum_wallet.dart'; import 'package:cw_ethereum/ethereum_wallet_creation_credentials.dart'; import 'package:cw_ethereum/ethereum_wallet_service.dart'; import 'package:cw_ethereum/ethereum_transaction_priority.dart'; """; const ethereumCwPart = "part 'cw_ethereum.dart';"; const ethereumContent = """ abstract class Ethereum { List getEthereumWordList(String language); WalletService createEthereumWalletService(Box walletInfoSource, bool isDirect); WalletCredentials createEthereumNewWalletCredentials({required String name, WalletInfo? walletInfo, String? password}); WalletCredentials createEthereumRestoreWalletFromSeedCredentials({required String name, required String mnemonic, required String password}); WalletCredentials createEthereumRestoreWalletFromPrivateKey({required String name, required String privateKey, required String password}); String getAddress(WalletBase wallet); String getPrivateKey(WalletBase wallet); String getPublicKey(WalletBase wallet); TransactionPriority getDefaultTransactionPriority(); TransactionPriority getEthereumTransactionPrioritySlow(); List getTransactionPriorities(); TransactionPriority deserializeEthereumTransactionPriority(int raw); Object createEthereumTransactionCredentials( List outputs, { required TransactionPriority priority, required CryptoCurrency currency, int? feeRate, }); Object createEthereumTransactionCredentialsRaw( List outputs, { TransactionPriority? priority, required CryptoCurrency currency, required int feeRate, }); int formatterEthereumParseAmount(String amount); double formatterEthereumAmountToDouble({TransactionInfo? transaction, BigInt? amount, int exponent = 18}); List getERC20Currencies(WalletBase wallet); Future addErc20Token(WalletBase wallet, Erc20Token token); Future deleteErc20Token(WalletBase wallet, Erc20Token token); Future getErc20Token(WalletBase wallet, String contractAddress); CryptoCurrency assetOfTransaction(WalletBase wallet, TransactionInfo transaction); void updateEtherscanUsageState(WalletBase wallet, bool isEnabled); Web3Client? getWeb3Client(WalletBase wallet); } """; const ethereumEmptyDefinition = 'Ethereum? ethereum;\n'; const ethereumCWDefinition = 'Ethereum? ethereum = CWEthereum();\n'; final output = '$ethereumCommonHeaders\n' + (hasImplementation ? '$ethereumCWHeaders\n' : '\n') + (hasImplementation ? '$ethereumCwPart\n\n' : '\n') + (hasImplementation ? ethereumCWDefinition : ethereumEmptyDefinition) + '\n' + ethereumContent; if (outputFile.existsSync()) { await outputFile.delete(); } await outputFile.writeAsString(output); } Future generateBitcoinCash(bool hasImplementation) async { final outputFile = File(bitcoinCashOutputPath); const bitcoinCashCommonHeaders = """ import 'dart:typed_data'; import 'package:cw_core/unspent_transaction_output.dart'; import 'package:cw_core/transaction_priority.dart'; import 'package:cw_core/unspent_coins_info.dart'; import 'package:cw_core/wallet_credentials.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_service.dart'; import 'package:hive/hive.dart'; """; const bitcoinCashCWHeaders = """ import 'package:cw_bitcoin_cash/cw_bitcoin_cash.dart'; import 'package:cw_bitcoin/bitcoin_transaction_priority.dart'; """; const bitcoinCashCwPart = "part 'cw_bitcoin_cash.dart';"; const bitcoinCashContent = """ abstract class BitcoinCash { String getMnemonic(int? strength); Uint8List getSeedFromMnemonic(String seed); String getCashAddrFormat(String address); WalletService createBitcoinCashWalletService( Box walletInfoSource, Box unspentCoinSource, bool isDirect); WalletCredentials createBitcoinCashNewWalletCredentials( {required String name, WalletInfo? walletInfo, String? password}); WalletCredentials createBitcoinCashRestoreWalletFromSeedCredentials( {required String name, required String mnemonic, required String password}); TransactionPriority deserializeBitcoinCashTransactionPriority(int raw); TransactionPriority getDefaultTransactionPriority(); List getTransactionPriorities(); TransactionPriority getBitcoinCashTransactionPrioritySlow(); } """; const bitcoinCashEmptyDefinition = 'BitcoinCash? bitcoinCash;\n'; const bitcoinCashCWDefinition = 'BitcoinCash? bitcoinCash = CWBitcoinCash();\n'; final output = '$bitcoinCashCommonHeaders\n' + (hasImplementation ? '$bitcoinCashCWHeaders\n' : '\n') + (hasImplementation ? '$bitcoinCashCwPart\n\n' : '\n') + (hasImplementation ? bitcoinCashCWDefinition : bitcoinCashEmptyDefinition) + '\n' + bitcoinCashContent; if (outputFile.existsSync()) { await outputFile.delete(); } await outputFile.writeAsString(output); } Future generateNano(bool hasImplementation) async { final outputFile = File(nanoOutputPath); const nanoCommonHeaders = """ import 'package:cw_core/cake_hive.dart'; import 'package:cw_core/nano_account.dart'; import 'package:cw_core/account.dart'; import 'package:cw_core/node.dart'; import 'package:cw_core/wallet_credentials.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/transaction_info.dart'; import 'package:cw_core/transaction_history.dart'; import 'package:cw_core/wallet_service.dart'; import 'package:cw_core/output_info.dart'; import 'package:cw_core/nano_account_info_response.dart'; import 'package:mobx/mobx.dart'; import 'package:hive/hive.dart'; import 'package:cake_wallet/view_model/send/output.dart'; """; const nanoCWHeaders = """ import 'package:cw_nano/nano_client.dart'; import 'package:cw_nano/nano_mnemonic.dart'; import 'package:cw_nano/nano_wallet.dart'; import 'package:cw_nano/nano_wallet_service.dart'; import 'package:cw_nano/nano_transaction_info.dart'; import 'package:cw_nano/nano_transaction_credentials.dart'; import 'package:cw_nano/nano_wallet_creation_credentials.dart'; // needed for nano_util: import 'dart:convert'; import 'dart:typed_data'; import 'package:convert/convert.dart'; import "package:ed25519_hd_key/ed25519_hd_key.dart"; import 'package:libcrypto/libcrypto.dart'; import 'package:nanodart/nanodart.dart' as ND; import 'package:decimal/decimal.dart'; """; const nanoCwPart = "part 'cw_nano.dart';"; const nanoContent = """ abstract class Nano { NanoAccountList getAccountList(Object wallet); Account getCurrentAccount(Object wallet); void setCurrentAccount(Object wallet, int id, String label, String? balance); WalletService createNanoWalletService(Box walletInfoSource, bool isDirect); WalletCredentials createNanoNewWalletCredentials({ required String name, String? password, }); WalletCredentials createNanoRestoreWalletFromSeedCredentials({ required String name, required String password, required String mnemonic, DerivationType? derivationType, }); WalletCredentials createNanoRestoreWalletFromKeysCredentials({ required String name, required String password, required String seedKey, DerivationType? derivationType, }); List getNanoWordList(String language); Map getKeys(Object wallet); Object createNanoTransactionCredentials(List outputs); Future changeRep(Object wallet, String address); Future updateTransactions(Object wallet); BigInt getTransactionAmountRaw(TransactionInfo transactionInfo); String getRepresentative(Object wallet); } abstract class NanoAccountList { ObservableList get accounts; void update(Object wallet); void refresh(Object wallet); Future> getAll(Object wallet); Future addAccount(Object wallet, {required String label}); Future setLabelAccount(Object wallet, {required int accountIndex, required String label}); } abstract class NanoUtil { String seedToPrivate(String seed, int index); String seedToAddress(String seed, int index); String seedToMnemonic(String seed); Future mnemonicToSeed(String mnemonic); String privateKeyToPublic(String privateKey); String addressToPublicKey(String publicAddress); String privateKeyToAddress(String privateKey); String publicKeyToAddress(String publicKey); bool isValidSeed(String seed); Future hdMnemonicListToSeed(List words); Future hdSeedToPrivate(String seed, int index); Future hdSeedToAddress(String seed, int index); Future uniSeedToAddress(String seed, int index, String type); Future uniSeedToPrivate(String seed, int index, String type); bool isValidBip39Seed(String seed); static const int maxDecimalDigits = 6; // Max digits after decimal BigInt rawPerNano = BigInt.parse("1000000000000000000000000000000"); BigInt rawPerNyano = BigInt.parse("1000000000000000000000000"); BigInt rawPerBanano = BigInt.parse("100000000000000000000000000000"); BigInt rawPerXMR = BigInt.parse("1000000000000"); BigInt convertXMRtoNano = BigInt.parse("1000000000000000000"); String getRawAsDecimalString(String? raw, BigInt? rawPerCur); String getRawAsUsableString(String? raw, BigInt rawPerCur); String getRawAccuracy(String? raw, BigInt rawPerCur); String getAmountAsRaw(String amount, BigInt rawPerCur); // derivationInfo: Future getInfoFromSeedOrMnemonic( DerivationType derivationType, { String? seedKey, String? mnemonic, required Node node, }); Future> compareDerivationMethods({ String? mnemonic, String? privateKey, required Node node, }); } """; const nanoEmptyDefinition = 'Nano? nano;\nNanoUtil? nanoUtil;\n'; const nanoCWDefinition = 'Nano? nano = CWNano();\nNanoUtil? nanoUtil = CWNanoUtil();\n'; final output = '$nanoCommonHeaders\n' + (hasImplementation ? '$nanoCWHeaders\n' : '\n') + (hasImplementation ? '$nanoCwPart\n\n' : '\n') + (hasImplementation ? nanoCWDefinition : nanoEmptyDefinition) + '\n' + nanoContent; if (outputFile.existsSync()) { await outputFile.delete(); } await outputFile.writeAsString(output); } Future generatePubspec( {required bool hasMonero, required bool hasBitcoin, required bool hasHaven, required bool hasEthereum, required bool hasNano, required bool hasBanano, required bool hasBitcoinCash, required bool hasFlutterSecureStorage, }) async { const cwCore = """ cw_core: path: ./cw_core """; const cwMonero = """ cw_monero: path: ./cw_monero """; const cwBitcoin = """ cw_bitcoin: path: ./cw_bitcoin """; const cwHaven = """ cw_haven: path: ./cw_haven """; const cwSharedExternal = """ cw_shared_external: path: ./cw_shared_external """; const flutterSecureStorage = """ flutter_secure_storage: git: url: https://github.com/cake-tech/flutter_secure_storage.git path: flutter_secure_storage ref: cake-8.0.0 version: 8.0.0 """; const cwEthereum = """ cw_ethereum: path: ./cw_ethereum """; const cwBitcoinCash = """ cw_bitcoin_cash: path: ./cw_bitcoin_cash """; const cwNano = """ cw_nano: path: ./cw_nano """; const cwBanano = """ cw_banano: path: ./cw_banano """; final inputFile = File(pubspecOutputPath); final inputText = await inputFile.readAsString(); final inputLines = inputText.split('\n'); final dependenciesIndex = inputLines.indexWhere((line) => line.toLowerCase() == 'dependencies:'); var output = cwCore; if (hasMonero) { output += '\n$cwMonero\n$cwSharedExternal'; } if (hasBitcoin) { output += '\n$cwBitcoin'; } if (hasEthereum) { output += '\n$cwEthereum'; } if (hasNano) { output += '\n$cwNano'; } if (hasBanano) { output += '\n$cwBanano'; } if (hasBitcoinCash) { output += '\n$cwBitcoinCash'; } if (hasHaven && !hasMonero) { output += '\n$cwSharedExternal\n$cwHaven'; } else if (hasHaven) { output += '\n$cwHaven'; } if (hasFlutterSecureStorage) { output += '\n$flutterSecureStorage\n'; } final outputLines = output.split('\n'); inputLines.insertAll(dependenciesIndex + 1, outputLines); final outputContent = inputLines.join('\n'); final outputFile = File(pubspecOutputPath); if (outputFile.existsSync()) { await outputFile.delete(); } await outputFile.writeAsString(outputContent); } Future generateWalletTypes( {required bool hasMonero, required bool hasBitcoin, required bool hasHaven, required bool hasEthereum, required bool hasNano, required bool hasBanano, required bool hasBitcoinCash}) async { final walletTypesFile = File(walletTypesPath); if (walletTypesFile.existsSync()) { await walletTypesFile.delete(); } const outputHeader = "import 'package:cw_core/wallet_type.dart';"; const outputDefinition = 'final availableWalletTypes = ['; var outputContent = outputHeader + '\n\n' + outputDefinition + '\n'; if (hasMonero) { outputContent += '\tWalletType.monero,\n'; } if (hasBitcoin) { outputContent += '\tWalletType.bitcoin,\n'; } if (hasEthereum) { outputContent += '\tWalletType.ethereum,\n'; } if (hasBitcoin) { outputContent += '\tWalletType.litecoin,\n'; } if (hasBitcoinCash) { outputContent += '\tWalletType.bitcoinCash,\n'; } if (hasNano) { outputContent += '\tWalletType.nano,\n'; } if (hasBanano) { outputContent += '\tWalletType.banano,\n'; } if (hasHaven) { outputContent += '\tWalletType.haven,\n'; } outputContent += '];\n'; await walletTypesFile.writeAsString(outputContent); } Future injectSecureStorage(bool hasFlutterSecureStorage) async { const flutterSecureStorageHeader = "import 'package:flutter_secure_storage/flutter_secure_storage.dart';"; const abstractSecureStorage = """ abstract class SecureStorage { Future read({required String key}); Future write({required String key, required String? value}); Future delete({required String key}); // Legacy Future readNoIOptions({required String key}); }"""; const defaultSecureStorage = """ class DefaultSecureStorage extends SecureStorage { DefaultSecureStorage._(this._secureStorage); factory DefaultSecureStorage() => _instance; static final _instance = DefaultSecureStorage._(FlutterSecureStorage()); final FlutterSecureStorage _secureStorage; @override Future read({required String key}) async => _secureStorage.read(key: key); @override Future write({required String key, required String? value}) async => _secureStorage.write(key: key, value: value); @override Future delete({required String key}) async => _secureStorage.delete(key: key); @override Future readNoIOptions({required String key}) async => _secureStorage.read(key: key, iOptions: IOSOptions()); }"""; const fakeSecureStorage = """ class FakeSecureStorage extends SecureStorage { @override Future read({required String key}) async => null; @override Future write({required String key, required String? value}) async {} @override Future delete({required String key}) async {} @override Future readNoIOptions({required String key}) async => null; }"""; final outputFile = File(secureStoragePath); final header = hasFlutterSecureStorage ? '${flutterSecureStorageHeader}\n\nfinal SecureStorage secureStorageShared = DefaultSecureStorage();\n' : 'final SecureStorage secureStorageShared = FakeSecureStorage();\n'; var output = ''; if (outputFile.existsSync()) { await outputFile.delete(); } output += '${header}\n${abstractSecureStorage}\n\n'; if (hasFlutterSecureStorage) { output += '${defaultSecureStorage}\n'; } else { output += '${fakeSecureStorage}\n'; } await outputFile.writeAsString(output); }