Generate MWEB addresses

This commit is contained in:
Hector Chu 2024-04-22 11:45:16 +01:00
parent dbc005dcf3
commit 29238effdf
11 changed files with 91 additions and 28 deletions

View file

@ -7,6 +7,7 @@ class BitcoinReceivePageOption implements ReceivePageOption {
static const p2tr = BitcoinReceivePageOption._('Taproot (P2TR)');
static const p2wsh = BitcoinReceivePageOption._('Segwit (P2WSH)');
static const p2pkh = BitcoinReceivePageOption._('Legacy (P2PKH)');
static const mweb = BitcoinReceivePageOption._('MWEB');
const BitcoinReceivePageOption._(this.value);
@ -24,12 +25,19 @@ class BitcoinReceivePageOption implements ReceivePageOption {
BitcoinReceivePageOption.p2pkh
];
static const allLitecoin = [
BitcoinReceivePageOption.p2wpkh,
BitcoinReceivePageOption.mweb
];
factory BitcoinReceivePageOption.fromType(BitcoinAddressType type) {
switch (type) {
case SegwitAddresType.p2tr:
return BitcoinReceivePageOption.p2tr;
case SegwitAddresType.p2wsh:
return BitcoinReceivePageOption.p2wsh;
case SegwitAddresType.mweb:
return BitcoinReceivePageOption.mweb;
case P2pkhAddressType.p2pkh:
return BitcoinReceivePageOption.p2pkh;
case P2shAddressType.p2wpkhInP2sh:

View file

@ -1337,6 +1337,8 @@ BitcoinBaseAddress addressTypeFromStr(String address, BasedUtxoNetwork network)
return P2wshAddress.fromAddress(address: address, network: network);
} else if (P2trAddress.regex.hasMatch(address)) {
return P2trAddress.fromAddress(address: address, network: network);
} else if (MwebAddress.regex.hasMatch(address)) {
return MwebAddress.fromAddress(address: address, network: network);
} else {
return P2wpkhAddress.fromAddress(address: address, network: network);
}
@ -1351,6 +1353,8 @@ BitcoinAddressType _getScriptType(BitcoinBaseAddress type) {
return SegwitAddresType.p2wsh;
} else if (type is P2trAddress) {
return SegwitAddresType.p2tr;
} else if (type is MwebAddress) {
return SegwitAddresType.mweb;
} else {
return SegwitAddresType.p2wpkh;
}

View file

@ -16,6 +16,7 @@ const List<BitcoinAddressType> ADDRESS_TYPES = [
P2pkhAddressType.p2pkh,
SegwitAddresType.p2tr,
SegwitAddresType.p2wsh,
SegwitAddresType.mweb,
P2shAddressType.p2wpkhInP2sh,
];
@ -154,6 +155,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
await _generateInitialAddresses(type: P2pkhAddressType.p2pkh);
} else if (walletInfo.type == WalletType.litecoin) {
await _generateInitialAddresses();
await _generateInitialAddresses(type: SegwitAddresType.mweb);
} else if (walletInfo.type == WalletType.bitcoin) {
await _generateInitialAddresses();
await _generateInitialAddresses(type: P2pkhAddressType.p2pkh);
@ -217,6 +219,10 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
{required int index, required bitcoin.HDWallet hd, BitcoinAddressType? addressType}) =>
'';
Future<String> getAddressAsync(
{required int index, required bitcoin.HDWallet hd, BitcoinAddressType? addressType}) async =>
getAddress(index: index, hd: hd, addressType: addressType);
@override
Future<void> updateAddressesInBox() async {
try {
@ -328,7 +334,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
for (var i = startIndex; i < count + startIndex; i++) {
final address = BitcoinAddressRecord(
getAddress(index: i, hd: _getHd(isHidden), addressType: type ?? addressPageType),
await getAddressAsync(index: i, hd: _getHd(isHidden), addressType: type ?? addressPageType),
index: i,
isHidden: isHidden,
type: type ?? addressPageType,

View file

@ -1,8 +1,11 @@
import 'package:convert/convert.dart';
import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
import 'package:bitcoin_flutter/bitcoin_flutter.dart';
import 'package:cw_bitcoin/utils.dart';
import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_mweb/cw_mweb.dart';
import 'package:cw_mweb/mwebd.pb.dart';
import 'package:mobx/mobx.dart';
part 'litecoin_wallet_addresses.g.dart';
@ -21,8 +24,40 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
super.initialChangeAddressIndex,
}) : super(walletInfo);
List<String> mweb_addrs = [];
Future<void> topUpMweb(int index) async {
while (mweb_addrs.length - index < 1000) {
final length = mweb_addrs.length;
final scanSecret = mainHd.derive(0).privKey!;
final spendPubkey = mainHd.derive(1).pubKey!;
final stub = await CwMweb.stub();
final resp = await stub.addresses(AddressRequest(
fromIndex: length,
toIndex: index + 1000,
scanSecret: hex.decode(scanSecret),
spendPubkey: hex.decode(spendPubkey),
));
if (mweb_addrs.length == length) {
mweb_addrs.addAll(resp.address);
}
}
}
@override
String getAddress(
{required int index, required bitcoin.HDWallet hd, BitcoinAddressType? addressType}) =>
generateP2WPKHAddress(hd: hd, index: index, network: network);
String getAddress({required int index, required HDWallet hd, BitcoinAddressType? addressType}) {
if (addressType == SegwitAddresType.mweb) {
topUpMweb(index);
return hd == sideHd ? mweb_addrs[0] : mweb_addrs[index+1];
}
return generateP2WPKHAddress(hd: hd, index: index, network: network);
}
@override
Future<String> getAddressAsync({required int index, required HDWallet hd, BitcoinAddressType? addressType}) async {
if (addressType == SegwitAddresType.mweb) {
await topUpMweb(index);
}
return getAddress(index: index, hd: hd, addressType: addressType);
}
}

View file

@ -86,11 +86,9 @@ packages:
bitcoin_base:
dependency: "direct main"
description:
path: "."
ref: cake-update-v2
resolved-ref: "01d844a5f5a520a31df5254e34169af4664aa769"
url: "https://github.com/cake-tech/bitcoin_base.git"
source: git
path: "../../bitcoin_base"
relative: true
source: path
version: "4.2.0"
bitcoin_flutter:
dependency: "direct main"

View file

@ -31,9 +31,7 @@ dependencies:
unorm_dart: ^0.2.0
cryptography: ^2.0.5
bitcoin_base:
git:
url: https://github.com/cake-tech/bitcoin_base.git
ref: cake-update-v2
path: ../../bitcoin_base
blockchain_utils: ^2.1.1
cw_mweb:
path: ../cw_mweb

View file

@ -30,9 +30,7 @@ dependencies:
url: https://github.com/cake-tech/bitbox-flutter.git
ref: Add-Support-For-OP-Return-data
bitcoin_base:
git:
url: https://github.com/cake-tech/bitcoin_base.git
ref: cake-update-v2
path: ../../bitcoin_base

View file

@ -242,6 +242,8 @@ class CWBitcoin extends Bitcoin {
return SegwitAddresType.p2tr;
case BitcoinReceivePageOption.p2wsh:
return SegwitAddresType.p2wsh;
case BitcoinReceivePageOption.mweb:
return SegwitAddresType.mweb;
case BitcoinReceivePageOption.p2wpkh:
default:
return SegwitAddresType.p2wpkh;

View file

@ -219,7 +219,8 @@ class AddressPage extends BasePage {
}
break;
default:
if (addressListViewModel.type == WalletType.bitcoin) {
if (addressListViewModel.type == WalletType.bitcoin ||
addressListViewModel.type == WalletType.litecoin) {
addressListViewModel.setAddressType(bitcoin!.getBitcoinAddressType(option));
}
}

View file

@ -1,4 +1,5 @@
import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cw_bitcoin/bitcoin_receive_page_option.dart';
import 'package:cw_core/receive_page_option.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_type.dart';
@ -11,19 +12,30 @@ class ReceiveOptionViewModel = ReceiveOptionViewModelBase with _$ReceiveOptionVi
abstract class ReceiveOptionViewModelBase with Store {
ReceiveOptionViewModelBase(this._wallet, this.initialPageOption)
: selectedReceiveOption = initialPageOption ??
(_wallet.type == WalletType.bitcoin
(_wallet.type == WalletType.bitcoin ||
_wallet.type == WalletType.litecoin
? bitcoin!.getSelectedAddressType(_wallet)
: ReceivePageOption.mainnet),
_options = [] {
final walletType = _wallet.type;
_options = walletType == WalletType.haven
? [ReceivePageOption.mainnet]
: walletType == WalletType.bitcoin
? [
...bitcoin!.getBitcoinReceivePageOptions(),
...ReceivePageOptions.where((element) => element != ReceivePageOption.mainnet)
]
: ReceivePageOptions;
switch (_wallet.type) {
case WalletType.bitcoin:
_options = [
...bitcoin!.getBitcoinReceivePageOptions(),
...ReceivePageOptions.where((element) => element != ReceivePageOption.mainnet)
];
break;
case WalletType.litecoin:
_options = [
...BitcoinReceivePageOption.allLitecoin,
...ReceivePageOptions.where((element) => element != ReceivePageOption.mainnet)
];
break;
case WalletType.haven:
_options = [ReceivePageOption.mainnet];
break;
default:
_options = ReceivePageOptions;
};
}
final WalletBase _wallet;

View file

@ -404,7 +404,8 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
@action
Future<void> setAddressType(dynamic option) async {
if (wallet.type == WalletType.bitcoin) {
if (wallet.type == WalletType.bitcoin ||
wallet.type == WalletType.litecoin) {
await bitcoin!.setAddressType(wallet, option);
}
}