Skip to content

Commit 6c4017b

Browse files
committed
V6.3.0
- Update dependencies. - Add estimate size for psbt - Add more script validation in psbt
1 parent 1e918a6 commit 6c4017b

17 files changed

Lines changed: 332 additions & 91 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## 6.3.0
2+
3+
- Update dependencies.
4+
- Add estimate size for psbt
5+
- Add more script validation in psbt
6+
17
## 6.2.0
28

39
- Update dependencies.

example/lib/musig/methods.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ Future<List<PsbtUtxo>> getPsbtUtxo(
7373
merkleProof: request.merkleProof,
7474
treeScript: request.treeScript,
7575
merkleRoot: request.merkleRoot,
76-
privateKeys: request.privateKeys,
7776
xOnlyOrInternalPubKey: request.xOnlyOrInternalPubKey,
7877
muSig2ParticipantPublicKeys: request.muSig2ParticipantPublicKeys,
7978
hash160: request.hash160,

lib/src/bitcoin/address/network_address.dart

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,55 @@ abstract class BitcoinNetworkAddress<T extends BasedUtxoNetwork> {
66
{required this.address,
77
required this.network,
88
required this.baseAddress});
9+
10+
static ADDRESS fromBaseAddress<ADDRESS extends BitcoinNetworkAddress>(
11+
{required BitcoinBaseAddress address,
12+
required BasedUtxoNetwork network}) {
13+
BitcoinNetworkAddress baseAddress;
14+
switch (network) {
15+
case BitcoinSVNetwork.mainnet:
16+
case BitcoinSVNetwork.testnet:
17+
baseAddress = BitcoinSVAddress.fromBaseAddress(address,
18+
network: network as BitcoinSVNetwork);
19+
case BitcoinNetwork.mainnet:
20+
case BitcoinNetwork.testnet:
21+
case BitcoinNetwork.testnet4:
22+
baseAddress = BitcoinAddress.fromBaseAddress(address,
23+
network: network as BitcoinNetwork);
24+
case LitecoinNetwork.mainnet:
25+
case LitecoinNetwork.testnet:
26+
baseAddress = LitecoinAddress.fromBaseAddress(address,
27+
network: network as LitecoinNetwork);
28+
case DashNetwork.mainnet:
29+
case DashNetwork.testnet:
30+
baseAddress = DashAddress.fromBaseAddress(address,
31+
network: network as DashNetwork);
32+
case DogecoinNetwork.mainnet:
33+
case DogecoinNetwork.testnet:
34+
baseAddress = DogeAddress.fromBaseAddress(address,
35+
network: network as DogecoinNetwork);
36+
case BitcoinCashNetwork.mainnet:
37+
case BitcoinCashNetwork.testnet:
38+
baseAddress = BitcoinCashAddress.fromBaseAddress(address,
39+
network: network as BitcoinCashNetwork);
40+
case PepeNetwork.mainnet:
41+
baseAddress = PepeAddress.fromBaseAddress(address,
42+
network: network as PepeNetwork);
43+
case ElectraProtocolNetwork.mainnet:
44+
case ElectraProtocolNetwork.testnet:
45+
baseAddress = ElectraProtocolAddress.fromBaseAddress(address,
46+
network: network as ElectraProtocolNetwork);
47+
default:
48+
throw DartBitcoinPluginException("Unknown network. ${network.value}");
49+
}
50+
if (baseAddress is! ADDRESS) {
51+
throw DartBitcoinPluginException(
52+
"Invalid cast: expected ${ADDRESS.runtimeType}, but found ${baseAddress.runtimeType}.",
53+
);
54+
}
55+
return baseAddress;
56+
}
57+
958
static ADDRESS parse<ADDRESS extends BitcoinNetworkAddress>(
1059
{required String address, required BasedUtxoNetwork network}) {
1160
BitcoinNetworkAddress baseAddress;

lib/src/bitcoin/address/utils/address_utils.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,6 @@ class _BitcoinAddressUtils {
292292
final version = decode.item2;
293293
final addrBytes = decode.item1;
294294
final scriptHex = BytesUtils.toHexString(addrBytes);
295-
296295
switch (type) {
297296
case P2pkhAddressType.p2pkh:
298297
if (BytesUtils.bytesEqual(version, network.p2pkhNetVer)) {

lib/src/bitcoin/script/output.dart

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,11 @@ class TxOutput {
2525
CashToken? cashToken}) {
2626
try {
2727
return TxOutput._(
28-
amount: amount.asUint64,
28+
amount: amount.asInt64,
2929
scriptPubKey: scriptPubKey,
3030
cashToken: cashToken);
3131
} catch (_) {
32-
throw DartBitcoinPluginException(
33-
"Invalid output amount: must be a non-negative 64-bit integer.");
32+
throw DartBitcoinPluginException("Invalid output amount.");
3433
}
3534
}
3635
final CashToken? cashToken;

lib/src/bitcoin/script/transaction.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,9 @@ class BtcTransaction {
6565
List<int>? version,
6666
}) {
6767
return BtcTransaction(
68-
inputs: inputs ?? this.inputs,
69-
outputs: outputs ?? this.outputs,
70-
witnesses: witnesses ?? this.witnesses,
68+
inputs: inputs ?? this.inputs.map((e) => e.clone()).toList(),
69+
outputs: outputs ?? this.outputs.map((e) => e.clone()).toList(),
70+
witnesses: witnesses ?? this.witnesses.map((e) => e.clone()).toList(),
7171
locktime: locktime ?? this.locktime,
7272
version: version ?? this.version);
7373
}

lib/src/bitcoin/script/utils.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,13 @@ enum ScriptPubKeyType {
2727
}
2828

2929
class BitcoinScriptUtils {
30+
static Script buildOpReturn(List<List<int>> data) {
31+
return Script(script: [
32+
BitcoinOpcode.opReturn,
33+
...data.map((e) => BytesUtils.toHexString(e))
34+
]);
35+
}
36+
3037
static bool scriptContains(
3138
{required Script script, required List<dynamic> elements}) {
3239
if (elements.length != script.script.length) return false;

lib/src/models/network.dart

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,3 +613,76 @@ class ElectraProtocolNetwork implements BasedUtxoNetwork {
613613
@override
614614
final String identifier;
615615
}
616+
617+
// class BonkcoinNetwork implements BasedUtxoNetwork {
618+
// /// Mainnet configuration with associated `CoinConf`.
619+
// static const ElectraProtocolNetwork mainnet = ElectraProtocolNetwork._(
620+
// 'BonkcoinMainnet', CoinsConf.electraProtocolMainNet, 'electra:mainnet');
621+
622+
// /// Testnet configuration with associated `CoinConf`.
623+
// static const ElectraProtocolNetwork testnet = ElectraProtocolNetwork._(
624+
// 'electraProtocolTestnet',
625+
// CoinsConf.electraProtocolTestNet,
626+
// 'electra:testnet');
627+
628+
// /// Overrides the `conf` property from `BasedUtxoNetwork` with the associated `CoinConf`.
629+
// @override
630+
// final CoinConf conf;
631+
// @override
632+
// final String value;
633+
634+
// /// Constructor for creating a Electra Protocol network with a specific configuration.
635+
// const BonkcoinNetwork._(this.value, this.conf, this.identifier);
636+
637+
// /// Retrieves the Wallet Import Format (WIF) version bytes from the associated `CoinConf`.
638+
// @override
639+
// List<int> get wifNetVer => conf.params.wifNetVer!;
640+
641+
// /// Retrieves the Pay-to-Public-Key-Hash (P2PKH) version bytes from the associated `CoinConf`.
642+
// @override
643+
// List<int> get p2pkhNetVer => conf.params.p2pkhNetVer!;
644+
645+
// /// Retrieves the Pay-to-Script-Hash (P2SH) version bytes from the associated `CoinConf`.
646+
// @override
647+
// List<int> get p2shNetVer => conf.params.p2shNetVer!;
648+
649+
// /// Retrieves the Human-Readable Part (HRP) for Pay-to-Witness-Public-Key-Hash (P2WPKH) addresses
650+
// /// from the associated `CoinConf`.
651+
// @override
652+
// String get p2wpkhHrp => conf.params.p2wpkhHrp!;
653+
654+
// /// Checks if the current network is the mainnet.
655+
// @override
656+
// bool get isMainnet => this == ElectraProtocolNetwork.mainnet;
657+
658+
// @override
659+
// final List<BitcoinAddressType> supportedAddress = const [
660+
// P2pkhAddressType.p2pkh,
661+
// SegwitAddressType.p2wpkh,
662+
// PubKeyAddressType.p2pk,
663+
// SegwitAddressType.p2wsh,
664+
// P2shAddressType.p2wshInP2sh,
665+
// P2shAddressType.p2wpkhInP2sh,
666+
// P2shAddressType.p2pkhInP2sh,
667+
// P2shAddressType.p2pkInP2sh,
668+
// ];
669+
670+
// @override
671+
// List<BipCoins> get coins {
672+
// if (isMainnet) {
673+
// return [
674+
// Bip44Coins.electraProtocol,
675+
// Bip49Coins.electraProtocol,
676+
// Bip84Coins.electraProtocol
677+
// ];
678+
// }
679+
// return [
680+
// Bip44Coins.electraProtocolTestnet,
681+
// Bip49Coins.electraProtocolTestnet,
682+
// Bip84Coins.electraProtocolTestnet
683+
// ];
684+
// }
685+
686+
// @override
687+
// final String identifier;
688+
// }

lib/src/provider/providers/explorer.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ class ApiProvider {
1111
{required this.api, Map<String, String>? header, required this.service})
1212
: _header = header ?? {'Content-Type': 'application/json'};
1313
factory ApiProvider.fromMempool(BasedUtxoNetwork network, ApiService service,
14-
{Map<String, String>? header}) {
15-
final api = APIConfig.mempool(network);
14+
{Map<String, String>? header, String? baseUrl}) {
15+
final api = APIConfig.mempool(network, baseUrl: baseUrl);
1616
return ApiProvider(api: api, header: header, service: service);
1717
}
1818
factory ApiProvider.fromBlocCypher(

lib/src/psbt/psbt_builder/core/psbt_builder.dart

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,57 @@ abstract class PsbtBuilderImpl {
127127
_psbt.input.updateInputs(index, [pubKeyNonce]);
128128
}
129129

130+
/// Finalizes all inputs in the PSBT and returns the finalized transaction.
131+
///
132+
/// This method attempts to finalize each input in the PSBT.
133+
///
134+
/// Note:
135+
/// - If an input is already finalized, it will be skipped.
136+
/// - If any input requires custom script handling, you must provide an
137+
/// `onFinalizeInput` callback to finalize it manually; otherwise,
138+
/// the operation may fail.
139+
///
140+
/// Returns the finalized [BtcTransaction] if successful.
141+
BtcTransaction finalizeAll({ONFINALIZEINPUT? onFinalizeInput});
142+
143+
/// Estimates the transaction size before finalization.
144+
/// Optionally accepts a [onFinalizeInput] callback to customize input finalization.
145+
/// - If any input requires custom script handling, you must provide an
146+
/// `onFinalizeInput` callback to finalize it manually; otherwise,
147+
/// the operation may fail.
148+
///
149+
/// This method does not reflect the finalized transaction size.
150+
/// For unsigned P2PKH inputs, it assumes an uncompressed public key
151+
/// unlocking script for estimation.
152+
/// For SegWit transactions, it returns the estimated virtual size (vsize).
153+
int getUnSafeTransactionSize({ONFINALIZEINPUT? onFinalizeInput}) {
154+
final fakeSignature = PsbtGlobalProprietaryUseType(
155+
identifier: PsbtUtils.fakeFinalizeGlobalIdentifier,
156+
subkeydata: [],
157+
data: const []);
158+
final Psbt psbt = Psbt(
159+
global: PsbtGlobal(
160+
version: _psbt.version,
161+
entries: [..._psbt.global.entries.clone(), fakeSignature]),
162+
input: PsbtInput(
163+
version: _psbt.version, entries: _psbt.input.entries.clone()),
164+
output: PsbtOutput(
165+
version: _psbt.version, entries: _psbt.output.entries.clone()));
166+
final builder = PsbtBuilder.fromPsbt(psbt);
167+
final tx = builder.finalizeAll(onFinalizeInput: onFinalizeInput);
168+
return tx.getSize();
169+
}
170+
171+
/// Finalizes all inputs and returns the serialized transaction size in bytes.
172+
///
173+
/// Optionally accepts a [onFinalizeInput] callback to customize input finalization.
174+
/// The returned size is the actual size of the fully finalized transaction.
175+
/// For SegWit transactions, it returns the estimated virtual size (vsize).
176+
int finalizeAllAndGetTransactionSize({ONFINALIZEINPUT? onFinalizeInput}) {
177+
final tx = finalizeAll(onFinalizeInput: onFinalizeInput);
178+
return tx.getSize();
179+
}
180+
130181
void _addNewTxOutput(PsbtTransactionOutput output) {
131182
PsbtUtils.validateCanAddOrUpdateOutput(psbt: _psbt);
132183
}

0 commit comments

Comments
 (0)