Merge remote-tracking branch 'origin/mweb' into mweb

This commit is contained in:
OmarHatem 2024-09-09 23:24:17 +03:00
commit 729df419c0
15 changed files with 117 additions and 75 deletions

View file

@ -110,15 +110,8 @@ jobs:
export PATH=$PATH:/usr/local/go/bin export PATH=$PATH:/usr/local/go/bin
export PATH=$PATH:~/go/bin export PATH=$PATH:~/go/bin
# build mwebd: # build mwebd:
cd /opt/android/cake_wallet cd /opt/android/cake_wallet/scripts/android/
git clone https://github.com/ltcmweb/mwebd ./build_mwebd.sh
cd /opt/android/cake_wallet/mwebd
git reset --hard f6ea8a9e3d348b01bb44f03a1cc4ad65b0abe935
gomobile bind -target=android -androidapi 21 .
mkdir -p /opt/android/cake_wallet/cw_mweb/android/libs/
mv ./mwebd.aar $_
cd ..
rm -rf mwebd
- name: Generate KeyStore - name: Generate KeyStore
run: | run: |

View file

@ -105,15 +105,8 @@ jobs:
export PATH=$PATH:/usr/local/go/bin export PATH=$PATH:/usr/local/go/bin
export PATH=$PATH:~/go/bin export PATH=$PATH:~/go/bin
# build mwebd: # build mwebd:
cd /opt/android/cake_wallet cd /opt/android/cake_wallet/scripts/android/
git clone https://github.com/ltcmweb/mwebd ./build_mwebd.sh
cd /opt/android/cake_wallet/mwebd
git reset --hard f6ea8a9e3d348b01bb44f03a1cc4ad65b0abe935
gomobile bind -target=android -androidapi 21 .
mkdir -p /opt/android/cake_wallet/cw_mweb/android/libs/
mv ./mwebd.aar $_
cd ..
rm -rf mwebd
- name: Generate localization - name: Generate localization
run: | run: |

View file

@ -8,6 +8,7 @@ import 'package:cw_core/sec_random_native.dart';
import 'package:cw_core/utils/text_normalizer.dart'; import 'package:cw_core/utils/text_normalizer.dart';
const segwit = '100'; const segwit = '100';
const mweb = 'eb';
final wordlist = englishWordlist; final wordlist = englishWordlist;
double logBase(num x, num base) => log(x) / log(base); double logBase(num x, num base) => log(x) / log(base);
@ -125,7 +126,7 @@ Future<Uint8List> mnemonicToSeedBytes(String mnemonic,
return Uint8List.fromList(bytes); return Uint8List.fromList(bytes);
} }
bool matchesAnyPrefix(String mnemonic) => prefixMatches(mnemonic, [segwit]).any((el) => el); bool matchesAnyPrefix(String mnemonic) => prefixMatches(mnemonic, [segwit, mweb]).any((el) => el);
bool validateMnemonic(String mnemonic, {String prefix = segwit}) { bool validateMnemonic(String mnemonic, {String prefix = segwit}) {
try { try {

View file

@ -1689,12 +1689,15 @@ abstract class ElectrumWalletBase
final Map<String, ElectrumTransactionInfo> historiesWithDetails = {}; final Map<String, ElectrumTransactionInfo> historiesWithDetails = {};
if (type == WalletType.bitcoin) { if (type == WalletType.bitcoin) {
await Future.wait(ADDRESS_TYPES await Future.wait(BITCOIN_ADDRESS_TYPES
.map((type) => fetchTransactionsForAddressType(historiesWithDetails, type))); .map((type) => fetchTransactionsForAddressType(historiesWithDetails, type)));
} else if (type == WalletType.bitcoinCash) { } else if (type == WalletType.bitcoinCash) {
await Future.wait(BITCOIN_CASH_ADDRESS_TYPES
.map((type) => fetchTransactionsForAddressType(historiesWithDetails, type)));
await fetchTransactionsForAddressType(historiesWithDetails, P2pkhAddressType.p2pkh); await fetchTransactionsForAddressType(historiesWithDetails, P2pkhAddressType.p2pkh);
} else if (type == WalletType.litecoin) { } else if (type == WalletType.litecoin) {
await fetchTransactionsForAddressType(historiesWithDetails, SegwitAddresType.p2wpkh); await Future.wait(LITECOIN_ADDRESS_TYPES
.map((type) => fetchTransactionsForAddressType(historiesWithDetails, type)));
} }
transactionHistory.transactions.values.forEach((tx) async { transactionHistory.transactions.values.forEach((tx) async {

View file

@ -11,15 +11,23 @@ part 'electrum_wallet_addresses.g.dart';
class ElectrumWalletAddresses = ElectrumWalletAddressesBase with _$ElectrumWalletAddresses; class ElectrumWalletAddresses = ElectrumWalletAddressesBase with _$ElectrumWalletAddresses;
const List<BitcoinAddressType> ADDRESS_TYPES = [ const List<BitcoinAddressType> BITCOIN_ADDRESS_TYPES = [
SegwitAddresType.p2wpkh, SegwitAddresType.p2wpkh,
P2pkhAddressType.p2pkh, P2pkhAddressType.p2pkh,
SegwitAddresType.p2tr, SegwitAddresType.p2tr,
SegwitAddresType.p2wsh, SegwitAddresType.p2wsh,
SegwitAddresType.mweb,
P2shAddressType.p2wpkhInP2sh, P2shAddressType.p2wpkhInP2sh,
]; ];
const List<BitcoinAddressType> LITECOIN_ADDRESS_TYPES = [
SegwitAddresType.p2wpkh,
SegwitAddresType.mweb,
];
const List<BitcoinAddressType> BITCOIN_CASH_ADDRESS_TYPES = [
P2pkhAddressType.p2pkh,
];
abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
ElectrumWalletAddressesBase( ElectrumWalletAddressesBase(
WalletInfo walletInfo, { WalletInfo walletInfo, {
@ -327,13 +335,6 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
}) => }) =>
''; '';
Future<String> getAddressAsync({
required int index,
required Bip32Slip10Secp256k1 hd,
BitcoinAddressType? addressType,
}) async =>
getAddress(index: index, hd: hd, addressType: addressType);
void addBitcoinAddressTypes() { void addBitcoinAddressTypes() {
final lastP2wpkh = _addresses final lastP2wpkh = _addresses
.where((addressRecord) => .where((addressRecord) =>
@ -393,6 +394,37 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
}); });
} }
void addLitecoinAddressTypes() {
final lastP2wpkh = _addresses
.where((addressRecord) =>
_isUnusedReceiveAddressByType(addressRecord, SegwitAddresType.p2wpkh))
.toList()
.last;
if (lastP2wpkh.address != address) {
addressesMap[lastP2wpkh.address] = 'P2WPKH';
} else {
addressesMap[address] = 'Active - P2WPKH';
}
final lastMweb = _addresses.firstWhere(
(addressRecord) => _isUnusedReceiveAddressByType(addressRecord, SegwitAddresType.mweb));
if (lastMweb.address != address) {
addressesMap[lastMweb.address] = 'MWEB';
} else {
addressesMap[address] = 'Active - MWEB';
}
}
void addBitcoinCashAddressTypes() {
final lastP2pkh = _addresses.firstWhere(
(addressRecord) => _isUnusedReceiveAddressByType(addressRecord, P2pkhAddressType.p2pkh));
if (lastP2pkh.address != address) {
addressesMap[lastP2pkh.address] = 'P2PKH';
} else {
addressesMap[address] = 'Active - P2PKH';
}
}
@override @override
Future<void> updateAddressesInBox() async { Future<void> updateAddressesInBox() async {
try { try {
@ -404,29 +436,18 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
allAddressesMap[addressRecord.address] = addressRecord.name; allAddressesMap[addressRecord.address] = addressRecord.name;
}); });
if (walletInfo.type == WalletType.bitcoin) { switch (walletInfo.type) {
addBitcoinAddressTypes(); case WalletType.bitcoin:
} addBitcoinAddressTypes();
break;
if (walletInfo.type == WalletType.litecoin) { case WalletType.litecoin:
final lastP2wpkh = _addresses addLitecoinAddressTypes();
.where((addressRecord) => break;
_isUnusedReceiveAddressByType(addressRecord, SegwitAddresType.p2wpkh)) case WalletType.bitcoinCash:
.toList() addBitcoinCashAddressTypes();
.last; break;
if (lastP2wpkh.address != address) { default:
addressesMap[lastP2wpkh.address] = 'P2WPKH'; break;
} else {
addressesMap[address] = 'Active - P2WPKH';
}
final lastMweb = _addresses.firstWhere(
(addressRecord) => _isUnusedReceiveAddressByType(addressRecord, SegwitAddresType.mweb));
if (lastMweb.address != address) {
addressesMap[lastMweb.address] = 'MWEB';
} else {
addressesMap[address] = 'Active - MWEB';
}
} }
await saveAddressesInBox(); await saveAddressesInBox();
@ -548,7 +569,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
for (var i = startIndex; i < count + startIndex; i++) { for (var i = startIndex; i < count + startIndex; i++) {
final address = BitcoinAddressRecord( final address = BitcoinAddressRecord(
await getAddressAsync(index: i, hd: _getHd(isHidden), addressType: type ?? addressPageType), getAddress(index: i, hd: _getHd(isHidden), addressType: type ?? addressPageType),
index: i, index: i,
isHidden: isHidden, isHidden: isHidden,
type: type ?? addressPageType, type: type ?? addressPageType,

View file

@ -317,11 +317,12 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
final oldBoxName = "${walletInfo.name.replaceAll(" ", "_")}_${MwebUtxo.boxName}"; final oldBoxName = "${walletInfo.name.replaceAll(" ", "_")}_${MwebUtxo.boxName}";
final newBoxName = "${newWalletName.replaceAll(" ", "_")}_${MwebUtxo.boxName}"; final newBoxName = "${newWalletName.replaceAll(" ", "_")}_${MwebUtxo.boxName}";
final oldBox = await Hive.openBox<MwebUtxo>(oldBoxName); final oldBox = await CakeHive.openBox<MwebUtxo>(oldBoxName);
mwebUtxosBox = await CakeHive.openBox<MwebUtxo>(newBoxName); mwebUtxosBox = await CakeHive.openBox<MwebUtxo>(newBoxName);
for (final key in oldBox.keys) { for (final key in oldBox.keys) {
await mwebUtxosBox.put(key, oldBox.get(key)!); await mwebUtxosBox.put(key, oldBox.get(key)!);
} }
oldBox.deleteFromDisk();
await super.renameWalletFiles(newWalletName); await super.renameWalletFiles(newWalletName);
} }

View file

@ -1,10 +1,10 @@
import 'dart:io'; import 'dart:io';
import 'package:cw_bitcoin/bitcoin_mnemonics_bip39.dart'; import 'package:cw_bitcoin/bitcoin_mnemonics_bip39.dart';
import 'package:cw_bitcoin/mnemonic_is_incorrect_exception.dart';
import 'package:cw_core/encryption_file_utils.dart'; import 'package:cw_core/encryption_file_utils.dart';
import 'package:cw_core/unspent_coins_info.dart'; import 'package:cw_core/unspent_coins_info.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:cw_bitcoin/bitcoin_mnemonic.dart'; import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
import 'package:cw_bitcoin/mnemonic_is_incorrect_exception.dart';
import 'package:cw_bitcoin/bitcoin_wallet_creation_credentials.dart'; import 'package:cw_bitcoin/bitcoin_wallet_creation_credentials.dart';
import 'package:cw_bitcoin/litecoin_wallet.dart'; import 'package:cw_bitcoin/litecoin_wallet.dart';
import 'package:cw_core/wallet_service.dart'; import 'package:cw_core/wallet_service.dart';
@ -150,9 +150,9 @@ class LitecoinWalletService extends WalletService<
@override @override
Future<LitecoinWallet> restoreFromSeed(BitcoinRestoreWalletFromSeedCredentials credentials, Future<LitecoinWallet> restoreFromSeed(BitcoinRestoreWalletFromSeedCredentials credentials,
{bool? isTestnet}) async { {bool? isTestnet}) async {
// if (!validateMnemonic(credentials.mnemonic) && !bip39.validateMnemonic(credentials.mnemonic)) { if (!validateMnemonic(credentials.mnemonic) && !bip39.validateMnemonic(credentials.mnemonic)) {
// throw LitecoinMnemonicIsIncorrectException(); throw LitecoinMnemonicIsIncorrectException();
// } }
final wallet = await LitecoinWalletBase.create( final wallet = await LitecoinWalletBase.create(
password: credentials.password!, password: credentials.password!,

View file

@ -267,6 +267,11 @@ const bitcoinDates = {
"2023-01": 769810, "2023-01": 769810,
}; };
const Map<String, int> litecoinDates = {
// TODO: add litecoin dates
};
int getBitcoinHeightByDate({required DateTime date}) { int getBitcoinHeightByDate({required DateTime date}) {
String dateKey = '${date.year}-${date.month.toString().padLeft(2, '0')}'; String dateKey = '${date.year}-${date.month.toString().padLeft(2, '0')}';
final closestKey = bitcoinDates.keys final closestKey = bitcoinDates.keys
@ -300,6 +305,21 @@ DateTime getDateByBitcoinHeight(int height) {
return estimatedDate; return estimatedDate;
} }
int getLitecoinHeightByDate({required DateTime date}) {
String dateKey = '${date.year}-${date.month.toString().padLeft(2, '0')}';
final closestKey = litecoinDates.keys
.firstWhere((key) => formatMapKey(key).isBefore(date), orElse: () => litecoinDates.keys.last);
final beginningBlock = litecoinDates[dateKey] ?? litecoinDates[closestKey]!;
final startOfMonth = DateTime(date.year, date.month);
final daysDifference = date.difference(startOfMonth).inDays;
// approximately 6 blocks per hour, 24 hours per day
int estimatedBlocksSinceStartOfMonth = (daysDifference * 24 * 6);
return beginningBlock + estimatedBlocksSinceStartOfMonth;
}
// TODO: enhance all of this global const lists // TODO: enhance all of this global const lists
const wowDates = { const wowDates = {
"2023-12": 583048, "2023-12": 583048,

View file

@ -529,6 +529,9 @@ class CWBitcoin extends Bitcoin {
@override @override
int getHeightByDate({required DateTime date}) => getBitcoinHeightByDate(date: date); int getHeightByDate({required DateTime date}) => getBitcoinHeightByDate(date: date);
@override
int getLitecoinHeightByDate({required DateTime date}) => getLitecoinHeightByDate(date: date);
@override @override
Future<void> rescan(Object wallet, {required int height, bool? doSingleScan}) async { Future<void> rescan(Object wallet, {required int height, bool? doSingleScan}) async {
final bitcoinWallet = wallet as ElectrumWallet; final bitcoinWallet = wallet as ElectrumWallet;

View file

@ -168,8 +168,7 @@ class BlockchainHeightState extends State<BlockchainHeightWidget> {
if (date != null) { if (date != null) {
int height; int height;
if (widget.isMwebScan) { if (widget.isMwebScan) {
throw UnimplementedError(); height = bitcoin!.getLitecoinHeightByDate(date: date);
// height = bitcoin!.getMwebHeightByDate(date: date);
} else if (widget.isSilentPaymentsScan) { } else if (widget.isSilentPaymentsScan) {
height = bitcoin!.getHeightByDate(date: date); height = bitcoin!.getHeightByDate(date: date);
} else { } else {

View file

@ -10,6 +10,7 @@ DIR=$(dirname "$0")
case $APP_ANDROID_TYPE in case $APP_ANDROID_TYPE in
"monero.com") $DIR/build_monero_all.sh ;; "monero.com") $DIR/build_monero_all.sh ;;
"cakewallet") $DIR/build_monero_all.sh "cakewallet") $DIR/build_monero_all.sh
$DIR/build_haven_all.sh ;; $DIR/build_haven_all.sh
$DIR/build_mwebd.sh ;;
"haven") $DIR/build_haven_all.sh ;; "haven") $DIR/build_haven_all.sh ;;
esac esac

View file

@ -1,10 +1,13 @@
# install go > 1.23: if [[ "$1" == "--install" ]]; then
wget https://go.dev/dl/go1.23.1.linux-amd64.tar.gz # install go > 1.23:
sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.23.1.linux-amd64.tar.gz wget https://go.dev/dl/go1.23.1.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.23.1.linux-amd64.tar.gz
export PATH=$PATH:~/go/bin export PATH=$PATH:/usr/local/go/bin
go install golang.org/x/mobile/cmd/gomobile@latest export PATH=$PATH:~/go/bin
gomobile init go install golang.org/x/mobile/cmd/gomobile@latest
gomobile init
fi
# build mwebd: # build mwebd:
git clone https://github.com/ltcmweb/mwebd git clone https://github.com/ltcmweb/mwebd
cd mwebd cd mwebd

View file

@ -9,6 +9,6 @@ DIR=$(dirname "$0")
case $APP_IOS_TYPE in case $APP_IOS_TYPE in
"monero.com") $DIR/build_monero_all.sh ;; "monero.com") $DIR/build_monero_all.sh ;;
"cakewallet") $DIR/build_monero_all.sh && $DIR/build_haven.sh ;; "cakewallet") $DIR/build_monero_all.sh && $DIR/build_haven.sh && $DIR/build_mwebd.sh ;;
"haven") $DIR/build_haven_all.sh ;; "haven") $DIR/build_haven_all.sh ;;
esac esac

View file

@ -1,9 +1,12 @@
#!/bin/bash #!/bin/bash
# install go > 1.23: if [[ "$1" == "--install" ]]; then
brew install go # install go > 1.23:
export PATH=$PATH:~/go/bin brew install go
go install golang.org/x/mobile/cmd/gomobile@latest export PATH=$PATH:~/go/bin
gomobile init go install golang.org/x/mobile/cmd/gomobile@latest
gomobile init
fi
# build mwebd: # build mwebd:
git clone https://github.com/ltcmweb/mwebd git clone https://github.com/ltcmweb/mwebd
cd mwebd cd mwebd

View file

@ -214,6 +214,7 @@ abstract class Bitcoin {
{int? outputsCount, int? size}); {int? outputsCount, int? size});
int feeAmountWithFeeRate(Object wallet, int feeRate, int inputsCount, int outputsCount, {int? size}); int feeAmountWithFeeRate(Object wallet, int feeRate, int inputsCount, int outputsCount, {int? size});
int getHeightByDate({required DateTime date}); int getHeightByDate({required DateTime date});
int getLitecoinHeightByDate({required DateTime date});
Future<void> rescan(Object wallet, {required int height, bool? doSingleScan}); Future<void> rescan(Object wallet, {required int height, bool? doSingleScan});
Future<bool> getNodeIsElectrsSPEnabled(Object wallet); Future<bool> getNodeIsElectrsSPEnabled(Object wallet);
void deleteSilentPaymentAddress(Object wallet, String address); void deleteSilentPaymentAddress(Object wallet, String address);