diff --git a/cw_bitcoin/lib/bitcoin_wallet_creation_credentials.dart b/cw_bitcoin/lib/bitcoin_wallet_creation_credentials.dart index 9be8df3884..fdd8593f54 100644 --- a/cw_bitcoin/lib/bitcoin_wallet_creation_credentials.dart +++ b/cw_bitcoin/lib/bitcoin_wallet_creation_credentials.dart @@ -66,6 +66,21 @@ class BitcoinWalletFromKeysCredentials extends WalletCredentials { final String xpub; } +class LitecoinWalletFromKeysCredentials extends WalletCredentials { + LitecoinWalletFromKeysCredentials({ + required String name, + required String password, + required this.xpub, + required this.scanSecret, + required this.spendPubkey, + WalletInfo? walletInfo, + }) : super(name: name, password: password, walletInfo: walletInfo); + + final String xpub; + final String scanSecret; + final String spendPubkey; +} + class BitcoinRestoreWalletFromHardware extends WalletCredentials { BitcoinRestoreWalletFromHardware({ required String name, diff --git a/cw_bitcoin/lib/litecoin_wallet.dart b/cw_bitcoin/lib/litecoin_wallet.dart index 7b32547b84..0b66fad2af 100644 --- a/cw_bitcoin/lib/litecoin_wallet.dart +++ b/cw_bitcoin/lib/litecoin_wallet.dart @@ -5,6 +5,7 @@ import 'package:convert/convert.dart' as convert; import 'dart:math'; import 'package:collection/collection.dart'; import 'package:crypto/crypto.dart'; +import 'package:cw_bitcoin/address_from_output.dart'; import 'package:cw_bitcoin/bitcoin_transaction_credentials.dart'; import 'package:cw_core/cake_hive.dart'; import 'package:cw_core/mweb_utxo.dart'; @@ -51,6 +52,9 @@ import 'package:bitcoin_base/src/crypto/keypair/sign_utils.dart'; import 'package:pointycastle/ecc/api.dart'; import 'package:pointycastle/ecc/curves/secp256k1.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'package:ur/cbor_lite.dart'; +import 'package:ur/ur.dart'; +import 'package:ur/ur_decoder.dart'; part 'litecoin_wallet.g.dart'; @@ -65,6 +69,8 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { Uint8List? seedBytes, String? mnemonic, String? xpub, + this.scanSecretOverride, + this.spendPubkeyOverride, String? passphrase, String? addressPageType, List? initialAddresses, @@ -93,6 +99,9 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { mwebHd = Bip32Slip10Secp256k1.fromSeed(seedBytes).derivePath("m/1000'") as Bip32Slip10Secp256k1; mwebEnabled = alwaysScan ?? false; + } else if (scanSecretOverride != null && spendPubkeyOverride != null) { + mwebHd = null; + mwebEnabled = alwaysScan ?? false; } else { mwebHd = null; mwebEnabled = false; @@ -108,6 +117,8 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { network: network, mwebHd: mwebHd, mwebEnabled: mwebEnabled, + scanSecretOverride: scanSecretOverride, + spendPubkeyOverride: spendPubkeyOverride, isHardwareWallet: walletInfo.isHardwareWallet, ); autorun((_) { @@ -159,7 +170,11 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { @override bool get hasRescan => true; - List get scanSecret => mwebHd!.childKey(Bip32KeyIndex(0x80000000)).privateKey.privKey.raw; + final String? scanSecretOverride; + final String? spendPubkeyOverride; + List get scanSecret => scanSecretOverride != null + ? hex.decode(scanSecretOverride!) + : mwebHd!.childKey(Bip32KeyIndex(0x80000000)).privateKey.privKey.raw; List get spendSecret => mwebHd!.childKey(Bip32KeyIndex(0x80000001)).privateKey.privKey.raw; static Future create( @@ -206,6 +221,10 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { ); } + @override + WalletKeysData get walletKeysData => + WalletKeysData(mnemonic: seed, xPub: xpub, passphrase: passphrase, scanSecret: scanSecretOverride, spendPubkey: spendPubkeyOverride); + static Future open({ required String name, required WalletInfo walletInfo, @@ -271,6 +290,8 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { return LitecoinWallet( mnemonic: keysData.mnemonic, xpub: keysData.xPub, + scanSecretOverride: keysData.scanSecret, + spendPubkeyOverride: keysData.spendPubkey, password: password, walletInfo: walletInfo, unspentCoinsInfo: unspentCoinsInfo, @@ -1030,7 +1051,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { final resp = await CwMweb.create(CreateRequest( rawTx: txb.buildTransaction((a, b, c, d) => '').toBytes(), scanSecret: scanSecret, - spendSecret: spendSecret, + spendSecret: List.filled(32, 0), feeRatePerKb: Int64(feeRate * 1000), dryRun: true)); final tx = BtcTransaction.fromRaw(hex.encode(resp.rawTx)); @@ -1057,6 +1078,47 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { return fee.toInt() + feeIncrease; } + Future buildPsbt(PendingBitcoinTransaction transaction, bool isMweb) async { + final List inputs = []; + final List txouts = []; + for (final utxo in transaction.utxos) { + if (utxo.utxo.scriptType != SegwitAddresType.mweb) { + inputs.add(utxo.utxo.toInput()); + txouts.add(TxOut(value: Int64(utxo.utxo.value.toInt()), + pkScript: utxo.ownerDetails.address.toScriptPubKey().toBytes())); + } + } + var resp = await CwMweb.psbtCreate(PsbtCreateRequest( + rawTx: inputs.isEmpty ? null : BtcTransaction( + inputs: inputs, + outputs: isMweb ? [] : transaction.outputs, + ).toBytes(), + witnessUtxo: txouts, + )); + for (final utxo in transaction.utxos) { + if (utxo.utxo.scriptType == SegwitAddresType.mweb) { + resp = await CwMweb.psbtAddInput(PsbtAddInputRequest( + psbtB64: resp.psbtB64, + scanSecret: scanSecret, + outputId: utxo.utxo.txHash, + addressIndex: utxo.utxo.vout, + )); + } + } + if (isMweb) for (final output in transaction.outputs) { + var address = addressFromOutputScript(output.scriptPubKey, LitecoinNetwork.mainnet); + if (output.scriptPubKey.getAddressType() == SegwitAddresType.mweb) { + address = SegwitBech32Encoder.encode("ltcmweb", 0, output.scriptPubKey.toBytes()); + } + resp = await CwMweb.psbtAddRecipient(PsbtAddRecipientRequest( + psbtB64: resp.psbtB64, + recipient: PsbtRecipient(address: address, value: Int64(output.amount.toInt())), + feeRatePerKb: Int64.parseInt(transaction.feeRate) * 1000, + )); + } + return base64.decode(resp.psbtB64); + } + @override Future createTransaction(Object credentials) async { try { @@ -1067,18 +1129,13 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { tx.changeAddressOverride = (await (walletAddresses as LitecoinWalletAddresses).getChangeAddress(coinTypeToSpendFrom: UnspentCoinType.nonMweb)) .address; + if (tx.shouldCommitUR()) { + tx.unsignedPsbt = await buildPsbt(tx, false); + } return tx; } await waitForMwebAddresses(); - final resp = await CwMweb.create(CreateRequest( - rawTx: hex.decode(tx.hex), - scanSecret: scanSecret, - spendSecret: spendSecret, - feeRatePerKb: Int64.parseInt(tx.feeRate) * 1000, - )); - final tx2 = BtcTransaction.fromRaw(hex.encode(resp.rawTx)); - // check if the transaction doesn't contain any mweb inputs or outputs: final transactionCredentials = credentials as BitcoinTransactionCredentials; @@ -1110,6 +1167,26 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { for (final utxo in tx.utxos) { if (utxo.utxo.scriptType == SegwitAddresType.mweb) { hasMwebInput = true; + + } else { + // check if any of the inputs of this transaction are hog-ex: + // this list is only non-mweb inputs: + bool isHogEx = true; + + final coin = unspentCoins + .firstWhere((coin) => coin.hash == utxo.utxo.txHash && coin.vout == utxo.utxo.vout); + + // TODO: detect actual hog-ex inputs + + if (!isHogEx) { + continue; + } + + int confirmations = coin.confirmations ?? 0; + if (confirmations < 6) { + throw Exception( + "A transaction input has less than 6 confirmations, please try again later."); + } } } @@ -1123,29 +1200,24 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { .address; if (isRegular) { tx.isMweb = false; + if (tx.shouldCommitUR()) { + tx.unsignedPsbt = await buildPsbt(tx, false); + } return tx; } - // check if any of the inputs of this transaction are hog-ex: - // this list is only non-mweb inputs: - tx2.inputs.forEach((txInput) { - bool isHogEx = true; - - final utxo = unspentCoins - .firstWhere((utxo) => utxo.hash == txInput.txId && utxo.vout == txInput.txIndex); - - // TODO: detect actual hog-ex inputs - - if (!isHogEx) { - return; - } + if (tx.shouldCommitUR()) { + tx.unsignedPsbt = await buildPsbt(tx, true); + return tx; + } - int confirmations = utxo.confirmations ?? 0; - if (confirmations < 6) { - throw Exception( - "A transaction input has less than 6 confirmations, please try again later."); - } - }); + final resp = await CwMweb.create(CreateRequest( + rawTx: hex.decode(tx.hex), + scanSecret: scanSecret, + spendSecret: spendSecret, + feeRatePerKb: Int64.parseInt(tx.feeRate) * 1000, + )); + final tx2 = BtcTransaction.fromRaw(hex.encode(resp.rawTx)); tx.hexOverride = tx2 .copyWith( @@ -1168,31 +1240,107 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { .toHex(); tx.outputAddresses = resp.outputId; - return tx - ..addListener((transaction) async { - final addresses = {}; - transaction.inputAddresses?.forEach((id) async { - final utxo = mwebUtxosBox.get(id); - // await mwebUtxosBox.delete(id); // gets deleted in checkMwebUtxosSpent - if (utxo == null) return; - // mark utxo as spent so we add it to the unconfirmed balance (as negative): - utxo.spent = true; - await mwebUtxosBox.put(id, utxo); - final addressRecord = walletAddresses.allAddresses - .firstWhere((addressRecord) => addressRecord.address == utxo.address); - if (!addresses.contains(utxo.address)) { - addresses.add(utxo.address); - } - addressRecord.balance -= utxo.value.toInt(); - }); - transaction.inputAddresses?.addAll(addresses); - printV("isPegIn: $isPegIn, isPegOut: $isPegOut"); - transaction.additionalInfo["isPegIn"] = isPegIn; - transaction.additionalInfo["isPegOut"] = isPegOut; - transactionHistory.addOne(transaction); - await updateUnspent(); - await updateBalance(); - }); + addTransactionListener(tx, [], isPegIn, isPegOut); + return tx; + } catch (e, s) { + printV(e); + printV(s); + if (e.toString().contains("commit failed")) { + printV(e); + throw Exception("Transaction commit failed (no peers responded), please try again."); + } + rethrow; + } + } + + void addTransactionListener(PendingBitcoinTransaction tx, + List inputAddresses, bool isPegIn, bool isPegOut) { + tx.addListener((transaction) async { + final addresses = {}; + transaction.inputAddresses?.addAll(inputAddresses); + transaction.inputAddresses?.forEach((id) async { + final utxo = mwebUtxosBox.get(id); + // await mwebUtxosBox.delete(id); // gets deleted in checkMwebUtxosSpent + if (utxo == null) return; + // mark utxo as spent so we add it to the unconfirmed balance (as negative): + utxo.spent = true; + await mwebUtxosBox.put(id, utxo); + final addressRecord = walletAddresses.allAddresses + .firstWhere((addressRecord) => addressRecord.address == utxo.address); + if (!addresses.contains(utxo.address)) { + addresses.add(utxo.address); + } + addressRecord.balance -= utxo.value.toInt(); + }); + transaction.inputAddresses?.addAll(addresses); + printV("isPegIn: $isPegIn, isPegOut: $isPegOut"); + transaction.additionalInfo["isPegIn"] = isPegIn; + transaction.additionalInfo["isPegOut"] = isPegOut; + transactionHistory.addOne(transaction); + await updateUnspent(); + await updateBalance(); + }); + } + + Future commitPsbtUR(List urCodes) async { + if (urCodes.isEmpty) throw Exception("No QR code got scanned"); + bool isUr = urCodes.any((str) { + return str.startsWith("ur:psbt/"); + }); + if (!isUr) return; + + final ur = URDecoder(); + for (final inp in urCodes) { + ur.receivePart(inp); + } + final result = ur.result as UR; + final psbtB64 = base64Encode(CBORDecoder(result.cbor).decodeBytes().$1); + + final resp = await CwMweb.psbtGetRecipients(PsbtGetRecipientsRequest(psbtB64: psbtB64)); + + bool hasMwebInput = false; + bool hasMwebOutput = false; + bool hasRegularOutput = false; + + for (final recipient in resp.recipient) { + if (recipient.address.contains("mweb")) { + hasMwebOutput = true; + } else { + hasRegularOutput = true; + } + } + + for (final address in resp.inputAddress) { + try { + LitecoinAddress(address); + } catch (_) { + hasMwebInput = true; + } + } + + bool isPegIn = !hasMwebInput && hasMwebOutput; + bool isPegOut = hasMwebInput && hasRegularOutput; + bool isRegular = !hasMwebInput && !hasMwebOutput; + + final resp2 = await CwMweb.psbtExtract(PsbtExtractRequest(psbtB64: psbtB64)); + + final tx = PendingBitcoinTransaction( + BtcTransaction.fromRaw(hex.encode(resp2.rawTx)), + type, + electrumClient: electrumClient, + amount: 0, + fee: resp.fee.toInt(), + feeRate: "", + network: network, + hasChange: resp.recipient.length > 1, + isMweb: !isRegular, + isViewOnly: false, + ); + tx.outputAddresses = resp2.outputId; + addTransactionListener(tx, resp.inputAddress, isPegIn, isPegOut); + + try { + await tx.commit(); } catch (e, s) { printV(e); printV(s); diff --git a/cw_bitcoin/lib/litecoin_wallet_addresses.dart b/cw_bitcoin/lib/litecoin_wallet_addresses.dart index 76228c16de..2448c3ea3d 100644 --- a/cw_bitcoin/lib/litecoin_wallet_addresses.dart +++ b/cw_bitcoin/lib/litecoin_wallet_addresses.dart @@ -28,6 +28,8 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with required super.isHardwareWallet, required this.mwebHd, required this.mwebEnabled, + required this.scanSecretOverride, + required this.spendPubkeyOverride, super.initialAddresses, super.initialMwebAddresses, super.initialRegularAddressIndex, @@ -45,9 +47,15 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with List mwebAddrs = []; bool generating = false; - List get scanSecret => mwebHd!.childKey(Bip32KeyIndex(0x80000000)).privateKey.privKey.raw; - List get spendPubkey => - mwebHd!.childKey(Bip32KeyIndex(0x80000001)).publicKey.pubKey.compressed; + final String? scanSecretOverride; + final String? spendPubkeyOverride; + + List get scanSecret => scanSecretOverride != null + ? hex.decode(scanSecretOverride!) + : mwebHd!.childKey(Bip32KeyIndex(0x80000000)).privateKey.privKey.raw; + List get spendPubkey => spendPubkeyOverride != null + ? hex.decode(spendPubkeyOverride!) + : mwebHd!.childKey(Bip32KeyIndex(0x80000001)).publicKey.pubKey.compressed; @override Future init() async { @@ -95,7 +103,7 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with // ensure mweb addresses are up to date: // This is the Case if the Litecoin Wallet is a hardware Wallet - if (mwebHd == null) return; + if (mwebHd == null && scanSecretOverride == null) return; if (mwebAddresses.length < mwebAddrs.length) { List addressRecords = mwebAddrs diff --git a/cw_bitcoin/lib/litecoin_wallet_service.dart b/cw_bitcoin/lib/litecoin_wallet_service.dart index 84056225ee..c58955f730 100644 --- a/cw_bitcoin/lib/litecoin_wallet_service.dart +++ b/cw_bitcoin/lib/litecoin_wallet_service.dart @@ -20,7 +20,7 @@ import 'package:path_provider/path_provider.dart'; class LitecoinWalletService extends WalletService< BitcoinNewWalletCredentials, BitcoinRestoreWalletFromSeedCredentials, - BitcoinRestoreWalletFromWIFCredentials, + LitecoinWalletFromKeysCredentials, BitcoinRestoreWalletFromHardware> { LitecoinWalletService( this.walletInfoSource, this.unspentCoinsInfoSource, this.isDirect); @@ -177,9 +177,25 @@ class LitecoinWalletService extends WalletService< } @override - Future restoreFromKeys(BitcoinRestoreWalletFromWIFCredentials credentials, - {bool? isTestnet}) async => - throw UnimplementedError(); + Future restoreFromKeys(LitecoinWalletFromKeysCredentials credentials, + {bool? isTestnet}) async { + final network = isTestnet == true ? LitecoinNetwork.testnet : LitecoinNetwork.mainnet; + credentials.walletInfo?.network = network.value; + + final wallet = await LitecoinWallet( + password: credentials.password!, + xpub: credentials.xpub, + scanSecretOverride: credentials.scanSecret, + spendPubkeyOverride: credentials.spendPubkey, + walletInfo: credentials.walletInfo!, + unspentCoinsInfo: unspentCoinsInfoSource, + encryptionFileUtils: encryptionFileUtilsFor(isDirect), + ); + + await wallet.save(); + await wallet.init(); + return wallet; + } @override Future restoreFromSeed(BitcoinRestoreWalletFromSeedCredentials credentials, diff --git a/cw_core/lib/wallet_keys_file.dart b/cw_core/lib/wallet_keys_file.dart index 638cdc39d1..ee25713e4c 100644 --- a/cw_core/lib/wallet_keys_file.dart +++ b/cw_core/lib/wallet_keys_file.dart @@ -98,15 +98,19 @@ class WalletKeysData { final String? altMnemonic; final String? passphrase; final String? xPub; + final String? scanSecret; + final String? spendPubkey; - WalletKeysData({this.privateKey, this.mnemonic, this.altMnemonic, this.passphrase, this.xPub}); + WalletKeysData({this.privateKey, this.mnemonic, this.altMnemonic, this.passphrase, this.xPub, this.scanSecret, this.spendPubkey}); String toJSON() => jsonEncode({ "privateKey": privateKey, "mnemonic": mnemonic, if (altMnemonic != null) "altMnemonic": altMnemonic, if (passphrase != null) "passphrase": passphrase, - if (xPub != null) "xPub": xPub + if (xPub != null) "xPub": xPub, + if (scanSecret != null) "scanSecret": scanSecret, + if (spendPubkey != null) "spendPubkey": spendPubkey, }); static WalletKeysData fromJSON(Map json) => WalletKeysData( @@ -115,5 +119,7 @@ class WalletKeysData { altMnemonic: json["altMnemonic"] as String?, passphrase: json["passphrase"] as String?, xPub: json["xPub"] as String?, + scanSecret: json["scanSecret"] as String?, + spendPubkey: json["spendPubkey"] as String?, ); } diff --git a/cw_mweb/.gitignore b/cw_mweb/.gitignore index 96486fd930..9d90768f51 100644 --- a/cw_mweb/.gitignore +++ b/cw_mweb/.gitignore @@ -28,3 +28,4 @@ migrate_working_dir/ .dart_tool/ .packages build/ +jniLibs/ diff --git a/cw_mweb/go/go.mod b/cw_mweb/go/go.mod index 36d1e464c4..e01117a281 100644 --- a/cw_mweb/go/go.mod +++ b/cw_mweb/go/go.mod @@ -1,6 +1,10 @@ module github.com/cake-tech/cake_wallet/cw_mweb/go -go 1.24.2 +go 1.24.1 + +require github.com/ltcmweb/mwebd v0.1.16 + +require github.com/ltcmweb/mwebd v0.1.16 require ( github.com/Microsoft/go-winio v0.6.2 // indirect @@ -23,10 +27,9 @@ require ( github.com/kkdai/bstream v1.0.0 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/ltcmweb/coinswapd v0.1.0 // indirect - github.com/ltcmweb/ltcd v0.25.6 // indirect + github.com/ltcmweb/ltcd v0.25.11 // indirect github.com/ltcmweb/ltcd/btcec/v2 v2.3.3 // indirect github.com/ltcmweb/ltcd/chaincfg/chainhash v1.0.3 // indirect - github.com/ltcmweb/mwebd v0.1.8 // indirect github.com/ltcmweb/neutrino v0.17.4 // indirect github.com/ltcmweb/neutrino/cache v1.1.0 // indirect github.com/ltcmweb/secp256k1 v0.1.1 // indirect @@ -37,14 +40,14 @@ require ( github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect go.etcd.io/bbolt v1.3.10 // indirect - golang.org/x/crypto v0.33.0 // indirect + golang.org/x/crypto v0.39.0 // indirect golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect - golang.org/x/net v0.35.0 // indirect - golang.org/x/sys v0.30.0 // indirect - golang.org/x/text v0.22.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240509183442-62759503f434 // indirect - google.golang.org/grpc v1.63.2 // indirect - google.golang.org/protobuf v1.34.2 // indirect + golang.org/x/net v0.41.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/text v0.26.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect + google.golang.org/grpc v1.75.0 // indirect + google.golang.org/protobuf v1.36.6 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect lukechampine.com/blake3 v1.3.0 // indirect ) diff --git a/cw_mweb/go/go.sum b/cw_mweb/go/go.sum index c973d854f5..f09c4a6ac0 100644 --- a/cw_mweb/go/go.sum +++ b/cw_mweb/go/go.sum @@ -6,12 +6,22 @@ github.com/aead/siphash v1.0.1 h1:FwHfE/T45KPKYuuSAKyyvE+oPWcaQ+CUmFW0bPlM+kg= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/alitto/pond/v2 v2.2.0 h1:hX3B1Lu4b5PjSHR+IWNRDKD0Jfw2ew8V25J7Vu5j7RM= github.com/alitto/pond/v2 v2.2.0/go.mod h1:xkjYEgQ05RSpWdfSd1nM3OVv7TBhLdy7rMp3+2Nq+yE= +github.com/bits-and-blooms/bitset v1.10.0 h1:ePXTeiPEazB5+opbv5fr8umg2R/1NlzgDsyepwsSr88= +github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= +github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 h1:R8vQdOQdZ9Y3SkEwmHoWBmX1DNXhXZqlTpq6s4tyJGc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= +github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= +github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= +github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M= +github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= +github.com/crate-crypto/go-kzg-4844 v1.0.0 h1:TsSgHwrkTKecKJ4kadtHi4b3xHW5dCFUDFnUp1TsawI= +github.com/crate-crypto/go-kzg-4844 v1.0.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= @@ -22,11 +32,25 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnN github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/decred/dcrd/lru v1.1.2 h1:KdCzlkxppuoIDGEvCGah1fZRicrDH36IipvlB1ROkFY= github.com/decred/dcrd/lru v1.1.2/go.mod h1:gEdCVgXs1/YoBvFWt7Scgknbhwik3FgVSzlnCcXL2N8= +github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA= +github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= github.com/ethereum/go-ethereum v1.14.8 h1:NgOWvXS+lauK+zFukEvi85UmmsS/OkV0N23UZ1VTIig= github.com/ethereum/go-ethereum v1.14.8/go.mod h1:TJhyuDq0JDppAkFXgqjwpdlQApywnu/m10kFPxh8vvs= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= +github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= @@ -39,14 +63,14 @@ github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuV github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/ltcmweb/coinswapd v0.1.0 h1:M6eoz4g7fDpsQeNA8wWbBh6PY1xykrihyLU44SgljeI= github.com/ltcmweb/coinswapd v0.1.0/go.mod h1:CY5cVSympaLrMO8fHWXO+e/iuPLs2L0U9daMCRTstEM= -github.com/ltcmweb/ltcd v0.25.6 h1:96aC38ZEyNVztylrBBqYnVZJ6cuF7IUvL2knhbMxs3Y= -github.com/ltcmweb/ltcd v0.25.6/go.mod h1:jQbvPfnT4bBXJKRwU5SdD9ZUopwmSvhngdjeopv2cIU= +github.com/ltcmweb/ltcd v0.25.11 h1:MI0n/9I0P2Ig+myofegrXXEvh00lY3TUqPk1akYHBxA= +github.com/ltcmweb/ltcd v0.25.11/go.mod h1:jQbvPfnT4bBXJKRwU5SdD9ZUopwmSvhngdjeopv2cIU= github.com/ltcmweb/ltcd/btcec/v2 v2.3.3 h1:gJc1ljDPCBtwBKFcC4SW44BFoJqoZzkeagndMYdqKKE= github.com/ltcmweb/ltcd/btcec/v2 v2.3.3/go.mod h1:NRr2WtpiSiSO29TkdZhbGNRA/Q16DV2eNbORf+M2ykI= github.com/ltcmweb/ltcd/chaincfg/chainhash v1.0.3 h1:CAPyzHI3bCFRrrVHZkDUR2i3Awj6l/aqAZIEi0E/nfM= github.com/ltcmweb/ltcd/chaincfg/chainhash v1.0.3/go.mod h1:zB+HhI2IbIwTGpdAhdzpm1GVX4ShcWTgN42+ar9HXrg= -github.com/ltcmweb/mwebd v0.1.8 h1:5TJgrM76H3s6kWUJ6CsU1L+DaafcAZ1edDlkyJ+GWt0= -github.com/ltcmweb/mwebd v0.1.8/go.mod h1:KPf+lXEvEMuG0NaHume0imWMb9Cvr15SNPujZO6EAv4= +github.com/ltcmweb/mwebd v0.1.16 h1:DaOIp/5TDhcDUxjvnWKHXkr6hF4LHe2bbY8I0zo7m9w= +github.com/ltcmweb/mwebd v0.1.16/go.mod h1:GEhTe4RTG4ImmzsyqCzO2NKK11U2Zgb5+leQnwY+u+4= github.com/ltcmweb/neutrino v0.17.4 h1:ZsguBvicTM5CtZDsKg+OBFuPUCKjfEJ3lRSGXPjF2oM= github.com/ltcmweb/neutrino v0.17.4/go.mod h1:KktZ+McIwHuTHe0K8JK9Wv4qgv8orkA21a0ZOU4SwJ4= github.com/ltcmweb/neutrino/cache v1.1.0 h1:C0Qn2p8ogcskRPfrBKPUayjn3m/CUJqI7otopNScvhk= @@ -58,10 +82,38 @@ github.com/ltcsuite/lnd/queue v1.1.0/go.mod h1:DJrxK2gPC2FjJAVYxPOcnY2CplI3rhL2P github.com/ltcsuite/lnd/ticker v1.0.1/go.mod h1:WZKpekfDVAVv7Gsrr0GAWC/U1XURfGesFg9sQYJbeL4= github.com/ltcsuite/lnd/ticker v1.1.0 h1:3zYM/JlKNqq+DotW8jiEdHVeY5Yl7n7cUb2bTof1yXM= github.com/ltcsuite/lnd/ticker v1.1.0/go.mod h1:K2qQ3EPe8enztYvn/VAbLafCPy13XHMuCRPsySoAbt8= +github.com/ltcsuite/ltcd v0.22.0-beta h1:jYVHOeg2oBDvsduV26LtCZnzwifMDWoVbkdHTjGvHTk= +github.com/ltcsuite/ltcd v0.22.0-beta/go.mod h1:/BXtm50r591uMfXf8XgSpL5er32HCvheJtBSPYK5bFM= +github.com/ltcsuite/ltcd/btcec/v2 v2.1.0 h1:0DMWBjQDb0V1+4kCLOJlNdHs7ewwYturuUfLHq8mosY= +github.com/ltcsuite/ltcd/btcec/v2 v2.1.0/go.mod h1:Vc9ZYXMcl5D6bA0VwMvGRDJYggO3YZ7/BuIri02Lq0E= +github.com/ltcsuite/ltcd/ltcutil v1.1.0 h1:btwbdHO9cEr22zW/vgCLiF6ghh+IDngJdJsyhJ6mntU= +github.com/ltcsuite/ltcd/ltcutil v1.1.0/go.mod h1:VbZlcopVgQteiCC5KRjIuxXH5wi1CtzhsvoYZ3K7FaE= +github.com/ltcsuite/ltcwallet v0.13.1 h1:XMyrDHn0BmgUgkNbR/Lzg36vjRsup3xdiPLSD471UMg= +github.com/ltcsuite/ltcwallet v0.13.1/go.mod h1:e6pIWRM9gsd5JnMsI9SgCJM0wi7awWdr20F1C1KUPiw= +github.com/ltcsuite/ltcwallet/wallet/txauthor v1.1.0 h1:MaSgMq7LCB+6dVm9oLzNCVp0lmY1WKmevmMK/t2c6To= +github.com/ltcsuite/ltcwallet/wallet/txauthor v1.1.0/go.mod h1:I53YELeELfA+dVporL+t44O8ArpuF8AjdJbbWIQaE2Q= +github.com/ltcsuite/ltcwallet/wallet/txrules v1.2.0 h1:P6H9zsMpBBuGOsp9lnil7XfPaPujDqrbcmkqvDdiSiI= +github.com/ltcsuite/ltcwallet/wallet/txrules v1.2.0/go.mod h1:lmA2Ozxvbr2M8Mqb6ugOv5/FQT6x2Qnwg3yT/NiWEks= +github.com/ltcsuite/ltcwallet/wallet/txsizes v1.1.0 h1:W884jMwG3K3Hu8FEMnV7KX1bd4HQd/4yvaevisFo9s8= +github.com/ltcsuite/ltcwallet/wallet/txsizes v1.1.0/go.mod h1:G9+XTWnE0xaXzHRzTuP+SOIXFPXFMfYF+w/wxPHb0K8= github.com/ltcsuite/ltcwallet/walletdb v1.3.5 h1:WymVw0FBQ8KJgH7B88ujRqBOJ9R0en9K9urpJW4atAE= github.com/ltcsuite/ltcwallet/walletdb v1.3.5/go.mod h1:29SBzxA55wNxY3ctFw6t5PgsULwf3NMwg2MiGQgtrJE= +github.com/ltcsuite/neutrino v0.13.2 h1:SDbRn4zt4e6z/4uVkVzVeKYpgXyoAh8ksA3m/uCIBaU= +github.com/ltcsuite/neutrino v0.13.2/go.mod h1:eTkaETZBeu3es/FisfjY8Cp3M2fC4s+2V2VUeS8O1Ic= +github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= +github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4= +github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= @@ -69,29 +121,51 @@ github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9f go.etcd.io/bbolt v1.3.5-0.20200615073812-232d8fc87f50/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/bbolt v1.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0= go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ= -golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= -golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= +go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= +go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= +go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= +go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI= +go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg= +go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc= +go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps= +go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= +go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= +golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= +golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= -golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= -golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= +golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= +golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= +golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240509183442-62759503f434 h1:umK/Ey0QEzurTNlsV3R+MfxHAb78HCEX/IkuR+zH4WQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240509183442-62759503f434/go.mod h1:I7Y+G38R2bu5j1aLzfFmQfTcU/WnFuqDwLZAbvKTKpM= -google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= -google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4= +google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE= lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= +rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= +rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= diff --git a/cw_mweb/go/mweb.go b/cw_mweb/go/mweb.go index 0fc2d3a9a2..46e1bee1e7 100644 --- a/cw_mweb/go/mweb.go +++ b/cw_mweb/go/mweb.go @@ -10,7 +10,7 @@ import ( var server *mwebd.Server //export StartServer -func StartServer(chain *C.char, dataDir *C.char, nodeUri *C.char) C.int { +func StartServer(chain *C.char, dataDir *C.char, nodeUri *C.char, errMsg **C.char) C.int { if server != nil { server.Stop() } @@ -21,15 +21,17 @@ func StartServer(chain *C.char, dataDir *C.char, nodeUri *C.char) C.int { var err error server, err = mwebd.NewServer(goChain, goDataDir, goNodeUri) if err != nil { + *errMsg = C.CString(err.Error()) return 0 } - start, err := server.Start(0) + err = server.StartUnix(goDataDir + "/mwebd.sock") if err != nil { + *errMsg = C.CString(err.Error()) return 0 } - return C.int(start) + return 1 } //export StopServer diff --git a/cw_mweb/lib/cw_mweb.dart b/cw_mweb/lib/cw_mweb.dart index bcd1827148..681ffe79ba 100644 --- a/cw_mweb/lib/cw_mweb.dart +++ b/cw_mweb/lib/cw_mweb.dart @@ -4,8 +4,8 @@ import 'dart:developer'; import 'dart:io'; import 'dart:typed_data'; -import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_mweb/mweb_ffi.dart'; +import 'package:cw_mweb/print_verbose.dart'; import 'package:grpc/grpc.dart'; import 'package:path_provider/path_provider.dart'; import 'mwebd.pbgrpc.dart'; @@ -64,10 +64,8 @@ class CwMweb { } printV("Attempting to connect to server on port: $_port"); - // wait for the server to finish starting up before we try to connect to it: - await Future.delayed(const Duration(seconds: 8)); - - _clientChannel = ClientChannel('127.0.0.1', port: _port!, channelShutdownHandler: () { + final address = InternetAddress("${appDir.path}/mwebd.sock", type: InternetAddressType.unix); + _clientChannel = ClientChannel(address, channelShutdownHandler: () { _rpcClient = null; printV("Channel is shutting down!"); }, @@ -219,4 +217,45 @@ class CwMweb { rethrow; } } + + static Future psbtCreate(PsbtCreateRequest request) async { + log("mweb.psbtCreate() called"); + _rpcClient = await stub(); + return await _rpcClient!.psbtCreate(request, options: CallOptions(timeout: TIMEOUT_DURATION)); + } + + static Future psbtAddInput(PsbtAddInputRequest request) async { + log("mweb.psbtAddInput() called"); + _rpcClient = await stub(); + return await _rpcClient!.psbtAddInput(request, options: CallOptions(timeout: TIMEOUT_DURATION)); + } + + static Future psbtAddRecipient(PsbtAddRecipientRequest request) async { + log("mweb.psbtAddRecipient() called"); + _rpcClient = await stub(); + return await _rpcClient!.psbtAddRecipient(request, options: CallOptions(timeout: TIMEOUT_DURATION)); + } + + static Future psbtGetRecipients(PsbtGetRecipientsRequest request) async { + log("mweb.psbtGetRecipients() called"); + _rpcClient = await stub(); + return await _rpcClient!.psbtGetRecipients(request, options: CallOptions(timeout: TIMEOUT_DURATION)); + } + + static Future psbtExtract(PsbtExtractRequest request) async { + log("mweb.psbtExtract() called"); + _rpcClient = await stub(); + return await _rpcClient!.psbtExtract(request, options: CallOptions(timeout: TIMEOUT_DURATION)); + } + static Future psbtSign(PsbtSignRequest request) async { + printV("mweb.psbtSign() called"); + _rpcClient = await stub(); + return await _rpcClient!.psbtSign(request, options: CallOptions(timeout: TIMEOUT_DURATION)); + } + + static Future psbtSignNonMweb(PsbtSignNonMwebRequest request) async { + printV("mweb.psbtSignNonMweb() called"); + _rpcClient = await stub(); + return await _rpcClient!.psbtSignNonMweb(request, options: CallOptions(timeout: TIMEOUT_DURATION)); + } } diff --git a/cw_mweb/lib/mweb_ffi.dart b/cw_mweb/lib/mweb_ffi.dart index 14f49ba91b..90e4c0308f 100644 --- a/cw_mweb/lib/mweb_ffi.dart +++ b/cw_mweb/lib/mweb_ffi.dart @@ -2,6 +2,7 @@ import 'dart:ffi'; import 'dart:io'; import 'dart:typed_data'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_mweb/generated_bindings.g.dart'; import 'package:ffi/ffi.dart'; @@ -24,12 +25,19 @@ class MWebFfi { final chain = "".toNativeUtf8().cast(); final dataDir_ = dataDir.toNativeUtf8().cast(); final nodeUri_ = nodeUri.toNativeUtf8().cast(); + final errMsgPtr = calloc>(); - final port = lib.StartServer(chain, dataDir_, nodeUri_); + final port = lib.StartServer(chain, dataDir_, nodeUri_, errMsgPtr); + if (port == 0) { + final errMsg = errMsgPtr.value.cast().toDartString(); + printV('Error starting server: $errMsg'); + calloc.free(errMsgPtr.value); + } calloc.free(chain); calloc.free(dataDir_); calloc.free(nodeUri_); + calloc.free(errMsgPtr); return port; } diff --git a/cw_mweb/lib/mwebd.pb.dart b/cw_mweb/lib/mwebd.pb.dart index d0dd486c04..faf5511c60 100644 --- a/cw_mweb/lib/mwebd.pb.dart +++ b/cw_mweb/lib/mwebd.pb.dart @@ -101,6 +101,7 @@ class StatusResponse extends $pb.GeneratedMessage { static StatusResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static StatusResponse? _defaultInstance; + /// The height of the latest block. @$pb.TagNumber(1) $core.int get blockHeaderHeight => $_getIZ(0); @$pb.TagNumber(1) @@ -110,6 +111,7 @@ class StatusResponse extends $pb.GeneratedMessage { @$pb.TagNumber(1) void clearBlockHeaderHeight() => clearField(1); + /// The height of the latest MWEB header. @$pb.TagNumber(2) $core.int get mwebHeaderHeight => $_getIZ(1); @$pb.TagNumber(2) @@ -119,6 +121,7 @@ class StatusResponse extends $pb.GeneratedMessage { @$pb.TagNumber(2) void clearMwebHeaderHeight() => clearField(2); + /// The height at which the MWEB utxo set is synced to. @$pb.TagNumber(3) $core.int get mwebUtxosHeight => $_getIZ(2); @$pb.TagNumber(3) @@ -128,6 +131,7 @@ class StatusResponse extends $pb.GeneratedMessage { @$pb.TagNumber(3) void clearMwebUtxosHeight() => clearField(3); + /// The timestamp of the latest block. @$pb.TagNumber(4) $core.int get blockTime => $_getIZ(3); @$pb.TagNumber(4) @@ -183,6 +187,10 @@ class UtxosRequest extends $pb.GeneratedMessage { static UtxosRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static UtxosRequest? _defaultInstance; + /// The block height from which to start fetching utxos from. + /// After all mined utxos have been streamed, unconfirmed and + /// newly confirmed utxos will also be streamed. If this is set + /// to 0 then all utxos belonging to the account will be fetched. @$pb.TagNumber(1) $core.int get fromHeight => $_getIZ(0); @$pb.TagNumber(1) @@ -192,6 +200,8 @@ class UtxosRequest extends $pb.GeneratedMessage { @$pb.TagNumber(1) void clearFromHeight() => clearField(1); + /// The scan secret or view key represents the account for + /// which utxos should be streamed. @$pb.TagNumber(2) $core.List<$core.int> get scanSecret => $_getN(1); @$pb.TagNumber(2) @@ -262,6 +272,7 @@ class Utxo extends $pb.GeneratedMessage { static Utxo getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static Utxo? _defaultInstance; + /// The block height of the utxo, or 0 for unconfirmed. @$pb.TagNumber(1) $core.int get height => $_getIZ(0); @$pb.TagNumber(1) @@ -271,6 +282,7 @@ class Utxo extends $pb.GeneratedMessage { @$pb.TagNumber(1) void clearHeight() => clearField(1); + /// The value of the utxo in litoshis. @$pb.TagNumber(2) $fixnum.Int64 get value => $_getI64(1); @$pb.TagNumber(2) @@ -280,6 +292,7 @@ class Utxo extends $pb.GeneratedMessage { @$pb.TagNumber(2) void clearValue() => clearField(2); + /// The MWEB address that the utxo was received on. @$pb.TagNumber(3) $core.String get address => $_getSZ(2); @$pb.TagNumber(3) @@ -289,6 +302,8 @@ class Utxo extends $pb.GeneratedMessage { @$pb.TagNumber(3) void clearAddress() => clearField(3); + /// The output ID. This functions like a transaction hash, + /// but is unique to every utxo. @$pb.TagNumber(4) $core.String get outputId => $_getSZ(3); @$pb.TagNumber(4) @@ -298,6 +313,7 @@ class Utxo extends $pb.GeneratedMessage { @$pb.TagNumber(4) void clearOutputId() => clearField(4); + /// The timestamp of the block the utxo was mined in. @$pb.TagNumber(5) $core.int get blockTime => $_getIZ(4); @$pb.TagNumber(5) @@ -363,6 +379,7 @@ class AddressRequest extends $pb.GeneratedMessage { static AddressRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static AddressRequest? _defaultInstance; + /// The starting index of the range. @$pb.TagNumber(1) $core.int get fromIndex => $_getIZ(0); @$pb.TagNumber(1) @@ -372,6 +389,8 @@ class AddressRequest extends $pb.GeneratedMessage { @$pb.TagNumber(1) void clearFromIndex() => clearField(1); + /// The ending index of the range. The result will contain all + /// addresses up to but not including this index. @$pb.TagNumber(2) $core.int get toIndex => $_getIZ(1); @$pb.TagNumber(2) @@ -381,6 +400,8 @@ class AddressRequest extends $pb.GeneratedMessage { @$pb.TagNumber(2) void clearToIndex() => clearField(2); + /// The scan secret or view key represents the account for + /// which addresses should be returned. @$pb.TagNumber(3) $core.List<$core.int> get scanSecret => $_getN(2); @$pb.TagNumber(3) @@ -390,6 +411,9 @@ class AddressRequest extends $pb.GeneratedMessage { @$pb.TagNumber(3) void clearScanSecret() => clearField(3); + /// The public key of the spend secret for the account. The spend + /// key is required for spending utxos but is also required + /// for generating addresses. @$pb.TagNumber(4) $core.List<$core.int> get spendPubkey => $_getN(3); @$pb.TagNumber(4) @@ -440,10 +464,61 @@ class AddressResponse extends $pb.GeneratedMessage { static AddressResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static AddressResponse? _defaultInstance; + /// An array of MWEB addresses within the requested range. @$pb.TagNumber(1) $core.List<$core.String> get address => $_getList(0); } +class LedgerApdu extends $pb.GeneratedMessage { + factory LedgerApdu({ + $core.List<$core.int>? data, + }) { + final $result = create(); + if (data != null) { + $result.data = data; + } + return $result; + } + LedgerApdu._() : super(); + factory LedgerApdu.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory LedgerApdu.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'LedgerApdu', createEmptyInstance: create) + ..a<$core.List<$core.int>>(1, _omitFieldNames ? '' : 'data', $pb.PbFieldType.OY) + ..hasRequiredFields = false + ; + + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + LedgerApdu clone() => LedgerApdu()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + LedgerApdu copyWith(void Function(LedgerApdu) updates) => super.copyWith((message) => updates(message as LedgerApdu)) as LedgerApdu; + + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static LedgerApdu create() => LedgerApdu._(); + LedgerApdu createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static LedgerApdu getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static LedgerApdu? _defaultInstance; + + @$pb.TagNumber(1) + $core.List<$core.int> get data => $_getN(0); + @$pb.TagNumber(1) + set data($core.List<$core.int> v) { $_setBytes(0, v); } + @$pb.TagNumber(1) + $core.bool hasData() => $_has(0); + @$pb.TagNumber(1) + void clearData() => clearField(1); +} + class SpentRequest extends $pb.GeneratedMessage { factory SpentRequest({ $core.Iterable<$core.String>? outputId, @@ -484,6 +559,7 @@ class SpentRequest extends $pb.GeneratedMessage { static SpentRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static SpentRequest? _defaultInstance; + /// An array of output IDs to perform checks for. @$pb.TagNumber(1) $core.List<$core.String> get outputId => $_getList(0); } @@ -528,6 +604,9 @@ class SpentResponse extends $pb.GeneratedMessage { static SpentResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static SpentResponse? _defaultInstance; + /// An array of the output IDs that were not found in the + /// unspent set. This means that the outputs are either + /// unconfirmed or were spent. @$pb.TagNumber(1) $core.List<$core.String> get outputId => $_getList(0); } @@ -592,6 +671,16 @@ class CreateRequest extends $pb.GeneratedMessage { static CreateRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static CreateRequest? _defaultInstance; + /// The raw bytes of the serialized transaction. This will be + /// a template where the non-MWEB inputs will remain unchanged, + /// and the MWEB inputs are specified by TxIns with the outpoint + /// hash set to the output ID of the utxo being spent, and the + /// outpoint index set to the index of the address that the utxo + /// was received on. MWEB outputs are specified by TxOuts with + /// the script pubkey set to the serialized scan and spend pubkeys + /// of the destination MWEB address. Any non-MWEB outputs will be + /// transformed into MWEB peg-outs. If the transaction doesn't + /// contain any MWEB i/o then the result will be unchanged. @$pb.TagNumber(1) $core.List<$core.int> get rawTx => $_getN(0); @$pb.TagNumber(1) @@ -601,6 +690,8 @@ class CreateRequest extends $pb.GeneratedMessage { @$pb.TagNumber(1) void clearRawTx() => clearField(1); + /// The scan secret or view key represents the account that + /// the utxos being spent belong to. @$pb.TagNumber(2) $core.List<$core.int> get scanSecret => $_getN(1); @$pb.TagNumber(2) @@ -610,6 +701,8 @@ class CreateRequest extends $pb.GeneratedMessage { @$pb.TagNumber(2) void clearScanSecret() => clearField(2); + /// The spend secret is the private key necessary for spending + /// the utxos belonging to the account. @$pb.TagNumber(3) $core.List<$core.int> get spendSecret => $_getN(2); @$pb.TagNumber(3) @@ -619,6 +712,7 @@ class CreateRequest extends $pb.GeneratedMessage { @$pb.TagNumber(3) void clearSpendSecret() => clearField(3); + /// The fee rate per KB in litoshis. @$pb.TagNumber(4) $fixnum.Int64 get feeRatePerKb => $_getI64(3); @$pb.TagNumber(4) @@ -628,6 +722,8 @@ class CreateRequest extends $pb.GeneratedMessage { @$pb.TagNumber(4) void clearFeeRatePerKb() => clearField(4); + /// Whether to skip MWEB transaction creation. This is useful + /// for fee estimation. @$pb.TagNumber(5) $core.bool get dryRun => $_getBF(4); @$pb.TagNumber(5) @@ -683,6 +779,10 @@ class CreateResponse extends $pb.GeneratedMessage { static CreateResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static CreateResponse? _defaultInstance; + /// The raw bytes of the serialized transaction. It will contain + /// a single TxOut representing the peg-in required. From this + /// it is possible to determine the addtional fee that was added + /// by the MWEB transaction. @$pb.TagNumber(1) $core.List<$core.int> get rawTx => $_getN(0); @$pb.TagNumber(1) @@ -692,26 +792,33 @@ class CreateResponse extends $pb.GeneratedMessage { @$pb.TagNumber(1) void clearRawTx() => clearField(1); + /// The output IDs of any utxos created by the transaction, + /// in the same order as in the template. @$pb.TagNumber(2) $core.List<$core.String> get outputId => $_getList(1); } -class BroadcastRequest extends $pb.GeneratedMessage { - factory BroadcastRequest({ +class PsbtCreateRequest extends $pb.GeneratedMessage { + factory PsbtCreateRequest({ $core.List<$core.int>? rawTx, + $core.Iterable? witnessUtxo, }) { final $result = create(); if (rawTx != null) { $result.rawTx = rawTx; } + if (witnessUtxo != null) { + $result.witnessUtxo.addAll(witnessUtxo); + } return $result; } - BroadcastRequest._() : super(); - factory BroadcastRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory BroadcastRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + PsbtCreateRequest._() : super(); + factory PsbtCreateRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory PsbtCreateRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); - static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'BroadcastRequest', createEmptyInstance: create) + static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'PsbtCreateRequest', createEmptyInstance: create) ..a<$core.List<$core.int>>(1, _omitFieldNames ? '' : 'rawTx', $pb.PbFieldType.OY) + ..pc(2, _omitFieldNames ? '' : 'witnessUtxo', $pb.PbFieldType.PM, subBuilder: TxOut.create) ..hasRequiredFields = false ; @@ -719,23 +826,24 @@ class BroadcastRequest extends $pb.GeneratedMessage { 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') - BroadcastRequest clone() => BroadcastRequest()..mergeFromMessage(this); + PsbtCreateRequest clone() => PsbtCreateRequest()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') - BroadcastRequest copyWith(void Function(BroadcastRequest) updates) => super.copyWith((message) => updates(message as BroadcastRequest)) as BroadcastRequest; + PsbtCreateRequest copyWith(void Function(PsbtCreateRequest) updates) => super.copyWith((message) => updates(message as PsbtCreateRequest)) as PsbtCreateRequest; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') - static BroadcastRequest create() => BroadcastRequest._(); - BroadcastRequest createEmptyInstance() => create(); - static $pb.PbList createRepeated() => $pb.PbList(); + static PsbtCreateRequest create() => PsbtCreateRequest._(); + PsbtCreateRequest createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static BroadcastRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static BroadcastRequest? _defaultInstance; + static PsbtCreateRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static PsbtCreateRequest? _defaultInstance; + /// The raw bytes of the serialized transaction. @$pb.TagNumber(1) $core.List<$core.int> get rawTx => $_getN(0); @$pb.TagNumber(1) @@ -744,24 +852,33 @@ class BroadcastRequest extends $pb.GeneratedMessage { $core.bool hasRawTx() => $_has(0); @$pb.TagNumber(1) void clearRawTx() => clearField(1); + + /// Witness utxos for each input. + @$pb.TagNumber(2) + $core.List get witnessUtxo => $_getList(1); } -class BroadcastResponse extends $pb.GeneratedMessage { - factory BroadcastResponse({ - $core.String? txid, +class TxOut extends $pb.GeneratedMessage { + factory TxOut({ + $fixnum.Int64? value, + $core.List<$core.int>? pkScript, }) { final $result = create(); - if (txid != null) { - $result.txid = txid; + if (value != null) { + $result.value = value; + } + if (pkScript != null) { + $result.pkScript = pkScript; } return $result; } - BroadcastResponse._() : super(); - factory BroadcastResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory BroadcastResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + TxOut._() : super(); + factory TxOut.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory TxOut.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); - static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'BroadcastResponse', createEmptyInstance: create) - ..aOS(1, _omitFieldNames ? '' : 'txid') + static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'TxOut', createEmptyInstance: create) + ..aInt64(1, _omitFieldNames ? '' : 'value') + ..a<$core.List<$core.int>>(2, _omitFieldNames ? '' : 'pkScript', $pb.PbFieldType.OY) ..hasRequiredFields = false ; @@ -769,33 +886,934 @@ class BroadcastResponse extends $pb.GeneratedMessage { 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') - BroadcastResponse clone() => BroadcastResponse()..mergeFromMessage(this); + TxOut clone() => TxOut()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') - BroadcastResponse copyWith(void Function(BroadcastResponse) updates) => super.copyWith((message) => updates(message as BroadcastResponse)) as BroadcastResponse; + TxOut copyWith(void Function(TxOut) updates) => super.copyWith((message) => updates(message as TxOut)) as TxOut; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') - static BroadcastResponse create() => BroadcastResponse._(); - BroadcastResponse createEmptyInstance() => create(); - static $pb.PbList createRepeated() => $pb.PbList(); + static TxOut create() => TxOut._(); + TxOut createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static BroadcastResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static BroadcastResponse? _defaultInstance; + static TxOut getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static TxOut? _defaultInstance; @$pb.TagNumber(1) - $core.String get txid => $_getSZ(0); + $fixnum.Int64 get value => $_getI64(0); @$pb.TagNumber(1) - set txid($core.String v) { $_setString(0, v); } + set value($fixnum.Int64 v) { $_setInt64(0, v); } @$pb.TagNumber(1) - $core.bool hasTxid() => $_has(0); + $core.bool hasValue() => $_has(0); @$pb.TagNumber(1) - void clearTxid() => clearField(1); + void clearValue() => clearField(1); + + @$pb.TagNumber(2) + $core.List<$core.int> get pkScript => $_getN(1); + @$pb.TagNumber(2) + set pkScript($core.List<$core.int> v) { $_setBytes(1, v); } + @$pb.TagNumber(2) + $core.bool hasPkScript() => $_has(1); + @$pb.TagNumber(2) + void clearPkScript() => clearField(2); +} + +class PsbtResponse extends $pb.GeneratedMessage { + factory PsbtResponse({ + $core.String? psbtB64, + }) { + final $result = create(); + if (psbtB64 != null) { + $result.psbtB64 = psbtB64; + } + return $result; + } + PsbtResponse._() : super(); + factory PsbtResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory PsbtResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'PsbtResponse', createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'psbtB64') + ..hasRequiredFields = false + ; + + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + PsbtResponse clone() => PsbtResponse()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + PsbtResponse copyWith(void Function(PsbtResponse) updates) => super.copyWith((message) => updates(message as PsbtResponse)) as PsbtResponse; + + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static PsbtResponse create() => PsbtResponse._(); + PsbtResponse createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static PsbtResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static PsbtResponse? _defaultInstance; + + /// The PSBT in base64 encoding. + @$pb.TagNumber(1) + $core.String get psbtB64 => $_getSZ(0); + @$pb.TagNumber(1) + set psbtB64($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasPsbtB64() => $_has(0); + @$pb.TagNumber(1) + void clearPsbtB64() => clearField(1); +} + +class PsbtAddInputRequest extends $pb.GeneratedMessage { + factory PsbtAddInputRequest({ + $core.String? psbtB64, + $core.List<$core.int>? scanSecret, + $core.String? outputId, + $core.int? addressIndex, + }) { + final $result = create(); + if (psbtB64 != null) { + $result.psbtB64 = psbtB64; + } + if (scanSecret != null) { + $result.scanSecret = scanSecret; + } + if (outputId != null) { + $result.outputId = outputId; + } + if (addressIndex != null) { + $result.addressIndex = addressIndex; + } + return $result; + } + PsbtAddInputRequest._() : super(); + factory PsbtAddInputRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory PsbtAddInputRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'PsbtAddInputRequest', createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'psbtB64') + ..a<$core.List<$core.int>>(2, _omitFieldNames ? '' : 'scanSecret', $pb.PbFieldType.OY) + ..aOS(3, _omitFieldNames ? '' : 'outputId') + ..a<$core.int>(4, _omitFieldNames ? '' : 'addressIndex', $pb.PbFieldType.OU3) + ..hasRequiredFields = false + ; + + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + PsbtAddInputRequest clone() => PsbtAddInputRequest()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + PsbtAddInputRequest copyWith(void Function(PsbtAddInputRequest) updates) => super.copyWith((message) => updates(message as PsbtAddInputRequest)) as PsbtAddInputRequest; + + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static PsbtAddInputRequest create() => PsbtAddInputRequest._(); + PsbtAddInputRequest createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static PsbtAddInputRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static PsbtAddInputRequest? _defaultInstance; + + /// The PSBT in base64 encoding. + @$pb.TagNumber(1) + $core.String get psbtB64 => $_getSZ(0); + @$pb.TagNumber(1) + set psbtB64($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasPsbtB64() => $_has(0); + @$pb.TagNumber(1) + void clearPsbtB64() => clearField(1); + + /// The scan secret or view key represents the account that + /// the utxos being spent belong to. + @$pb.TagNumber(2) + $core.List<$core.int> get scanSecret => $_getN(1); + @$pb.TagNumber(2) + set scanSecret($core.List<$core.int> v) { $_setBytes(1, v); } + @$pb.TagNumber(2) + $core.bool hasScanSecret() => $_has(1); + @$pb.TagNumber(2) + void clearScanSecret() => clearField(2); + + /// The output ID of the utxo. + @$pb.TagNumber(3) + $core.String get outputId => $_getSZ(2); + @$pb.TagNumber(3) + set outputId($core.String v) { $_setString(2, v); } + @$pb.TagNumber(3) + $core.bool hasOutputId() => $_has(2); + @$pb.TagNumber(3) + void clearOutputId() => clearField(3); + + /// The address index of the utxo. + @$pb.TagNumber(4) + $core.int get addressIndex => $_getIZ(3); + @$pb.TagNumber(4) + set addressIndex($core.int v) { $_setUnsignedInt32(3, v); } + @$pb.TagNumber(4) + $core.bool hasAddressIndex() => $_has(3); + @$pb.TagNumber(4) + void clearAddressIndex() => clearField(4); +} + +class PsbtAddRecipientRequest extends $pb.GeneratedMessage { + factory PsbtAddRecipientRequest({ + $core.String? psbtB64, + PsbtRecipient? recipient, + $fixnum.Int64? feeRatePerKb, + }) { + final $result = create(); + if (psbtB64 != null) { + $result.psbtB64 = psbtB64; + } + if (recipient != null) { + $result.recipient = recipient; + } + if (feeRatePerKb != null) { + $result.feeRatePerKb = feeRatePerKb; + } + return $result; + } + PsbtAddRecipientRequest._() : super(); + factory PsbtAddRecipientRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory PsbtAddRecipientRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'PsbtAddRecipientRequest', createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'psbtB64') + ..aOM(2, _omitFieldNames ? '' : 'recipient', subBuilder: PsbtRecipient.create) + ..a<$fixnum.Int64>(3, _omitFieldNames ? '' : 'feeRatePerKb', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO) + ..hasRequiredFields = false + ; + + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + PsbtAddRecipientRequest clone() => PsbtAddRecipientRequest()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + PsbtAddRecipientRequest copyWith(void Function(PsbtAddRecipientRequest) updates) => super.copyWith((message) => updates(message as PsbtAddRecipientRequest)) as PsbtAddRecipientRequest; + + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static PsbtAddRecipientRequest create() => PsbtAddRecipientRequest._(); + PsbtAddRecipientRequest createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static PsbtAddRecipientRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static PsbtAddRecipientRequest? _defaultInstance; + + /// The PSBT in base64 encoding. + @$pb.TagNumber(1) + $core.String get psbtB64 => $_getSZ(0); + @$pb.TagNumber(1) + set psbtB64($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasPsbtB64() => $_has(0); + @$pb.TagNumber(1) + void clearPsbtB64() => clearField(1); + + @$pb.TagNumber(2) + PsbtRecipient get recipient => $_getN(1); + @$pb.TagNumber(2) + set recipient(PsbtRecipient v) { setField(2, v); } + @$pb.TagNumber(2) + $core.bool hasRecipient() => $_has(1); + @$pb.TagNumber(2) + void clearRecipient() => clearField(2); + @$pb.TagNumber(2) + PsbtRecipient ensureRecipient() => $_ensure(1); + + /// The fee rate per KB in litoshis. + @$pb.TagNumber(3) + $fixnum.Int64 get feeRatePerKb => $_getI64(2); + @$pb.TagNumber(3) + set feeRatePerKb($fixnum.Int64 v) { $_setInt64(2, v); } + @$pb.TagNumber(3) + $core.bool hasFeeRatePerKb() => $_has(2); + @$pb.TagNumber(3) + void clearFeeRatePerKb() => clearField(3); +} + +class PsbtGetRecipientsRequest extends $pb.GeneratedMessage { + factory PsbtGetRecipientsRequest({ + $core.String? psbtB64, + }) { + final $result = create(); + if (psbtB64 != null) { + $result.psbtB64 = psbtB64; + } + return $result; + } + PsbtGetRecipientsRequest._() : super(); + factory PsbtGetRecipientsRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory PsbtGetRecipientsRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'PsbtGetRecipientsRequest', createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'psbtB64') + ..hasRequiredFields = false + ; + + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + PsbtGetRecipientsRequest clone() => PsbtGetRecipientsRequest()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + PsbtGetRecipientsRequest copyWith(void Function(PsbtGetRecipientsRequest) updates) => super.copyWith((message) => updates(message as PsbtGetRecipientsRequest)) as PsbtGetRecipientsRequest; + + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static PsbtGetRecipientsRequest create() => PsbtGetRecipientsRequest._(); + PsbtGetRecipientsRequest createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static PsbtGetRecipientsRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static PsbtGetRecipientsRequest? _defaultInstance; + + /// The PSBT in base64 encoding. + @$pb.TagNumber(1) + $core.String get psbtB64 => $_getSZ(0); + @$pb.TagNumber(1) + set psbtB64($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasPsbtB64() => $_has(0); + @$pb.TagNumber(1) + void clearPsbtB64() => clearField(1); +} + +class PsbtGetRecipientsResponse extends $pb.GeneratedMessage { + factory PsbtGetRecipientsResponse({ + $core.Iterable? recipient, + $core.Iterable<$core.String>? inputAddress, + $fixnum.Int64? fee, + }) { + final $result = create(); + if (recipient != null) { + $result.recipient.addAll(recipient); + } + if (inputAddress != null) { + $result.inputAddress.addAll(inputAddress); + } + if (fee != null) { + $result.fee = fee; + } + return $result; + } + PsbtGetRecipientsResponse._() : super(); + factory PsbtGetRecipientsResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory PsbtGetRecipientsResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'PsbtGetRecipientsResponse', createEmptyInstance: create) + ..pc(1, _omitFieldNames ? '' : 'recipient', $pb.PbFieldType.PM, subBuilder: PsbtRecipient.create) + ..pPS(2, _omitFieldNames ? '' : 'inputAddress') + ..aInt64(3, _omitFieldNames ? '' : 'fee') + ..hasRequiredFields = false + ; + + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + PsbtGetRecipientsResponse clone() => PsbtGetRecipientsResponse()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + PsbtGetRecipientsResponse copyWith(void Function(PsbtGetRecipientsResponse) updates) => super.copyWith((message) => updates(message as PsbtGetRecipientsResponse)) as PsbtGetRecipientsResponse; + + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static PsbtGetRecipientsResponse create() => PsbtGetRecipientsResponse._(); + PsbtGetRecipientsResponse createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static PsbtGetRecipientsResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static PsbtGetRecipientsResponse? _defaultInstance; + + @$pb.TagNumber(1) + $core.List get recipient => $_getList(0); + + @$pb.TagNumber(2) + $core.List<$core.String> get inputAddress => $_getList(1); + + @$pb.TagNumber(3) + $fixnum.Int64 get fee => $_getI64(2); + @$pb.TagNumber(3) + set fee($fixnum.Int64 v) { $_setInt64(2, v); } + @$pb.TagNumber(3) + $core.bool hasFee() => $_has(2); + @$pb.TagNumber(3) + void clearFee() => clearField(3); +} + +class PsbtRecipient extends $pb.GeneratedMessage { + factory PsbtRecipient({ + $core.String? address, + $fixnum.Int64? value, + }) { + final $result = create(); + if (address != null) { + $result.address = address; + } + if (value != null) { + $result.value = value; + } + return $result; + } + PsbtRecipient._() : super(); + factory PsbtRecipient.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory PsbtRecipient.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'PsbtRecipient', createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'address') + ..aInt64(2, _omitFieldNames ? '' : 'value') + ..hasRequiredFields = false + ; + + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + PsbtRecipient clone() => PsbtRecipient()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + PsbtRecipient copyWith(void Function(PsbtRecipient) updates) => super.copyWith((message) => updates(message as PsbtRecipient)) as PsbtRecipient; + + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static PsbtRecipient create() => PsbtRecipient._(); + PsbtRecipient createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static PsbtRecipient getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static PsbtRecipient? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get address => $_getSZ(0); + @$pb.TagNumber(1) + set address($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasAddress() => $_has(0); + @$pb.TagNumber(1) + void clearAddress() => clearField(1); + + @$pb.TagNumber(2) + $fixnum.Int64 get value => $_getI64(1); + @$pb.TagNumber(2) + set value($fixnum.Int64 v) { $_setInt64(1, v); } + @$pb.TagNumber(2) + $core.bool hasValue() => $_has(1); + @$pb.TagNumber(2) + void clearValue() => clearField(2); +} + +class PsbtSignRequest extends $pb.GeneratedMessage { + factory PsbtSignRequest({ + $core.String? psbtB64, + $core.List<$core.int>? scanSecret, + $core.List<$core.int>? spendSecret, + }) { + final $result = create(); + if (psbtB64 != null) { + $result.psbtB64 = psbtB64; + } + if (scanSecret != null) { + $result.scanSecret = scanSecret; + } + if (spendSecret != null) { + $result.spendSecret = spendSecret; + } + return $result; + } + PsbtSignRequest._() : super(); + factory PsbtSignRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory PsbtSignRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'PsbtSignRequest', createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'psbtB64') + ..a<$core.List<$core.int>>(2, _omitFieldNames ? '' : 'scanSecret', $pb.PbFieldType.OY) + ..a<$core.List<$core.int>>(3, _omitFieldNames ? '' : 'spendSecret', $pb.PbFieldType.OY) + ..hasRequiredFields = false + ; + + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + PsbtSignRequest clone() => PsbtSignRequest()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + PsbtSignRequest copyWith(void Function(PsbtSignRequest) updates) => super.copyWith((message) => updates(message as PsbtSignRequest)) as PsbtSignRequest; + + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static PsbtSignRequest create() => PsbtSignRequest._(); + PsbtSignRequest createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static PsbtSignRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static PsbtSignRequest? _defaultInstance; + + /// The PSBT in base64 encoding. + @$pb.TagNumber(1) + $core.String get psbtB64 => $_getSZ(0); + @$pb.TagNumber(1) + set psbtB64($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasPsbtB64() => $_has(0); + @$pb.TagNumber(1) + void clearPsbtB64() => clearField(1); + + /// The scan secret or view key represents the account that + /// the utxos being spent belong to. + @$pb.TagNumber(2) + $core.List<$core.int> get scanSecret => $_getN(1); + @$pb.TagNumber(2) + set scanSecret($core.List<$core.int> v) { $_setBytes(1, v); } + @$pb.TagNumber(2) + $core.bool hasScanSecret() => $_has(1); + @$pb.TagNumber(2) + void clearScanSecret() => clearField(2); + + /// The spend secret is the private key necessary for spending + /// the utxos belonging to the account. + @$pb.TagNumber(3) + $core.List<$core.int> get spendSecret => $_getN(2); + @$pb.TagNumber(3) + set spendSecret($core.List<$core.int> v) { $_setBytes(2, v); } + @$pb.TagNumber(3) + $core.bool hasSpendSecret() => $_has(2); + @$pb.TagNumber(3) + void clearSpendSecret() => clearField(3); +} + +class PsbtSignNonMwebRequest extends $pb.GeneratedMessage { + factory PsbtSignNonMwebRequest({ + $core.String? psbtB64, + $core.List<$core.int>? privKey, + $core.int? index, + }) { + final $result = create(); + if (psbtB64 != null) { + $result.psbtB64 = psbtB64; + } + if (privKey != null) { + $result.privKey = privKey; + } + if (index != null) { + $result.index = index; + } + return $result; + } + PsbtSignNonMwebRequest._() : super(); + factory PsbtSignNonMwebRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory PsbtSignNonMwebRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'PsbtSignNonMwebRequest', createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'psbtB64') + ..a<$core.List<$core.int>>(2, _omitFieldNames ? '' : 'privKey', $pb.PbFieldType.OY) + ..a<$core.int>(3, _omitFieldNames ? '' : 'index', $pb.PbFieldType.OU3) + ..hasRequiredFields = false + ; + + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + PsbtSignNonMwebRequest clone() => PsbtSignNonMwebRequest()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + PsbtSignNonMwebRequest copyWith(void Function(PsbtSignNonMwebRequest) updates) => super.copyWith((message) => updates(message as PsbtSignNonMwebRequest)) as PsbtSignNonMwebRequest; + + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static PsbtSignNonMwebRequest create() => PsbtSignNonMwebRequest._(); + PsbtSignNonMwebRequest createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static PsbtSignNonMwebRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static PsbtSignNonMwebRequest? _defaultInstance; + + /// The PSBT in base64 encoding. + @$pb.TagNumber(1) + $core.String get psbtB64 => $_getSZ(0); + @$pb.TagNumber(1) + set psbtB64($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasPsbtB64() => $_has(0); + @$pb.TagNumber(1) + void clearPsbtB64() => clearField(1); + + /// The private key necessary for spending the input. + @$pb.TagNumber(2) + $core.List<$core.int> get privKey => $_getN(1); + @$pb.TagNumber(2) + set privKey($core.List<$core.int> v) { $_setBytes(1, v); } + @$pb.TagNumber(2) + $core.bool hasPrivKey() => $_has(1); + @$pb.TagNumber(2) + void clearPrivKey() => clearField(2); + + /// The index of the input to sign. + @$pb.TagNumber(3) + $core.int get index => $_getIZ(2); + @$pb.TagNumber(3) + set index($core.int v) { $_setUnsignedInt32(2, v); } + @$pb.TagNumber(3) + $core.bool hasIndex() => $_has(2); + @$pb.TagNumber(3) + void clearIndex() => clearField(3); +} + +class PsbtExtractRequest extends $pb.GeneratedMessage { + factory PsbtExtractRequest({ + $core.String? psbtB64, + $core.bool? unsigned, + }) { + final $result = create(); + if (psbtB64 != null) { + $result.psbtB64 = psbtB64; + } + if (unsigned != null) { + $result.unsigned = unsigned; + } + return $result; + } + PsbtExtractRequest._() : super(); + factory PsbtExtractRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory PsbtExtractRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'PsbtExtractRequest', createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'psbtB64') + ..aOB(2, _omitFieldNames ? '' : 'unsigned') + ..hasRequiredFields = false + ; + + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + PsbtExtractRequest clone() => PsbtExtractRequest()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + PsbtExtractRequest copyWith(void Function(PsbtExtractRequest) updates) => super.copyWith((message) => updates(message as PsbtExtractRequest)) as PsbtExtractRequest; + + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static PsbtExtractRequest create() => PsbtExtractRequest._(); + PsbtExtractRequest createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static PsbtExtractRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static PsbtExtractRequest? _defaultInstance; + + /// The PSBT in base64 encoding. + @$pb.TagNumber(1) + $core.String get psbtB64 => $_getSZ(0); + @$pb.TagNumber(1) + set psbtB64($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasPsbtB64() => $_has(0); + @$pb.TagNumber(1) + void clearPsbtB64() => clearField(1); + + /// Extract the unsigned transaction. + @$pb.TagNumber(2) + $core.bool get unsigned => $_getBF(1); + @$pb.TagNumber(2) + set unsigned($core.bool v) { $_setBool(1, v); } + @$pb.TagNumber(2) + $core.bool hasUnsigned() => $_has(1); + @$pb.TagNumber(2) + void clearUnsigned() => clearField(2); +} + +class BroadcastRequest extends $pb.GeneratedMessage { + factory BroadcastRequest({ + $core.List<$core.int>? rawTx, + }) { + final $result = create(); + if (rawTx != null) { + $result.rawTx = rawTx; + } + return $result; + } + BroadcastRequest._() : super(); + factory BroadcastRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory BroadcastRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'BroadcastRequest', createEmptyInstance: create) + ..a<$core.List<$core.int>>(1, _omitFieldNames ? '' : 'rawTx', $pb.PbFieldType.OY) + ..hasRequiredFields = false + ; + + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + BroadcastRequest clone() => BroadcastRequest()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + BroadcastRequest copyWith(void Function(BroadcastRequest) updates) => super.copyWith((message) => updates(message as BroadcastRequest)) as BroadcastRequest; + + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static BroadcastRequest create() => BroadcastRequest._(); + BroadcastRequest createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static BroadcastRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static BroadcastRequest? _defaultInstance; + + /// The raw bytes of the serialized transaction. + @$pb.TagNumber(1) + $core.List<$core.int> get rawTx => $_getN(0); + @$pb.TagNumber(1) + set rawTx($core.List<$core.int> v) { $_setBytes(0, v); } + @$pb.TagNumber(1) + $core.bool hasRawTx() => $_has(0); + @$pb.TagNumber(1) + void clearRawTx() => clearField(1); +} + +class BroadcastResponse extends $pb.GeneratedMessage { + factory BroadcastResponse({ + $core.String? txid, + }) { + final $result = create(); + if (txid != null) { + $result.txid = txid; + } + return $result; + } + BroadcastResponse._() : super(); + factory BroadcastResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory BroadcastResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'BroadcastResponse', createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'txid') + ..hasRequiredFields = false + ; + + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + BroadcastResponse clone() => BroadcastResponse()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + BroadcastResponse copyWith(void Function(BroadcastResponse) updates) => super.copyWith((message) => updates(message as BroadcastResponse)) as BroadcastResponse; + + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static BroadcastResponse create() => BroadcastResponse._(); + BroadcastResponse createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static BroadcastResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static BroadcastResponse? _defaultInstance; + + /// The transaction ID. + @$pb.TagNumber(1) + $core.String get txid => $_getSZ(0); + @$pb.TagNumber(1) + set txid($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasTxid() => $_has(0); + @$pb.TagNumber(1) + void clearTxid() => clearField(1); +} + +class CoinswapRequest extends $pb.GeneratedMessage { + factory CoinswapRequest({ + $core.List<$core.int>? scanSecret, + $core.List<$core.int>? spendSecret, + $core.String? outputId, + $core.int? addrIndex, + }) { + final $result = create(); + if (scanSecret != null) { + $result.scanSecret = scanSecret; + } + if (spendSecret != null) { + $result.spendSecret = spendSecret; + } + if (outputId != null) { + $result.outputId = outputId; + } + if (addrIndex != null) { + $result.addrIndex = addrIndex; + } + return $result; + } + CoinswapRequest._() : super(); + factory CoinswapRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory CoinswapRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'CoinswapRequest', createEmptyInstance: create) + ..a<$core.List<$core.int>>(1, _omitFieldNames ? '' : 'scanSecret', $pb.PbFieldType.OY) + ..a<$core.List<$core.int>>(2, _omitFieldNames ? '' : 'spendSecret', $pb.PbFieldType.OY) + ..aOS(3, _omitFieldNames ? '' : 'outputId') + ..a<$core.int>(4, _omitFieldNames ? '' : 'addrIndex', $pb.PbFieldType.OU3) + ..hasRequiredFields = false + ; + + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + CoinswapRequest clone() => CoinswapRequest()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + CoinswapRequest copyWith(void Function(CoinswapRequest) updates) => super.copyWith((message) => updates(message as CoinswapRequest)) as CoinswapRequest; + + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static CoinswapRequest create() => CoinswapRequest._(); + CoinswapRequest createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static CoinswapRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static CoinswapRequest? _defaultInstance; + + /// The scan secret or view key represents the account that + /// the utxo belongs to. + @$pb.TagNumber(1) + $core.List<$core.int> get scanSecret => $_getN(0); + @$pb.TagNumber(1) + set scanSecret($core.List<$core.int> v) { $_setBytes(0, v); } + @$pb.TagNumber(1) + $core.bool hasScanSecret() => $_has(0); + @$pb.TagNumber(1) + void clearScanSecret() => clearField(1); + + /// The spend secret is the private key necessary for spending + /// the utxos belonging to the account. + @$pb.TagNumber(2) + $core.List<$core.int> get spendSecret => $_getN(1); + @$pb.TagNumber(2) + set spendSecret($core.List<$core.int> v) { $_setBytes(1, v); } + @$pb.TagNumber(2) + $core.bool hasSpendSecret() => $_has(1); + @$pb.TagNumber(2) + void clearSpendSecret() => clearField(2); + + /// Output ID of the utxo to request a coinswap for. + @$pb.TagNumber(3) + $core.String get outputId => $_getSZ(2); + @$pb.TagNumber(3) + set outputId($core.String v) { $_setString(2, v); } + @$pb.TagNumber(3) + $core.bool hasOutputId() => $_has(2); + @$pb.TagNumber(3) + void clearOutputId() => clearField(3); + + /// Address index of the utxo. + @$pb.TagNumber(4) + $core.int get addrIndex => $_getIZ(3); + @$pb.TagNumber(4) + set addrIndex($core.int v) { $_setUnsignedInt32(3, v); } + @$pb.TagNumber(4) + $core.bool hasAddrIndex() => $_has(3); + @$pb.TagNumber(4) + void clearAddrIndex() => clearField(4); +} + +class CoinswapResponse extends $pb.GeneratedMessage { + factory CoinswapResponse({ + $core.String? outputId, + }) { + final $result = create(); + if (outputId != null) { + $result.outputId = outputId; + } + return $result; + } + CoinswapResponse._() : super(); + factory CoinswapResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory CoinswapResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'CoinswapResponse', createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'outputId') + ..hasRequiredFields = false + ; + + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + CoinswapResponse clone() => CoinswapResponse()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + CoinswapResponse copyWith(void Function(CoinswapResponse) updates) => super.copyWith((message) => updates(message as CoinswapResponse)) as CoinswapResponse; + + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static CoinswapResponse create() => CoinswapResponse._(); + CoinswapResponse createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static CoinswapResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static CoinswapResponse? _defaultInstance; + + /// Output ID of the utxo created by the transaction. + @$pb.TagNumber(1) + $core.String get outputId => $_getSZ(0); + @$pb.TagNumber(1) + set outputId($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasOutputId() => $_has(0); + @$pb.TagNumber(1) + void clearOutputId() => clearField(1); } const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names'); -const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names'); +const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names'); \ No newline at end of file diff --git a/cw_mweb/lib/mwebd.pbgrpc.dart b/cw_mweb/lib/mwebd.pbgrpc.dart index 6bc48cfdfe..b5a2852f79 100644 --- a/cw_mweb/lib/mwebd.pbgrpc.dart +++ b/cw_mweb/lib/mwebd.pbgrpc.dart @@ -41,10 +41,46 @@ class RpcClient extends $grpc.Client { '/Rpc/Create', ($0.CreateRequest value) => value.writeToBuffer(), ($core.List<$core.int> value) => $0.CreateResponse.fromBuffer(value)); + static final _$psbtCreate = $grpc.ClientMethod<$0.PsbtCreateRequest, $0.PsbtResponse>( + '/Rpc/PsbtCreate', + ($0.PsbtCreateRequest value) => value.writeToBuffer(), + ($core.List<$core.int> value) => $0.PsbtResponse.fromBuffer(value)); + static final _$psbtAddInput = $grpc.ClientMethod<$0.PsbtAddInputRequest, $0.PsbtResponse>( + '/Rpc/PsbtAddInput', + ($0.PsbtAddInputRequest value) => value.writeToBuffer(), + ($core.List<$core.int> value) => $0.PsbtResponse.fromBuffer(value)); + static final _$psbtAddRecipient = $grpc.ClientMethod<$0.PsbtAddRecipientRequest, $0.PsbtResponse>( + '/Rpc/PsbtAddRecipient', + ($0.PsbtAddRecipientRequest value) => value.writeToBuffer(), + ($core.List<$core.int> value) => $0.PsbtResponse.fromBuffer(value)); + static final _$psbtGetRecipients = $grpc.ClientMethod<$0.PsbtGetRecipientsRequest, $0.PsbtGetRecipientsResponse>( + '/Rpc/PsbtGetRecipients', + ($0.PsbtGetRecipientsRequest value) => value.writeToBuffer(), + ($core.List<$core.int> value) => $0.PsbtGetRecipientsResponse.fromBuffer(value)); + static final _$psbtSign = $grpc.ClientMethod<$0.PsbtSignRequest, $0.PsbtResponse>( + '/Rpc/PsbtSign', + ($0.PsbtSignRequest value) => value.writeToBuffer(), + ($core.List<$core.int> value) => $0.PsbtResponse.fromBuffer(value)); + static final _$psbtSignNonMweb = $grpc.ClientMethod<$0.PsbtSignNonMwebRequest, $0.PsbtResponse>( + '/Rpc/PsbtSignNonMweb', + ($0.PsbtSignNonMwebRequest value) => value.writeToBuffer(), + ($core.List<$core.int> value) => $0.PsbtResponse.fromBuffer(value)); + static final _$psbtExtract = $grpc.ClientMethod<$0.PsbtExtractRequest, $0.CreateResponse>( + '/Rpc/PsbtExtract', + ($0.PsbtExtractRequest value) => value.writeToBuffer(), + ($core.List<$core.int> value) => $0.CreateResponse.fromBuffer(value)); + static final _$ledgerExchange = $grpc.ClientMethod<$0.LedgerApdu, $0.LedgerApdu>( + '/Rpc/LedgerExchange', + ($0.LedgerApdu value) => value.writeToBuffer(), + ($core.List<$core.int> value) => $0.LedgerApdu.fromBuffer(value)); static final _$broadcast = $grpc.ClientMethod<$0.BroadcastRequest, $0.BroadcastResponse>( '/Rpc/Broadcast', ($0.BroadcastRequest value) => value.writeToBuffer(), ($core.List<$core.int> value) => $0.BroadcastResponse.fromBuffer(value)); + static final _$coinswap = $grpc.ClientMethod<$0.CoinswapRequest, $0.CoinswapResponse>( + '/Rpc/Coinswap', + ($0.CoinswapRequest value) => value.writeToBuffer(), + ($core.List<$core.int> value) => $0.CoinswapResponse.fromBuffer(value)); RpcClient($grpc.ClientChannel channel, {$grpc.CallOptions? options, @@ -72,9 +108,45 @@ class RpcClient extends $grpc.Client { return $createUnaryCall(_$create, request, options: options); } + $grpc.ResponseFuture<$0.PsbtResponse> psbtCreate($0.PsbtCreateRequest request, {$grpc.CallOptions? options}) { + return $createUnaryCall(_$psbtCreate, request, options: options); + } + + $grpc.ResponseFuture<$0.PsbtResponse> psbtAddInput($0.PsbtAddInputRequest request, {$grpc.CallOptions? options}) { + return $createUnaryCall(_$psbtAddInput, request, options: options); + } + + $grpc.ResponseFuture<$0.PsbtResponse> psbtAddRecipient($0.PsbtAddRecipientRequest request, {$grpc.CallOptions? options}) { + return $createUnaryCall(_$psbtAddRecipient, request, options: options); + } + + $grpc.ResponseFuture<$0.PsbtGetRecipientsResponse> psbtGetRecipients($0.PsbtGetRecipientsRequest request, {$grpc.CallOptions? options}) { + return $createUnaryCall(_$psbtGetRecipients, request, options: options); + } + + $grpc.ResponseFuture<$0.PsbtResponse> psbtSign($0.PsbtSignRequest request, {$grpc.CallOptions? options}) { + return $createUnaryCall(_$psbtSign, request, options: options); + } + + $grpc.ResponseFuture<$0.PsbtResponse> psbtSignNonMweb($0.PsbtSignNonMwebRequest request, {$grpc.CallOptions? options}) { + return $createUnaryCall(_$psbtSignNonMweb, request, options: options); + } + + $grpc.ResponseFuture<$0.CreateResponse> psbtExtract($0.PsbtExtractRequest request, {$grpc.CallOptions? options}) { + return $createUnaryCall(_$psbtExtract, request, options: options); + } + + $grpc.ResponseFuture<$0.LedgerApdu> ledgerExchange($0.LedgerApdu request, {$grpc.CallOptions? options}) { + return $createUnaryCall(_$ledgerExchange, request, options: options); + } + $grpc.ResponseFuture<$0.BroadcastResponse> broadcast($0.BroadcastRequest request, {$grpc.CallOptions? options}) { return $createUnaryCall(_$broadcast, request, options: options); } + + $grpc.ResponseFuture<$0.CoinswapResponse> coinswap($0.CoinswapRequest request, {$grpc.CallOptions? options}) { + return $createUnaryCall(_$coinswap, request, options: options); + } } @$pb.GrpcServiceName('Rpc') @@ -117,6 +189,62 @@ abstract class RpcServiceBase extends $grpc.Service { false, ($core.List<$core.int> value) => $0.CreateRequest.fromBuffer(value), ($0.CreateResponse value) => value.writeToBuffer())); + $addMethod($grpc.ServiceMethod<$0.PsbtCreateRequest, $0.PsbtResponse>( + 'PsbtCreate', + psbtCreate_Pre, + false, + false, + ($core.List<$core.int> value) => $0.PsbtCreateRequest.fromBuffer(value), + ($0.PsbtResponse value) => value.writeToBuffer())); + $addMethod($grpc.ServiceMethod<$0.PsbtAddInputRequest, $0.PsbtResponse>( + 'PsbtAddInput', + psbtAddInput_Pre, + false, + false, + ($core.List<$core.int> value) => $0.PsbtAddInputRequest.fromBuffer(value), + ($0.PsbtResponse value) => value.writeToBuffer())); + $addMethod($grpc.ServiceMethod<$0.PsbtAddRecipientRequest, $0.PsbtResponse>( + 'PsbtAddRecipient', + psbtAddRecipient_Pre, + false, + false, + ($core.List<$core.int> value) => $0.PsbtAddRecipientRequest.fromBuffer(value), + ($0.PsbtResponse value) => value.writeToBuffer())); + $addMethod($grpc.ServiceMethod<$0.PsbtGetRecipientsRequest, $0.PsbtGetRecipientsResponse>( + 'PsbtGetRecipients', + psbtGetRecipients_Pre, + false, + false, + ($core.List<$core.int> value) => $0.PsbtGetRecipientsRequest.fromBuffer(value), + ($0.PsbtGetRecipientsResponse value) => value.writeToBuffer())); + $addMethod($grpc.ServiceMethod<$0.PsbtSignRequest, $0.PsbtResponse>( + 'PsbtSign', + psbtSign_Pre, + false, + false, + ($core.List<$core.int> value) => $0.PsbtSignRequest.fromBuffer(value), + ($0.PsbtResponse value) => value.writeToBuffer())); + $addMethod($grpc.ServiceMethod<$0.PsbtSignNonMwebRequest, $0.PsbtResponse>( + 'PsbtSignNonMweb', + psbtSignNonMweb_Pre, + false, + false, + ($core.List<$core.int> value) => $0.PsbtSignNonMwebRequest.fromBuffer(value), + ($0.PsbtResponse value) => value.writeToBuffer())); + $addMethod($grpc.ServiceMethod<$0.PsbtExtractRequest, $0.CreateResponse>( + 'PsbtExtract', + psbtExtract_Pre, + false, + false, + ($core.List<$core.int> value) => $0.PsbtExtractRequest.fromBuffer(value), + ($0.CreateResponse value) => value.writeToBuffer())); + $addMethod($grpc.ServiceMethod<$0.LedgerApdu, $0.LedgerApdu>( + 'LedgerExchange', + ledgerExchange_Pre, + false, + false, + ($core.List<$core.int> value) => $0.LedgerApdu.fromBuffer(value), + ($0.LedgerApdu value) => value.writeToBuffer())); $addMethod($grpc.ServiceMethod<$0.BroadcastRequest, $0.BroadcastResponse>( 'Broadcast', broadcast_Pre, @@ -124,6 +252,13 @@ abstract class RpcServiceBase extends $grpc.Service { false, ($core.List<$core.int> value) => $0.BroadcastRequest.fromBuffer(value), ($0.BroadcastResponse value) => value.writeToBuffer())); + $addMethod($grpc.ServiceMethod<$0.CoinswapRequest, $0.CoinswapResponse>( + 'Coinswap', + coinswap_Pre, + false, + false, + ($core.List<$core.int> value) => $0.CoinswapRequest.fromBuffer(value), + ($0.CoinswapResponse value) => value.writeToBuffer())); } $async.Future<$0.StatusResponse> status_Pre($grpc.ServiceCall call, $async.Future<$0.StatusRequest> request) async { @@ -146,14 +281,59 @@ abstract class RpcServiceBase extends $grpc.Service { return create(call, await request); } + $async.Future<$0.PsbtResponse> psbtCreate_Pre($grpc.ServiceCall call, $async.Future<$0.PsbtCreateRequest> request) async { + return psbtCreate(call, await request); + } + + $async.Future<$0.PsbtResponse> psbtAddInput_Pre($grpc.ServiceCall call, $async.Future<$0.PsbtAddInputRequest> request) async { + return psbtAddInput(call, await request); + } + + $async.Future<$0.PsbtResponse> psbtAddRecipient_Pre($grpc.ServiceCall call, $async.Future<$0.PsbtAddRecipientRequest> request) async { + return psbtAddRecipient(call, await request); + } + + $async.Future<$0.PsbtGetRecipientsResponse> psbtGetRecipients_Pre($grpc.ServiceCall call, $async.Future<$0.PsbtGetRecipientsRequest> request) async { + return psbtGetRecipients(call, await request); + } + + $async.Future<$0.PsbtResponse> psbtSign_Pre($grpc.ServiceCall call, $async.Future<$0.PsbtSignRequest> request) async { + return psbtSign(call, await request); + } + + $async.Future<$0.PsbtResponse> psbtSignNonMweb_Pre($grpc.ServiceCall call, $async.Future<$0.PsbtSignNonMwebRequest> request) async { + return psbtSignNonMweb(call, await request); + } + + $async.Future<$0.CreateResponse> psbtExtract_Pre($grpc.ServiceCall call, $async.Future<$0.PsbtExtractRequest> request) async { + return psbtExtract(call, await request); + } + + $async.Future<$0.LedgerApdu> ledgerExchange_Pre($grpc.ServiceCall call, $async.Future<$0.LedgerApdu> request) async { + return ledgerExchange(call, await request); + } + $async.Future<$0.BroadcastResponse> broadcast_Pre($grpc.ServiceCall call, $async.Future<$0.BroadcastRequest> request) async { return broadcast(call, await request); } + $async.Future<$0.CoinswapResponse> coinswap_Pre($grpc.ServiceCall call, $async.Future<$0.CoinswapRequest> request) async { + return coinswap(call, await request); + } + $async.Future<$0.StatusResponse> status($grpc.ServiceCall call, $0.StatusRequest request); $async.Stream<$0.Utxo> utxos($grpc.ServiceCall call, $0.UtxosRequest request); $async.Future<$0.AddressResponse> addresses($grpc.ServiceCall call, $0.AddressRequest request); $async.Future<$0.SpentResponse> spent($grpc.ServiceCall call, $0.SpentRequest request); $async.Future<$0.CreateResponse> create($grpc.ServiceCall call, $0.CreateRequest request); + $async.Future<$0.PsbtResponse> psbtCreate($grpc.ServiceCall call, $0.PsbtCreateRequest request); + $async.Future<$0.PsbtResponse> psbtAddInput($grpc.ServiceCall call, $0.PsbtAddInputRequest request); + $async.Future<$0.PsbtResponse> psbtAddRecipient($grpc.ServiceCall call, $0.PsbtAddRecipientRequest request); + $async.Future<$0.PsbtGetRecipientsResponse> psbtGetRecipients($grpc.ServiceCall call, $0.PsbtGetRecipientsRequest request); + $async.Future<$0.PsbtResponse> psbtSign($grpc.ServiceCall call, $0.PsbtSignRequest request); + $async.Future<$0.PsbtResponse> psbtSignNonMweb($grpc.ServiceCall call, $0.PsbtSignNonMwebRequest request); + $async.Future<$0.CreateResponse> psbtExtract($grpc.ServiceCall call, $0.PsbtExtractRequest request); + $async.Future<$0.LedgerApdu> ledgerExchange($grpc.ServiceCall call, $0.LedgerApdu request); $async.Future<$0.BroadcastResponse> broadcast($grpc.ServiceCall call, $0.BroadcastRequest request); -} + $async.Future<$0.CoinswapResponse> coinswap($grpc.ServiceCall call, $0.CoinswapRequest request); +} \ No newline at end of file diff --git a/cw_mweb/lib/print_verbose.dart b/cw_mweb/lib/print_verbose.dart new file mode 100644 index 0000000000..69d4832c0c --- /dev/null +++ b/cw_mweb/lib/print_verbose.dart @@ -0,0 +1,107 @@ +import 'dart:io'; +import 'dart:math'; +import 'package:flutter/foundation.dart'; + +enum LogLevel { info, debug, warn, error } + +/// Pass an optional [file] to also write the log to a file. +void printV( + dynamic content, { + String? file, + LogLevel level = LogLevel.info, +}) { + final programInfo = CustomTrace(StackTrace.current); + final logLine = + "[${level.name.toUpperCase()}] ${programInfo.fileName}#${programInfo.lineNumber}:${programInfo.columnNumber} ${programInfo.callerFunctionName}: $content"; + + print(logLine); + + if (file != null) { + final logFile = File(file); + if (!logFile.existsSync()) { + logFile.createSync(recursive: true); + } + logFile.writeAsStringSync("$logLine\n", mode: FileMode.append, flush: true); + } +} + +// https://stackoverflow.com/a/59386101 + +class CustomTrace { + final StackTrace _trace; + + String? fileName; + String? functionName; + String? callerFunctionName; + int? lineNumber; + int? columnNumber; + + CustomTrace(this._trace) { + try { + _parseTrace(); + } catch (e) { + if (kDebugMode) print("Unable to parse trace (printV): $e"); + } + } + + String _getFunctionNameFromFrame(String frame) { + /* Just giving another nickname to the frame */ + var currentTrace = frame; + /* To get rid off the #number thing, get the index of the first whitespace */ + var indexOfWhiteSpace = currentTrace.indexOf(' '); + + /* Create a substring from the first whitespace index till the end of the string */ + var subStr = currentTrace.substring(max(0, indexOfWhiteSpace)); + + /* Grab the function name using reg expr */ + var indexOfFunction = subStr.indexOf(RegExp(r'[A-Za-z0-9_]')); + + /* Create a new substring from the function name index till the end of string */ + subStr = subStr.substring(indexOfFunction); + + indexOfWhiteSpace = subStr.indexOf(RegExp(r'[ .]')); + + /* Create a new substring from start to the first index of a whitespace. This substring gives us the function name */ + subStr = subStr.substring(0, max(0, indexOfWhiteSpace)); + + return subStr; + } + + void _parseTrace() { + /* The trace comes with multiple lines of strings, (each line is also known as a frame), so split the trace's string by lines to get all the frames */ + var frames = this._trace.toString().split("\n"); + + /* The first frame is the current function */ + this.functionName = _getFunctionNameFromFrame(frames[0]); + + /* The second frame is the caller function */ + this.callerFunctionName = _getFunctionNameFromFrame(frames[1]); + + /* The first frame has all the information we need */ + var traceString = frames[1]; + + /* Search through the string and find the index of the file name by looking for the '.dart' regex */ + var indexOfFileName = traceString.indexOf( + RegExp(r'[/A-Za-z_]+.dart'), 1); // 1 to offest and not print the printV function name + + var fileInfo = traceString.substring(max(0, indexOfFileName)); + + var listOfInfos = fileInfo.split(":"); + + /* Splitting fileInfo by the character ":" separates the file name, the line number and the column counter nicely. + Example: main.dart:5:12 + To get the file name, we split with ":" and get the first index + To get the line number, we would have to get the second index + To get the column number, we would have to get the third index + */ + try { + this.fileName = listOfInfos[0]; + this.lineNumber = int.tryParse(listOfInfos[1]); + var columnStr = listOfInfos[2]; + columnStr = columnStr.replaceFirst(")", ""); + this.columnNumber = int.tryParse(columnStr); + } catch (e) { + if (kDebugMode) print("Unable to parse trace (printV): $e"); + } + } +} diff --git a/cw_mweb/pubspec.yaml b/cw_mweb/pubspec.yaml index 300bbd590b..6fdcfec377 100644 --- a/cw_mweb/pubspec.yaml +++ b/cw_mweb/pubspec.yaml @@ -13,8 +13,6 @@ dependencies: grpc: ^4.0.1 path_provider: ^2.1.2 plugin_platform_interface: ^2.0.2 - cw_core: - path: ../cw_core ffi: ^2.1.0 dev_dependencies: diff --git a/lib/bitcoin/cw_bitcoin.dart b/lib/bitcoin/cw_bitcoin.dart index 953c88c270..48066a0f90 100644 --- a/lib/bitcoin/cw_bitcoin.dart +++ b/lib/bitcoin/cw_bitcoin.dart @@ -28,6 +28,22 @@ class CWBitcoin extends Bitcoin { BitcoinWalletFromKeysCredentials( name: name, password: password, xpub: xpub, hardwareWalletType: hardwareWalletType); + @override + WalletCredentials createLitecoinWalletFromKeys({ + required String name, + required String password, + required String xpub, + required String scanSecret, + required String spendPubkey, + }) => + LitecoinWalletFromKeysCredentials( + name: name, + password: password, + xpub: xpub, + scanSecret: scanSecret, + spendPubkey: spendPubkey, + ); + @override WalletCredentials createBitcoinRestoreWalletFromWIFCredentials( {required String name, @@ -767,6 +783,7 @@ class CWBitcoin extends Bitcoin { @override Future commitPsbtUR(Object wallet, List urCodes) { + if (wallet is LitecoinWallet) return wallet.commitPsbtUR(urCodes); final _wallet = wallet as BitcoinWalletBase; return _wallet.commitPsbtUR(urCodes); } diff --git a/lib/src/screens/restore/wallet_restore_from_keys_form.dart b/lib/src/screens/restore/wallet_restore_from_keys_form.dart index 5713ad7d0c..4d14168f9f 100644 --- a/lib/src/screens/restore/wallet_restore_from_keys_form.dart +++ b/lib/src/screens/restore/wallet_restore_from_keys_form.dart @@ -54,6 +54,12 @@ class WalletRestoreFromKeysFormState extends State { spendKeyController = restoredWallet != null ? TextEditingController(text: restoredWallet.spendKey) : TextEditingController(), + scanSecretController = restoredWallet != null + ? TextEditingController(text: restoredWallet.scanSecret) + : TextEditingController(), + spendPubkeyController = restoredWallet != null + ? TextEditingController(text: restoredWallet.spendPubkey) + : TextEditingController(), privateKeyController = restoredWallet != null ? TextEditingController(text: restoredWallet.privateKey) : TextEditingController(), @@ -68,6 +74,8 @@ class WalletRestoreFromKeysFormState extends State { final TextEditingController addressController; final TextEditingController viewKeyController; final TextEditingController spendKeyController; + final TextEditingController scanSecretController; + final TextEditingController spendPubkeyController; final TextEditingController nameTextEditingController; final TextEditingController privateKeyController; final TextEditingController? passwordTextEditingController; @@ -115,6 +123,8 @@ class WalletRestoreFromKeysFormState extends State { viewKeyController.dispose(); privateKeyController.dispose(); spendKeyController.dispose(); + scanSecretController.dispose(); + spendPubkeyController.dispose(); passwordTextEditingController?.dispose(); if (passwordListener != null) { passwordTextEditingController?.removeListener(passwordListener!); @@ -253,6 +263,22 @@ class WalletRestoreFromKeysFormState extends State { maxLines: null, ), ), + Container( + padding: EdgeInsets.only(top: 20.0), + child: BaseTextFormField( + controller: scanSecretController, + hintText: "Scan secret", + maxLines: null, + ), + ), + Container( + padding: EdgeInsets.only(top: 20.0), + child: BaseTextFormField( + controller: spendPubkeyController, + hintText: "Spend public key", + maxLines: null, + ), + ), if (widget.walletRestoreViewModel.hasBlockchainHeightSelector) BlockchainHeightWidget( key: blockchainHeightKey, diff --git a/lib/src/screens/restore/wallet_restore_page.dart b/lib/src/screens/restore/wallet_restore_page.dart index 411178c834..671cb08691 100644 --- a/lib/src/screens/restore/wallet_restore_page.dart +++ b/lib/src/screens/restore/wallet_restore_page.dart @@ -224,8 +224,12 @@ class WalletRestorePage extends BasePage { walletRestoreFromKeysFormKey.currentState!.addressController.text; credentials['spendKey'] = walletRestoreFromKeysFormKey.currentState!.spendKeyController.text; + credentials['scanSecret'] = + walletRestoreFromKeysFormKey.currentState!.scanSecretController.text; + credentials['spendPubkey'] = + walletRestoreFromKeysFormKey.currentState!.spendPubkeyController.text; credentials['height'] = - walletRestoreFromKeysFormKey.currentState!.blockchainHeightKey.currentState!.height; + walletRestoreFromKeysFormKey.currentState!.blockchainHeightKey.currentState?.height; } } } diff --git a/lib/view_model/restore/restore_wallet.dart b/lib/view_model/restore/restore_wallet.dart index 1ca8dd0cf4..98077a140b 100644 --- a/lib/view_model/restore/restore_wallet.dart +++ b/lib/view_model/restore/restore_wallet.dart @@ -12,6 +12,8 @@ class RestoredWallet { this.txId, this.spendKey, this.viewKey, + this.scanSecret, + this.spendPubkey, this.mnemonicSeed, this.passphrase, this.txAmount, @@ -26,6 +28,8 @@ class RestoredWallet { final String? txId; final String? spendKey; final String? viewKey; + final String? scanSecret; + final String? spendPubkey; final String? mnemonicSeed; final String? passphrase; final String? txAmount; @@ -56,6 +60,8 @@ class RestoredWallet { address: json['address'] as String?, spendKey: json['spend_key'] as String?, viewKey: json['view_key'] as String?, + scanSecret: json['scan_secret'] as String?, + spendPubkey: json['spend_pubkey'] as String?, height: height != null ? int.tryParse(height) ?? 0 : 0, privateKey: json['private_key'] as String?, ); diff --git a/lib/view_model/wallet_restore_view_model.dart b/lib/view_model/wallet_restore_view_model.dart index cd10d143e8..36e3ce968b 100644 --- a/lib/view_model/wallet_restore_view_model.dart +++ b/lib/view_model/wallet_restore_view_model.dart @@ -53,9 +53,9 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store { case WalletType.polygon: case WalletType.decred: case WalletType.bitcoin: + case WalletType.litecoin: availableModes = [WalletRestoreMode.seed, WalletRestoreMode.keys]; break; - case WalletType.litecoin: case WalletType.bitcoinCash: case WalletType.zano: case WalletType.none: @@ -219,6 +219,8 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store { if (mode == WalletRestoreMode.keys) { final viewKey = options['viewKey'] as String?; final spendKey = options['spendKey'] as String?; + final scanSecret = options['scanSecret'] as String?; + final spendPubkey = options['spendPubkey'] as String?; final address = options['address'] as String?; switch (type) { @@ -230,6 +232,15 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store { hardwareWalletType: hardwareWalletType, ); + case WalletType.litecoin: + return bitcoin!.createLitecoinWalletFromKeys( + name: name, + password: password, + xpub: viewKey!, + scanSecret: scanSecret!, + spendPubkey: spendPubkey!, + ); + case WalletType.monero: return monero!.createMoneroRestoreWalletFromKeysCredentials( name: name, diff --git a/scripts/android/build_mwebd.sh b/scripts/android/build_mwebd.sh index d56123afc4..abe1c5c02f 100755 --- a/scripts/android/build_mwebd.sh +++ b/scripts/android/build_mwebd.sh @@ -1,3 +1,6 @@ +#!/bin/bash +set -e -x + if [[ "$1" == "--dont-install" ]]; then echo "Skipping Go installation as per --dont-install flag" else @@ -47,4 +50,4 @@ GOARCH=arm \ CC=${NDK_BIN}/armv7a-linux-androideabi21-clang \ go build -v -buildmode=c-shared -o ${ANDROID_OUT}/armeabi-v7a/libmweb.so . cd ../ -dart run ffigen --config ffigen_config.yaml +dart run ffigen --config ffigen_config.yaml \ No newline at end of file diff --git a/scripts/android/build_torch.sh b/scripts/android/build_torch.sh index a3955b189b..31ed0849bf 100755 --- a/scripts/android/build_torch.sh +++ b/scripts/android/build_torch.sh @@ -6,4 +6,4 @@ cd "$(dirname "$0")" cd ../torch_dart -./build.sh aarch64-linux-android armv7a-linux-androideabi x86_64-linux-android \ No newline at end of file +./build.sh aarch64-linux-android armv7a-linux-androideabi x86_64-linux-android diff --git a/tool/configure.dart b/tool/configure.dart index 347eb79a29..6ef7daaa37 100644 --- a/tool/configure.dart +++ b/tool/configure.dart @@ -172,6 +172,7 @@ abstract class Bitcoin { }); WalletCredentials createBitcoinRestoreWalletFromWIFCredentials({required String name, required String password, required String wif, WalletInfo? walletInfo}); WalletCredentials createBitcoinWalletFromKeys({required String name, required String password, required String xpub, HardwareWalletType? hardwareWalletType}); + WalletCredentials createLitecoinWalletFromKeys({required String name, required String password, required String xpub, required String scanSecret, required String spendPubkey}); WalletCredentials createBitcoinNewWalletCredentials({required String name, WalletInfo? walletInfo, String? password, String? passphrase, String? mnemonic}); WalletCredentials createBitcoinHardwareWalletCredentials({required String name, required HardwareAccountData accountData, WalletInfo? walletInfo}); List getWordList();