-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbtc_txn.py
More file actions
executable file
·207 lines (173 loc) · 7.5 KB
/
btc_txn.py
File metadata and controls
executable file
·207 lines (173 loc) · 7.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
import requests
import random
from datetime import datetime, timedelta
from bitcoinlib.keys import Key
from bitcoinlib.transactions import Transaction, Input, Output
# Configuration
file_path = '.btc_txn.txt'
PRIVATE_KEY_WIF = "cMvKdjsGpFBbRdeE27A8mHLJL4TXnhA9uC4niahYYP7bhKUxsKQk" # Replace with your private key in WIF format
PUBLIC_KEY = "tb1qquv56uy060f7g3khehqzvk7q0l7fvjxgayq08e" # Replace with your private key in WIF format
RECEIVER_ADDRESS = "tb1q5adq0tjduagkda27u2rcm7lh3zq4rd4sl7tw26" # Replace with the recipient's Bitcoin address
NETWORK = 'testnet' # 'testnet' for testing
MAX_FEE_SATOSHI = 850 # Transaction fee in BTC
NODE_URL = 'http://payram:bitpayramtest@13.211.216.231:18332' # Replace with your node URL
NODE_USERNAME = 'payram' # Replace with your node username, if needed
NODE_PASSWORD = 'bitpayramtest' # Replace with your node password, if needed
min_amount = 500 # Minimum BTC to send
max_amount = 1000 # Maximum BTC to send
addresses = [
'tb1q5adq0tjduagkda27u2rcm7lh3zq4rd4sl7tw26',
'tb1q6zvn7583n7mkqaajvpt7p3n0pgaczam9sk88p9',
'tb1qtffes7cxq9plgj5gg9v8chr37ypmmly7ej948j',
'tb1qwykt43q3my6u6mt4aws3l5r54xyyf6yhnxdnj4',
'tb1qf5nal5c2cz32j3snjkz6v3lva4gfp6dr9shqdp',
'tb1qvnzl5esullqaup4ceuepyn2j05u0548dvjvcl8',
'tb1q3g6w4s389k0t400ag3y2ryr6uhqgdk2w9facxm',
'tb1q5rl3zf02eq4p5sveg7lr3paxmdvh46d7z06m9q',
'tb1qp35f7wlt5ms02askng407r47a24pd3npj63xky',
'tb1qfun0cupskqzcw6f27zhxlmth6gh4kjmh8rvtfd',
"tb1qu2ehkx6228mht79wpp2x0zwrfy6l9lju9s9zpz",
"tb1qsvdkgk3c6e805929hz8hhzv9enhufplyu59yx9",
"tb1qlz26uuc8mldzzlxnt6pgw3hduylny8v75pd62z",
"tb1qcf4yca3w3d058nuuspgllauxd9rkccj2lavshe",
"tb1q4h6ysjmay8fezt0f9anwklgz9qh264wy92na93",
"tb1q7xq8k2a8ajcnxk98y7avt5p3lt4gx0kp7u9lwl"
]
def save_current_timestamp_to_file() -> None:
current_time = datetime.now()
with open(file_path, 'w') as file:
file.write(current_time.isoformat())
def get_timestamp_from_file() -> datetime:
try:
with open(file_path, 'r') as file:
timestamp_str = file.read().strip()
return datetime.fromisoformat(timestamp_str)
except Exception:
return datetime.now() - timedelta(days=1)
def proceed_if_time_exceeds_one_hour() -> bool:
try:
saved_timestamp = get_timestamp_from_file()
current_time = datetime.now()
time_difference = current_time - saved_timestamp
if time_difference > timedelta(hours=1):
return True
else:
return False
except FileNotFoundError:
print("Timestamp file not found. Please save a timestamp first.")
return False
def fetch_current_fee_rate():
try:
response = requests.get('https://blockstream.info/testnet/api/fee-estimates')
if response.status_code == 200:
fee_estimates = response.json()
fee_rate = max(fee_estimates.get('6', 0), 2)
return fee_rate
else:
print(f"Error fetching fee estimates: {response.text}")
return None
except Exception as e:
print(f"Error fetching fee rate: {str(e)}")
return None
def estimate_tx_size(num_inputs, num_outputs):
version = 4
marker_and_flag = 2
locktime = 4
input_base_size = 36 + 1 + 4
witness_size = 72 + 33
total_input_size = input_base_size + witness_size
output_size = 8 + 1 + 25
tx_size = version + marker_and_flag + (num_inputs * total_input_size) + (num_outputs * output_size) + locktime
return tx_size
def fetch_utxos(address):
response = requests.get(f'https://blockstream.info/testnet/api/address/{address}/utxo')
if response.status_code == 200:
return response.json()
else:
print(f"Error fetching UTXOs: {response.text}")
return []
def broadcast_transaction(signed_tx) -> bool:
response = requests.post(
NODE_URL,
json={
"jsonrpc": "1.0",
"id": "broadcast",
"method": "sendrawtransaction",
"params": [signed_tx]
},
auth=(NODE_USERNAME, NODE_PASSWORD)
)
if response.status_code == 200:
print(f"Transaction broadcasted successfully: {response.json()['result']}")
return True
else:
print(f"Error broadcasting transaction: {response.text}")
return False
def main():
if proceed_if_time_exceeds_one_hour():
fee_satoshi_per_byte = fetch_current_fee_rate()
if fee_satoshi_per_byte is None:
print("Fees not available!")
return
saved_timestamp = get_timestamp_from_file()
current_time = datetime.now()
time_difference = current_time - saved_timestamp
hours_since_last = time_difference.total_seconds() // 3600
# Ensure hours_since_last is between 1 and 8
hours_since_last = max(1, min(hours_since_last, 14))
# Generate multiple random amounts based on hours since the last timestamp
amounts = [int(round(random.uniform(min_amount, max_amount), 8)) for _ in range(int(hours_since_last))]
amount_to_send = sum(amounts)
selected_addresses = random.sample(addresses, 1)
for to_address in selected_addresses:
tx_size = estimate_tx_size(1, 2)
fee = int(round(fee_satoshi_per_byte * tx_size / 2))
if fee > MAX_FEE_SATOSHI:
print(f"Fee {fee} is very high, skipping the transaction.")
return
print(to_address)
# Create the key object from the private key WIF
key = Key(PRIVATE_KEY_WIF, network=NETWORK, compressed=True)
sender_address = key.address(script_type='p2wpkh', encoding='bech32')
utxos = fetch_utxos('tb1qquv56uy060f7g3khehqzvk7q0l7fvjxgayq08e')
if not utxos:
print("No UTXOs found. Cannot create transaction.")
return
tx_size = estimate_tx_size(len(utxos), 2)
fee = int(round(fee_satoshi_per_byte * tx_size / 2))
if fee > MAX_FEE_SATOSHI:
print(f"Fee {fee} is very high, skipping the transaction.")
return
inputs = []
total_amount = 0
for utxo in utxos:
total_amount += utxo['value']
pubkey = key.public_hex
witnesses = [bytes.fromhex(pubkey)]
inputs.append(Input(
prev_txid=utxo['txid'],
output_n=utxo['vout'],
value=utxo['value'],
script_type='p2wpkh',
witness_type='segwit',
address=sender_address,
witnesses=witnesses
))
total_amount_exlude_fees = total_amount - fee
print(amount_to_send)
change_amount = total_amount_exlude_fees - amount_to_send
if amount_to_send <= 0:
print("Insufficient funds to cover the transaction fee.")
return
outputs = [
Output(address=to_address, value=amount_to_send, network=NETWORK),
Output(address='tb1qquv56uy060f7g3khehqzvk7q0l7fvjxgayq08e', value=change_amount, network=NETWORK)
]
tx = Transaction(network=NETWORK, inputs=inputs, outputs=outputs, witness_type='segwit')
for index, inp in enumerate(inputs):
tx.sign(index_n=index, keys=key)
signed_tx = tx.raw_hex()
if broadcast_transaction(signed_tx):
save_current_timestamp_to_file()
if __name__ == "__main__":
main()