Skip to content

Commit

Permalink
v4.6.0
Browse files Browse the repository at this point in the history
add asyncTransactionBuilder method to support building transactions asynchronously.
  • Loading branch information
mrtnetwork committed Jul 5, 2024
1 parent 4368730 commit 560d845
Show file tree
Hide file tree
Showing 26 changed files with 462 additions and 115 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 4.6.0

* add asyncTransactionBuilder method to support building transactions asynchronously.

## 4.5.0

* Added support for Pepecoin network
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

import 'package:bitcoin_base/bitcoin_base.dart';

import 'package:blockchain_utils/bip/mnemonic/mnemonic.dart';
import 'package:blockchain_utils/blockchain_utils.dart';
import 'package:example/services_examples/explorer_service/explorer_service.dart';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:blockchain_utils/bip/mnemonic/mnemonic.dart';
import 'package:blockchain_utils/blockchain_utils.dart';
import 'package:example/services_examples/explorer_service/explorer_service.dart';

Expand Down
1 change: 1 addition & 0 deletions lib/src/bitcoin/address/address.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
library bitcoin_base.address;

import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:bitcoin_base/src/exception/exception.dart';
import 'package:bitcoin_base/src/utils/enumerate.dart';
import 'package:blockchain_utils/blockchain_utils.dart';
part 'core.dart';
Expand Down
4 changes: 2 additions & 2 deletions lib/src/bitcoin/address/core.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ abstract class BitcoinAddressType implements Enumerate {
/// Factory method to create a BitcoinAddressType enum value from a name or value.
static BitcoinAddressType fromValue(String value) {
return values.firstWhere((element) => element.value == value,
orElse: () =>
throw MessageException('Invalid BitcoinAddressType: $value'));
orElse: () => throw BitcoinBasePluginException(
'Invalid BitcoinAddressType: $value'));
}

/// Check if the address type is Pay-to-Script-Hash (P2SH).
Expand Down
8 changes: 5 additions & 3 deletions lib/src/bitcoin/address/legacy_address.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ abstract class LegacyAddress implements BitcoinBaseAddress {
final decode = _BitcoinAddressUtils.decodeLagacyAddressWithNetworkAndType(
address: address, type: type, network: network);
if (decode == null) {
throw MessageException("Invalid ${network.conf.coinName} address");
throw BitcoinBasePluginException(
"Invalid ${network.conf.coinName} address");
}
_addressProgram = decode;
}
Expand Down Expand Up @@ -62,7 +63,8 @@ class P2shAddress extends LegacyAddress {
@override
String toAddress(BasedUtxoNetwork network) {
if (!network.supportedAddress.contains(type)) {
throw MessageException("network does not support ${type.value} address");
throw BitcoinBasePluginException(
"network does not support ${type.value} address");
}
return super.toAddress(network);
}
Expand Down Expand Up @@ -109,7 +111,7 @@ class P2pkAddress extends LegacyAddress {
P2pkAddress({required String publicKey}) : super._() {
final toBytes = BytesUtils.fromHexString(publicKey);
if (!Secp256k1PublicKeyEcdsa.isValidBytes(toBytes)) {
throw const MessageException("Invalid secp256k1 public key");
throw const BitcoinBasePluginException("Invalid secp256k1 public key");
}
publicHex = publicKey;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/src/bitcoin/address/network_address.dart
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ class BitcoinCashAddress extends BitcoinNetworkAddress<BitcoinCashNetwork> {
address, network,
validateNetworkHRP: validateNetworkPrefix);
if (decodeAddress == null) {
throw MessageException("Invalid ${network.value} address.");
throw BitcoinBasePluginException("Invalid ${network.value} address.");
}
return BitcoinCashAddress._(decodeAddress, address);
}
Expand Down
6 changes: 4 additions & 2 deletions lib/src/bitcoin/address/segwit_address.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ abstract class SegwitAddress implements BitcoinBaseAddress {
required BasedUtxoNetwork network,
required this.segwitVersion}) {
if (!network.supportedAddress.contains(type)) {
throw MessageException("network does not support ${type.value} address");
throw BitcoinBasePluginException(
"network does not support ${type.value} address");
}
addressProgram = _BitcoinAddressUtils.toSegwitProgramWithVersionAndNetwork(
address: address, version: segwitVersion, network: network);
Expand All @@ -29,7 +30,8 @@ abstract class SegwitAddress implements BitcoinBaseAddress {
@override
String toAddress(BasedUtxoNetwork network) {
if (!network.supportedAddress.contains(type)) {
throw MessageException("network does not support ${type.value} address");
throw BitcoinBasePluginException(
"network does not support ${type.value} address");
}
return _BitcoinAddressUtils.segwitToAddress(
addressProgram: addressProgram,
Expand Down
10 changes: 5 additions & 5 deletions lib/src/bitcoin/address/utils/address_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class _BitcoinAddressUtils {
final convert = SegwitBech32Decoder.decode(network.p2wpkhHrp, address);
final witnessVersion = convert.item1;
if (witnessVersion != version) {
throw const MessageException("Invalid segwit version");
throw const BitcoinBasePluginException("Invalid segwit version");
}
return BytesUtils.toHexString(convert.item2);
}
Expand Down Expand Up @@ -137,7 +137,7 @@ class _BitcoinAddressUtils {
if (network.supportedAddress.contains(address.type)) {
return address;
}
throw MessageException(
throw BitcoinBasePluginException(
"${network.value} does not support ${address.type.value} address");
}

Expand All @@ -158,7 +158,7 @@ class _BitcoinAddressUtils {
}
baseAddress ??= toLegacy(address, network);
if (baseAddress == null) {
throw const MessageException("Invalid Bitcoin address");
throw const BitcoinBasePluginException("Invalid Bitcoin address");
}
return validateAddress(baseAddress, network);
}
Expand All @@ -180,7 +180,7 @@ class _BitcoinAddressUtils {
}
// ignore: empty_catches
} catch (e) {}
throw const MessageException(
throw const BitcoinBasePluginException(
"Invalid Bitcoin address program length (program length should be 32 or 20 bytes)");
}

Expand Down Expand Up @@ -276,7 +276,7 @@ class _BitcoinAddressUtils {
required BitcoinAddressType type,
required BasedUtxoNetwork network}) {
if (!network.supportedAddress.contains(type)) {
throw MessageException(
throw BitcoinBasePluginException(
"${network.value} does not support ${type.value} address type");
}
if (network is BitcoinCashNetwork) {
Expand Down
3 changes: 2 additions & 1 deletion lib/src/bitcoin/script/input.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:bitcoin_base/src/bitcoin/script/op_code/constant.dart';
import 'package:bitcoin_base/src/exception/exception.dart';
import 'package:blockchain_utils/utils/utils.dart';
import 'script.dart';

Expand Down Expand Up @@ -62,7 +63,7 @@ class TxInput {
List<int> inpHash =
txInputRaw.sublist(cursor, cursor + 32).reversed.toList();
if (inpHash.isEmpty) {
throw ArgumentError(
throw const BitcoinBasePluginException(
"Input transaction hash not found. Probably malformed raw transaction");
}
List<int> outputN =
Expand Down
7 changes: 5 additions & 2 deletions lib/src/bitcoin/script/op_code/tools.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:bitcoin_base/src/exception/exception.dart';
import 'package:blockchain_utils/utils/utils.dart';

List<int> opPushData(String hexData) {
Expand All @@ -18,13 +19,15 @@ List<int> opPushData(String hexData) {
writeUint32LE(lengthBytes.length, lengthBytes);
return List<int>.from([0x4e, ...lengthBytes, ...dataBytes]);
} else {
throw ArgumentError("Data too large. Cannot push into script");
throw const BitcoinBasePluginException(
"Data too large. Cannot push into script");
}
}

List<int> pushInteger(int integer) {
if (integer < 0) {
throw ArgumentError('Integer is currently required to be positive.');
throw const BitcoinBasePluginException(
'Integer is currently required to be positive.');
}

/// Calculate the number of bytes required to represent the integer
Expand Down
9 changes: 6 additions & 3 deletions lib/src/bitcoin/script/sequence.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'dart:typed_data';
import 'package:bitcoin_base/src/bitcoin/script/op_code/constant.dart';
import 'package:bitcoin_base/src/exception/exception.dart';
import 'package:blockchain_utils/utils/utils.dart';

/// Helps setting up appropriate sequence. Used to provide the sequence to transaction inputs and to scripts.
Expand All @@ -12,7 +13,8 @@ class Sequence {
{required this.seqType, required this.value, this.isTypeBlock = true}) {
if (seqType == BitcoinOpCodeConst.TYPE_RELATIVE_TIMELOCK &&
(value < 1 || value > mask16)) {
throw ArgumentError('Sequence should be between 1 and 65535');
throw const BitcoinBasePluginException(
'Sequence should be between 1 and 65535');
}
}
final int seqType;
Expand All @@ -37,13 +39,14 @@ class Sequence {
return IntUtils.toBytes(seq, length: 4, byteOrder: Endian.little);
}

throw ArgumentError("Invalid seqType");
throw const BitcoinBasePluginException("Invalid seqType");
}

/// Returns the appropriate integer for a script; e.g. for relative timelocks
int forScript() {
if (seqType == BitcoinOpCodeConst.TYPE_REPLACE_BY_FEE) {
throw const FormatException("RBF is not to be included in a script.");
throw const BitcoinBasePluginException(
"RBF is not to be included in a script.");
}
int scriptIntiger = value;
if (seqType == BitcoinOpCodeConst.TYPE_RELATIVE_TIMELOCK && !isTypeBlock) {
Expand Down
22 changes: 4 additions & 18 deletions lib/src/bitcoin/script/transaction.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'dart:typed_data';
import 'package:bitcoin_base/src/cash_token/cash_token.dart';
import 'package:bitcoin_base/src/bitcoin/script/op_code/constant.dart';
import 'package:bitcoin_base/src/crypto/crypto.dart';
import 'package:bitcoin_base/src/exception/exception.dart';
import 'package:blockchain_utils/utils/utils.dart';
import 'package:blockchain_utils/crypto/quick_crypto.dart';
import 'input.dart';
Expand Down Expand Up @@ -39,8 +40,6 @@ class BtcTransaction {
final bool hasSegwit;
final List<TxWitnessInput> witnesses;

// List<TxWitnessInput> get witnesses =>
// List.unmodifiable(_witnesses.map((e) => e.copy()).toList());
BtcTransaction copyWith({
List<TxInput>? inputs,
List<TxOutput>? outputs,
Expand All @@ -59,10 +58,6 @@ class BtcTransaction {
);
}

// void addWitnesses(TxWitnessInput witness) {
// _witnesses.add(witness);
// }

/// creates a copy of the object (classmethod)
static BtcTransaction copy(BtcTransaction tx) {
return BtcTransaction(
Expand Down Expand Up @@ -164,22 +159,16 @@ class BtcTransaction {
}
} else if ((sighash & 0x1f) == BitcoinOpCodeConst.SIGHASH_SINGLE) {
if (txInIndex >= tx.outputs.length) {
throw ArgumentError(
"Transaction index is greater than theavailable outputs");
throw const BitcoinBasePluginException(
"Transaction index is greater than the available outputs");
}
// final txout = tx.outputs[txInIndex];
// tx.outputs.clear();
// tx = tx.copyWith(outputs: []);

List<TxOutput> outputs = [];
for (int i = 0; i < txInIndex; i++) {
outputs.add(TxOutput(
amount: BigInt.from(BitcoinOpCodeConst.NEGATIVE_SATOSHI),
scriptPubKey: Script(script: [])));
// tx.outputs.add(TxOutput(
// amount: BigInt.from(BitcoinOpCodeConst.NEGATIVE_SATOSHI),
// scriptPubKey: Script(script: [])));
}
// outputs.add(txout);
tx = tx.copyWith(outputs: [...outputs, tx.outputs[txInIndex]]);
for (int i = 0; i < tx.inputs.length; i++) {
if (i != txInIndex) {
Expand All @@ -189,10 +178,7 @@ class BtcTransaction {
}
}
if ((sighash & BitcoinOpCodeConst.SIGHASH_ANYONECANPAY) != 0) {
// final inp = tx.inputs[txInIndex];
tx = tx.copyWith(inputs: [tx.inputs[txInIndex]]);
// tx.inputs.clear();
// tx.inputs.add(inp);
}
List<int> txForSign = tx.toBytes(segwit: false);

Expand Down
22 changes: 13 additions & 9 deletions lib/src/cash_token/cash_token.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
// SOFTWARE.

import 'dart:typed_data';
import 'package:bitcoin_base/src/exception/exception.dart';
import 'package:blockchain_utils/blockchain_utils.dart';

/// The CashTokenCapability class represents different capabilities associated with a Cash Token.
Expand Down Expand Up @@ -62,7 +63,8 @@ class CashTokenCapability {
final int intCapability = _getCapability(bitfield);
return values.firstWhere((element) => element.value == intCapability);
} on StateError {
throw const MessageException("Invalid CashToken NFT Capability");
throw const BitcoinBasePluginException(
"Invalid CashToken NFT Capability");
}
}

Expand All @@ -71,7 +73,8 @@ class CashTokenCapability {
try {
return values.firstWhere((element) => element.name == name);
} on StateError {
throw const MessageException("Invalid CashToken NFT Capability Name");
throw const BitcoinBasePluginException(
"Invalid CashToken NFT Capability Name");
}
}

Expand Down Expand Up @@ -270,29 +273,30 @@ class CashToken {
List<int>? commitment,
required int bitfield}) {
if (!CashTokenUtils.isValidBitfield(bitfield)) {
throw const MessageException("Invalid bitfield");
throw const BitcoinBasePluginException("Invalid bitfield");
}
if (CashTokenUtils.hasAmount(bitfield) && amount == null) {
throw const MessageException(
throw const BitcoinBasePluginException(
"Invalid cash token: the bitfield indicates an amount, but the amount is null.");
}
if (amount != null) {
if (amount < BigInt.zero || amount > CashTokenUtils.maxTokenAmount) {
throw const MessageException(
throw const BitcoinBasePluginException(
"Invalid amount. Amount must be between zero and 99.");
}
}
if (!StringUtils.isHexBytes(category)) {
throw const MessageException("Invalid category hexadecimal bytes.");
throw const BitcoinBasePluginException(
"Invalid category hexadecimal bytes.");
}
final toBytes = BytesUtils.fromHexString(category);
if (toBytes.length != CashTokenUtils.idBytesLength) {
throw const MessageException(
throw const BitcoinBasePluginException(
"Invalid category. The category should consist of 32 bytes.");
}
if (CashTokenUtils.hasCommitmentLength(bitfield) &&
(commitment == null || commitment.isEmpty)) {
throw const MessageException(
throw const BitcoinBasePluginException(
"Invalid cash token: the bitfield indicates an commitment, but the commitment is null or empty.");
}
return CashToken.noValidate(
Expand Down Expand Up @@ -332,7 +336,7 @@ class CashToken {
amount < BigInt.zero ||
amount > CashTokenUtils.maxTokenAmount ||
CashTokenUtils.hasCommitmentLength(bitfield) && commitment.isEmpty) {
throw const MessageException('Invalid cash token');
throw const BitcoinBasePluginException('Invalid cash token');
}
return Tuple(
CashToken(
Expand Down
11 changes: 8 additions & 3 deletions lib/src/crypto/keypair/ec_public.dart
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
import 'package:bitcoin_base/src/bitcoin/address/address.dart';
import 'package:bitcoin_base/src/bitcoin/script/script.dart';
import 'package:bitcoin_base/src/exception/exception.dart';
import 'package:blockchain_utils/blockchain_utils.dart';

class ECPublic {
final Bip32PublicKey publicKey;
ECPublic(this.publicKey) {
const ECPublic._(this.publicKey);

factory ECPublic.fromBip32(Bip32PublicKey publicKey) {
if (publicKey.curveType != EllipticCurveTypes.secp256k1) {
throw ArgumentError("invalid public key curve for bitcoin");
throw const BitcoinBasePluginException(
"invalid public key curve for bitcoin");
}
return ECPublic._(publicKey);
}

/// Constructs an ECPublic key from a byte representation.
factory ECPublic.fromBytes(List<int> public) {
final publicKey = Bip32PublicKey.fromBytes(public, Bip32KeyData(),
Bip32Const.mainNetKeyNetVersions, EllipticCurveTypes.secp256k1);
return ECPublic(publicKey);
return ECPublic._(publicKey);
}

/// Constructs an ECPublic key from hex representation.
Expand Down
9 changes: 9 additions & 0 deletions lib/src/exception/exception.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import 'package:blockchain_utils/blockchain_utils.dart';

class BitcoinBasePluginException extends BlockchainUtilsException {
@override
final String message;
@override
final Map<String, dynamic>? details;
const BitcoinBasePluginException(this.message, {this.details});
}
Loading

0 comments on commit 560d845

Please sign in to comment.