bitcoinwatcher 2.13__py3-none-any.whl → 2.15__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -56,7 +56,9 @@ class AbstractAddressListener(AbstractTxListener, ABC):
56
56
  self.consume(tx_hex=tx.raw_hex(), subscribed_address="SATFLOW", address_tx_data=address_tx_data)
57
57
  else:
58
58
  logger.debug(f"No addresses to listen to for transaction {tx.txid}.")
59
- return
60
-
59
+ bitmap_tx = next((addr_data for addr_data in address_tx_data if addr_data.bitmap_details is not None), None)
60
+ if bitmap_tx:
61
+ logger.info(f"Transaction {tx.txid} contains bitmap inscription: {bitmap_tx.bitmap_details}")
62
+ self.consume(tx_hex=tx.raw_hex(), subscribed_address="BITMAP",address_tx_data=address_tx_data)
61
63
  for address in addresses_for_events:
62
64
  self.consume(tx_hex=tx.raw_hex(), subscribed_address=address, address_tx_data=address_tx_data)
@@ -16,6 +16,10 @@ class TransactionStatus(Enum):
16
16
  UNCONFIRMED = "unconfirmed"
17
17
  CONFIRMED = "confirmed"
18
18
 
19
+ class BitmapDetails:
20
+ bitmap_number: int
21
+ fee: int
22
+ fee_per_vbyte: float
19
23
 
20
24
  @dataclasses.dataclass
21
25
  class AddressTxData:
@@ -26,6 +30,8 @@ class AddressTxData:
26
30
  _amount: int = 0
27
31
  is_confirmed: bool = False
28
32
  is_reveal_tx: bool = False
33
+ fee: int = 0
34
+ bitmap_details: BitmapDetails | None = None
29
35
 
30
36
  def get_amount(self):
31
37
  return self._amount
@@ -1,10 +1,11 @@
1
+ import math
1
2
  import os
2
3
  from multiprocessing.pool import ThreadPool
3
4
 
4
5
  from bitcoinlib.transactions import Transaction
5
6
 
6
7
  from bitcoin.address_listener.address_listener import AddressTxData
7
- from bitcoin.models.address_tx_data import AddressTxType
8
+ from bitcoin.models.address_tx_data import AddressTxType, BitmapDetails
8
9
  from bitcoin.utils.bitcoin_rpc import BitcoinRPC
9
10
  from bitcoin.tx_extractors.abstract_extractor import AbstractTxAddressDataExtractor
10
11
  from bitcoin.utils.context_aware_logging import logger, ctx_tx_status
@@ -36,6 +37,48 @@ class BitcoinRPCAddressDataExtractor(AbstractTxAddressDataExtractor):
36
37
  return AddressTxData(tx_id=tx_id, is_confirmed=tx_status, address=address, _amount=amount,
37
38
  type=AddressTxType.INPUT)
38
39
 
40
+ @staticmethod
41
+ def check_bitmap_patterns(tx: Transaction) -> str:
42
+ """Check if transaction contains bitmap inscription patterns"""
43
+ patterns = [
44
+ "036f7264", # ord
45
+ "746578742f706c61696e", # text/plain
46
+ "2e6269746d6170" # .bitmap
47
+ ]
48
+
49
+ raw_hex = tx.raw_hex()
50
+ if all(p in raw_hex for p in patterns):
51
+ bitmap_pattern = "e6269746d6170"
52
+ index = raw_hex.find(bitmap_pattern)
53
+ if index != -1 and index >= 13:
54
+ before_hex = raw_hex[index-13:index]
55
+ try:
56
+ decoded_text = bytes.fromhex(before_hex + bitmap_pattern).decode("utf-8", errors="ignore")
57
+ return decoded_text
58
+ except:
59
+ return "[could not decode bitmap]"
60
+ return None
61
+
62
+ @staticmethod
63
+ def calculate_transaction_fee(tx: Transaction, inputs_data: list) -> int:
64
+ """Calculate transaction fee manually using fetched input data and outputs"""
65
+ # Calculate total input value from fetched RPC data
66
+ total_input_value = 0
67
+ for input_data in inputs_data:
68
+ value = input_data.get("value", 0)
69
+ total_input_value += int(value * 100000000) # Convert to satoshis
70
+
71
+ # Calculate total output value from transaction outputs
72
+ total_output_value = sum(output.value for output in tx.outputs)
73
+
74
+ # Fee = inputs - outputs
75
+ calculated_fee = total_input_value - total_output_value
76
+
77
+ logger.info("Fee calculation - Input: %d sats, Output: %d sats, Fee: %d sats",
78
+ total_input_value, total_output_value, calculated_fee)
79
+
80
+ return calculated_fee
81
+
39
82
  def extract(self, tx: Transaction) -> [AddressTxData]:
40
83
  logger.info("Extracting rpc tx data")
41
84
  outputs = tx.outputs
@@ -47,6 +90,15 @@ class BitcoinRPCAddressDataExtractor(AbstractTxAddressDataExtractor):
47
90
  is_confirmed = self.bitcoinrpc.is_confirmed(tx_id)
48
91
  ctx_tx_status.set(is_confirmed)
49
92
  logger.info("Transaction is_confirmed: %s", is_confirmed)
93
+
94
+ # Calculate fee manually using fetched input data
95
+ calculated_fee = self.calculate_transaction_fee(tx, inputs_data)
96
+ bitcoinlib_fee = tx.fee
97
+
98
+ # Check for bitmap inscription
99
+ bitmap_inscription = self.check_bitmap_patterns(tx)
100
+ if bitmap_inscription:
101
+ logger.info("Bitmap inscription found: %s", bitmap_inscription)
50
102
  for input in inputs:
51
103
  address = input.address
52
104
  amount = 0
@@ -67,4 +119,13 @@ class BitcoinRPCAddressDataExtractor(AbstractTxAddressDataExtractor):
67
119
  _amount=amount,
68
120
  type=AddressTxType.OUTPUT,
69
121
  tx_id=tx.txid))
122
+ if bitmap_inscription is not None:
123
+ bitmap_details = BitmapDetails()
124
+ bitmap_details.fee = calculated_fee
125
+ witness_size = len(tx.witness_data()) // 2 if tx.witness_data else 0
126
+ virtual_size = (tx.size * 3 + witness_size) / 4
127
+ fee_per_vbyte = math.ceil(calculated_fee / virtual_size * 100) / 100 if virtual_size > 0 else 0
128
+ bitmap_details.fee_per_vbyte = round(fee_per_vbyte, 2)
129
+ bitmap_details.bitmap_number = int(bitmap_inscription.split(".bitmap")[0])
130
+ address_tx_data[0].bitmap_details = bitmap_details
70
131
  return address_tx_data
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bitcoinwatcher
3
- Version: 2.13
3
+ Version: 2.15
4
4
  Summary: bitcoinwatcher is a Python library that implements a ZMQ subscriber and provides abstractions to build custom address watchers. This library is designed to make it easy for developers to monitor Bitcoin addresses and react to changes in their state.
5
5
  Author: twosatsmaxi
6
6
  License: Apache License
@@ -1,9 +1,9 @@
1
1
  bitcoin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  bitcoin/address_listener/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- bitcoin/address_listener/address_listener.py,sha256=vMIuCALrYo-Lh-olzikualMKTaFvxS4I_hebhUxW9CU,2874
3
+ bitcoin/address_listener/address_listener.py,sha256=lxRcvrB1Gr360RXymkGNNOCxsKqD2pbALBvbjQ0UEno,3206
4
4
  bitcoin/address_listener/simple_address_listener.py,sha256=yQTxWVthsMiYkXzWYmGMCzP0LWTUokgWFkqEf8GsUB4,1674
5
5
  bitcoin/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- bitcoin/models/address_tx_data.py,sha256=KSSCzAjYxLEgXIELVSsnSEhgY65xi0K3HUjoamVV_LQ,750
6
+ bitcoin/models/address_tx_data.py,sha256=E_3YJ6A0RBrg5FeSVtkw5qQbKKubbq_QWIp9LXQOWq0,897
7
7
  bitcoin/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  bitcoin/tests/test_address_listener.py,sha256=USK3BMGnRsTBmCXcbnC9WkX6kF-W_sHt7RKARv39IDg,3125
9
9
  bitcoin/tests/test_bitcoin_rpc.py,sha256=Xt9Mh71YQqE_gskgLMfPLs0J0YcCT7z5UimT42LOris,4137
@@ -12,7 +12,7 @@ bitcoin/tests/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuF
12
12
  bitcoin/tests/data/transactions.py,sha256=qIX9seGYguQ1lvLOCF8oe3NQhMJZP0SsBmz1iFbszhg,396279
13
13
  bitcoin/tx_extractors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
14
  bitcoin/tx_extractors/abstract_extractor.py,sha256=YLnuqc3jva15NpOX8xV4oB5PEXc6rXbG8Lx0cBXW66s,291
15
- bitcoin/tx_extractors/bitcoin_rpc.py,sha256=00rAn1wtuvTmJMws4VfJWUv_Mf5WEe4eKbOGEtBjTQY,3323
15
+ bitcoin/tx_extractors/bitcoin_rpc.py,sha256=SBGxzUg9raOia9hmk8Aqy6d5gcmS42hfIQVFvmIeVSU,6038
16
16
  bitcoin/tx_extractors/default.py,sha256=KLT0EIbrp9yzFTQ-U5JRGI4ACHkvEMmycdXQGoPRU20,1509
17
17
  bitcoin/tx_extractors/mempool.py,sha256=mPPY1GOvBmZWn7UVP2sUaXtfcyeTCj-LmRDl2F4WhC8,2090
18
18
  bitcoin/tx_listener/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -25,8 +25,8 @@ bitcoin/utils/bitcoin_utils.py,sha256=hoYzduIO5vsBPW4imp-pNqsxmErtJMCaPURc6N_OKx
25
25
  bitcoin/utils/constants.py,sha256=bolLU7V3pFt6dQQ__CK5ESC8bkg0jO_Akn4iubaUum0,51
26
26
  bitcoin/utils/context_aware_logging.py,sha256=p3PuFnHjJcgEH8O9ng7UrXvW3SVDWGaeYgxysDuqRyI,1874
27
27
  bitcoin/utils/inscription_utils.py,sha256=8QbOJ1o1n1bMFsPREGLzwFjnGzfuARgJCPr6ORhP44o,193
28
- bitcoinwatcher-2.13.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
29
- bitcoinwatcher-2.13.dist-info/METADATA,sha256=JHDTZ035ubdz0pVyH-PJK8h1oNdBXzSLD6otqsCdYaA,15043
30
- bitcoinwatcher-2.13.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
31
- bitcoinwatcher-2.13.dist-info/top_level.txt,sha256=YdUgzLdCiMlrwaKyDqHA1acEd23QFko5bv7D6nBANJ0,8
32
- bitcoinwatcher-2.13.dist-info/RECORD,,
28
+ bitcoinwatcher-2.15.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
29
+ bitcoinwatcher-2.15.dist-info/METADATA,sha256=db1mb7vF2iQYeIO9_g4SYqqbOl4WWvGqKWuVOhFJGHM,15043
30
+ bitcoinwatcher-2.15.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
31
+ bitcoinwatcher-2.15.dist-info/top_level.txt,sha256=YdUgzLdCiMlrwaKyDqHA1acEd23QFko5bv7D6nBANJ0,8
32
+ bitcoinwatcher-2.15.dist-info/RECORD,,