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())
示例#2
0
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)
示例#4
0
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