def main(): # always remember to setup the network setup('testnet') # could also instantiate from existing WIF key priv = PrivateKey.from_wif( 'cVdte9ei2xsVjmZSPtyucG43YZgNkmKTqhwiUA8M4Fc3LdPJxPmZ') # compressed is the default print("\nPrivate key WIF:", priv.to_wif(compressed=True)) # get the public key pub = priv.get_public_key() # compressed is the default print("Public key:", pub.to_hex(compressed=True)) # get address from public key address = pub.get_segwit_address() # print the address and hash - default is compressed address print("Native Address:", address.to_string()) segwit_hash = address.to_hash() print("Segwit Hash:", segwit_hash) print("Segwit Version:", address.get_type()) # test to_string addr2 = P2wpkhAddress.from_hash(segwit_hash) print("Created P2wpkhAddress from Segwit Hash and calculate address:") print("Native Address:", addr2.to_string()) # # display P2SH-P2WPKH # # create segwit address addr3 = PrivateKey.from_wif( 'cTmyBsxMQ3vyh4J3jCKYn2Au7AhTKvqeYuxxkinsg6Rz3BBPrYKK').get_public_key( ).get_segwit_address() # wrap in P2SH address addr4 = P2shAddress.from_script(addr3.to_script_pub_key()) print("P2SH(P2WPKH):", addr4.to_string()) # # display P2WSH # p2wpkh_key = PrivateKey.from_wif( 'cNn8itYxAng4xR4eMtrPsrPpDpTdVNuw7Jb6kfhFYZ8DLSZBCg37') script = Script([ 'OP_1', p2wpkh_key.get_public_key().to_hex(), 'OP_1', 'OP_CHECKMULTISIG' ]) p2wsh_addr = P2wshAddress.from_script(script) print("P2WSH of P2PK:", p2wsh_addr.to_string()) # # display P2SH-P2WSH # p2sh_p2wsh_addr = P2shAddress.from_script(p2wsh_addr.to_script_pub_key()) print("P2SH(P2WSH of P2PK):", p2sh_p2wsh_addr.to_string())
def main(): # always remember to setup the network setup('testnet') priv1 = PrivateKey("cN1XE3ESGgdvr4fWsB7L3BcqXncUauF8Fo8zzv4Sm6WrkiGrsxrG") priv2 = PrivateKey("cR8AkcbL2pgBswrHp28AftEznHPPLA86HiTog8MpNCibxwrsUcZ4") p2sh_redeem_script = Script( ['OP_1', priv1.get_public_key().to_hex(), priv2.get_public_key().to_hex(),'OP_2', 'OP_CHECKMULTISIG']) fromAddress = P2wshAddress.from_script(p2sh_redeem_script) toAddress = P2wpkhAddress.from_address("tb1qtstf97nhk2gycz7vl37esddjpxwt3ut30qp5pn") # set values txid = '2042195c40a92353f2ffe30cd0df8d177698560e81807e8bf9174a9c0e98e6c2' vout = 0 amount = 0.01 # create transaction input from tx id of UTXO txin = TxInput(txid, vout) txOut1 = TxOutput(0.0001, toAddress.to_script_pub_key()) txOut2 = TxOutput(0.0098, fromAddress.to_script_pub_key()) tx = Transaction([txin], [txOut1, txOut2], has_segwit=True) sig1 = priv1.sign_segwit_input(tx, 0, p2sh_redeem_script, amount) tx.witnesses.append(Script(['OP_0', sig1, p2sh_redeem_script.to_hex()])) # print raw signed transaction ready to be broadcasted print("\nRaw signed transaction:\n" + tx.serialize()) print("\nTxId:", tx.get_txid())
def main(): # always remember to setup the network setup('testnet') # send 2 P2PKH inputs to 1 P2WPKH output # create transaction inputs from tx ids of UTXOs (contained 0.002 tBTC) txin = TxInput('eddfaa3d5a1c9a2a2961638aa4e28871b09ed9620f9077482248f368d46d8205', 1) txin2 = TxInput('cf4b2987c06b9dd2ba6770af31a4942a4ea3e7194c0d64e8699e9fda03f50551', 1) # create transaction output using P2WPKH scriptPubKey (locking script) addr = P2wpkhAddress('tb1qlffsz7cgzmyzhklleu97afru7vwjytux4z4zsl') txout = TxOutput(to_satoshis(0.0019), addr.to_script_pub_key()) #txout = TxOutput(to_satoshis(0.0019), Script([0, addr.to_hash()]) ) # create transaction from inputs/outputs -- default locktime is used # note that this is not a segwit transaction since we don't spend segwit tx = Transaction([txin, txin2], [txout]) #, has_segwit=True) # print raw transaction print("\nRaw unsigned transaction:\n" + tx.serialize()) # use the private keys corresponding to the address that contains the # UTXOs we are trying to spend to sign the input sk = PrivateKey('cTALNpTpRbbxTCJ2A5Vq88UxT44w1PE2cYqiB3n4hRvzyCev1Wwo') sk2 = PrivateKey('cVf3kGh6552jU2rLaKwXTKq5APHPoZqCP4GQzQirWGHFoHQ9rEVt') # note that we pass the scriptPubkey as one of the inputs of sign_input # because it is used to replace the scriptSig of the UTXO we are trying to # spend when creating the transaction digest from_addr = P2pkhAddress('n4bkvTyU1dVdzsrhWBqBw8fEMbHjJvtmJR') sig = sk.sign_input( tx, 0, Script(['OP_DUP', 'OP_HASH160', from_addr.to_hash160(), 'OP_EQUALVERIFY', 'OP_CHECKSIG']) ) from_addr2 = P2pkhAddress('mmYNBho9BWQB2dSniP1NJvnPoj5EVWw89w') sig2 = sk2.sign_input( tx, 1, from_addr2.to_script_pub_key() ) # get public key as hex pk = sk.get_public_key().to_hex() pk2 = sk2.get_public_key().to_hex() # set the scriptSig (unlocking script) txin.script_sig = Script([sig, pk]) txin2.script_sig = Script([sig2, pk2]) signed_tx = tx.serialize() # print raw signed transaction ready to be broadcasted print("\nRaw signed transaction:\n" + signed_tx)
def tip_or_withdrawFunc(update, ctx): # Initialise bitcoin.py setup('mainnet') query = update.callback_query chID = query.message.chat.id msgID = query.message.message_id query.answer() data = str(query.data).split(",") sender = str(query.from_user.id) if sender == data[3]: if data[4] == "t": target = data[1] if data[0] == "Y": ctx.bot.delete_message(chat_id=chID, message_id=msgID) sender_wif = PrivateKey(db.getWIF(sender)) fee = convertToSatoshis(Decimal(config.coin['minFee'])) target_address = P2wpkhAddress(getAddress(target)) sender_address = P2wpkhAddress(getAddress(sender)) sender_balance = 0 amount = convertToSatoshis(Decimal(data[2])) + fee unspent = requests.get( f"{config.apiUrl}/unspent/{sender_address.to_string()}" ).json()["result"] txin = [] for i in range(0, len(unspent)): sender_balance += unspent[i]['value'] txin.append( TxInput(unspent[i]['txid'], unspent[i]['index'])) if sender_balance >= amount: txout = [] txout.append( TxOutput((amount - fee), target_address.to_script_pub_key())) txchange = sender_balance - amount if txchange > 0: txout.append( TxOutput(txchange, sender_address.to_script_pub_key())) script_code = Script([ 'OP_DUP', 'OP_HASH160', sender_wif.get_public_key().to_hash160(), 'OP_EQUALVERIFY', 'OP_CHECKSIG' ]) tx = Transaction(txin, txout, has_segwit=True) tx.witnesses = [] for i in range(0, len(unspent)): value = unspent[i]['value'] sig = sender_wif.sign_segwit_input( tx, i, script_code, value) tx.witnesses.append( Script([sig, sender_wif.get_public_key().to_hex()])) post_data = {'raw': tx.serialize()} txid = requests.post(f"{config.apiUrl}/broadcast", data=post_data).json()['result'] ctx.bot.send_message( chat_id=chID, text= f"Success, sent @{db.getUserName(data[1])} {data[2]} {config.coin['ticker']}." ) ctx.bot.send_message( chat_id=chID, text= f"[View Transaction](https://sugar\\.wtf/esplora/tx/{str(txid)})", parse_mode="MarkdownV2") else: ctx.bot.send_message( chat_id=chID, text="You do not have enough funds to tip that amount") elif data[0] == "N": ctx.bot.delete_message(chat_id=chID, message_id=msgID) ctx.bot.send_message( chat_id=chID, text= f"You declined sending @{db.getUserName(data[1])} {data[2]} {config.coin['ticker']}" ) elif data[4] == "w": if data[0] == "Y": ctx.bot.delete_message(chat_id=chID, message_id=msgID) sender_wif = PrivateKey(db.getWIF(sender)) fee = convertToSatoshis(Decimal(config.coin['minFee'])) sender_address = P2wpkhAddress(getAddress(sender)) sender_balance = 0 amount = convertToSatoshis(Decimal(data[2])) + fee target_address = P2wpkhAddress("sugar1q" + data[1]) unspent = requests.get( f"{config.apiUrl}/unspent/{sender_address.to_string()}" ).json()['result'] txin = [] for i in range(0, len(unspent)): sender_balance += unspent[i]['value'] txin.append( TxInput(unspent[i]['txid'], unspent[i]['index'])) if sender_balance >= amount: txout = [] txout.append( TxOutput((amount - fee), target_address.to_script_pub_key())) txchange = sender_balance - amount if txchange > 0: txout.append( TxOutput(txchange, sender_address.to_script_pub_key())) script_code = Script([ 'OP_DUP', 'OP_HASH160', sender_wif.get_public_key().to_hash160(), 'OP_EQUALVERIFY', 'OP_CHECKSIG' ]) tx = Transaction(txin, txout, has_segwit=True) tx.witnesses = [] for i in range(0, len(unspent)): value = unspent[i]['value'] sig = sender_wif.sign_segwit_input( tx, i, script_code, value) tx.witnesses.append( Script([sig, sender_wif.get_public_key().to_hex()])) post_data = {'raw': tx.serialize()} txid = requests.post(f"{config.apiUrl}/broadcast", data=post_data).json()['result'] ctx.bot.send_message( chat_id=chID, text= f"Success, withdrew {data[2]} {config.coin['ticker']} to address {target_address.to_string()} " ) ctx.bot.send_message( chat_id=chID, text= f"[View Transaction](https://sugar\\.wtf/esplora/tx/{str(txid)})", parse_mode="MarkdownV2") else: ctx.bot.send_message( chat_id=chID, text= "You do not have enough funds to withdraw the specified amount." ) elif data[0] == "N": ctx.bot.delete_message(chat_id=chID, message_id=msgID) ctx.bot.send_message( chat_id=chID, text= f"You declined withdrawing {data[2]} {config.coin['ticker']} to address {'sugar1q' + data[1]}" )
def test_p2wpkh_creation_pubkey(self): addr = P2wpkhAddress.from_hash(self.pub.get_segwit_address().to_hash()) self.assertTrue(self.correct_p2wpkh_address, addr.to_string())
def issue_op_return(conf, op_return_bstring, interactive=False): op_return_hex = binascii.hexlify(op_return_bstring).decode() if interactive: print('\nConfigured values are:\n') print('working_directory:\t{}'.format(conf.working_directory)) print('issuing_address:\t{}'.format(conf.issuing_address)) print('full_node_url:\t\t{}'.format(conf.full_node_url)) print('full_node_rpc_user:\t{}'.format(conf.full_node_rpc_user)) print('testnet:\t\t{}'.format(conf.testnet)) print('tx_fee_per_byte:\t{}'.format(conf.tx_fee_per_byte)) print('Bytes for OP_RETURN:\n{}'.format(op_return_bstring)) print('Hex for OP_RETURN:\n{}'.format(op_return_hex)) op_return_cert_protocol = op_return_hex if interactive: consent = input('Do you want to continue? [y/N]: ').lower() in ('y', 'yes') if not consent: sys.exit() #import time #start = time.time() # test explicitly when non interactive if not conf.full_node_rpc_password and interactive: conf.full_node_rpc_password = getpass.getpass('\nPlease enter the password for the node\'s RPC user: '******'testnet') else: setup('mainnet') host, port = conf.full_node_url.split(':') # TODO: update when NodeProxy accepts full url! proxy = NodeProxy(conf.full_node_rpc_user, conf.full_node_rpc_password, host, port).get_proxy() # checks if address is native segwit or not. is_address_bech32 = False if (conf.issuing_address.startswith('bc') or conf.issuing_address.startswith('tb')): is_address_bech32 = True # create transaction tx_outputs = [] unspent = sorted(proxy.listunspent(1, 9999999, [conf.issuing_address]), key=lambda x: x['amount'], reverse=False) if not unspent: raise ValueError("No UTXOs found") issuing_pubkey = proxy.getaddressinfo(conf.issuing_address)['pubkey'] tx = None tx_inputs = [] inputs_amount = 0 # coin selection: use smallest UTXO and if not enough satoshis add next # smallest, etc. until sufficient tx fees are accumulated # TODO wrt dust instead of adding another UTXO we should just remove the # change_output and allocate the remaining (<546sats) to fees for utxo in unspent: txin = TxInput(utxo['txid'], utxo['vout']) tx_inputs.append(txin) inputs_amount += utxo['amount'] # currently bitcoin lib requires explicit instantiation; made method to # check this; update if/when the library fixes/automates this change_script_out = None if is_address_bech32: change_script_out = P2wpkhAddress(conf.issuing_address).to_script_pub_key() else: change_script_out = P2pkhAddress(conf.issuing_address).to_script_pub_key() change_output = TxOutput(to_satoshis(inputs_amount), change_script_out) op_return_output = TxOutput(to_satoshis(0), Script(['OP_RETURN', op_return_cert_protocol])) tx_outputs = [ change_output, op_return_output ] tx = Transaction(tx_inputs, tx_outputs, has_segwit=is_address_bech32) # sign transaction to get its size r = proxy.signrawtransactionwithwallet(tx.serialize()) if r['complete'] == None: if interactive: sys.exit("Transaction couldn't be signed by node") else: raise RuntimeError("Transaction couldn't be signed by node") signed_tx = r['hex'] signed_tx_size = proxy.decoderawtransaction(signed_tx)['vsize'] # calculate fees and change in satoshis tx_fee = signed_tx_size * conf.tx_fee_per_byte change_amount = to_satoshis(inputs_amount) - tx_fee # the default Bitcoin Core node doesn't allow the creation of dust UTXOs # https://bitcoin.stackexchange.com/questions/10986/what-is-meant-by-bitcoin-dust # if change is less than 546 satoshis that is considered dust (with the # default node parameters) then include another UTXO if change_amount >= 550: break if(change_amount < 0): if interactive: sys.exit("Specified address cannot cover the transaction fee of: {} satoshis".format(tx_fee)) else: raise RuntimeError("insufficient satoshis, cannot create transaction") # update tx out for change and re-sign tx.outputs[0].amount = change_amount r = proxy.signrawtransactionwithwallet(tx.serialize()) if r['complete'] == None: if interactive: sys.exit("Transaction couldn't be signed by node") else: raise RuntimeError("Transaction couldn't be signed by node") signed_tx = r['hex'] # send transaction if interactive: print('The fee will be {} satoshis.\n'.format(tx_fee)) consent = input('Do you want to issue on the blockchain? [y/N]: ').lower() in ('y', 'yes') if not consent: sys.exit() tx_id = proxy.sendrawtransaction(signed_tx) #end = time.time() #print("publish_hash.issue_op_return()", end-start, " seconds") return tx_id