Exemplo n.º 1
0
def spend_sh_fund(tx_ins, wif_keys, tx_outs):
    """
    spend script hash fund
    the key point of an input comes from multisig address is that,
    its sign script is combined with several individual signs
    :param tx_ins: list with tuple(tx_id, idx, balance, address, redeem_script)
    :param wif_keys: private keys in wif format,
        technical should be the same order with the pubkey in redeem script,
        but pycoin has inner control, so here order is not mandatory
    :param tx_outs: balance, receiver_address
    :return: raw hex and tx id
    """
    _txs_in = []
    _un_spent = []
    for tx_id, idx, balance, address, _ in tx_ins:
        # must h2b_rev NOT h2b
        tx_id_b = h2b_rev(tx_id)
        _txs_in.append(TxIn(tx_id_b, idx))

        _un_spent.append(
            Spendable(balance, network.contract.for_address(address), tx_id_b,
                      idx))

    _txs_out = []
    for balance, receiver_address in tx_outs:
        _txs_out.append(
            TxOut(balance, network.contract.for_address(receiver_address)))

    version, lock_time = 1, 0
    tx = Tx(version, _txs_in, _txs_out, lock_time)
    tx.set_unspents(_un_spent)

    # construct hash160_lookup[hash160] = (secret_exponent, public_pair, compressed) for each individual key
    hash160_lookup = build_hash160_lookup(
        [network.parse.wif(wif_key).secret_exponent() for wif_key in wif_keys],
        [secp256k1_generator])

    for i in range(0, len(tx_ins)):
        # you can add some conditions that if the input script is not p2sh type, not provide p2sh_lookup,
        # so that all kinds of inputs can work together
        p2sh_lookup = build_p2sh_lookup([binascii.unhexlify(tx_ins[i][-1])])
        r = BitcoinSolver(tx).solve(hash160_lookup,
                                    i,
                                    hash_type=SIGHASH_ALL,
                                    p2sh_lookup=p2sh_lookup)
        if isinstance(r, bytes):
            tx.txs_in[i].script = r
        else:
            tx.txs_in[i].script = r[0]
            tx.set_witness(i, r[1])

    return tx.as_hex(), tx.id()
Exemplo n.º 2
0
def tether_tx_sh(tx_ins, wif_keys, send_amount, receiver, change_address):
    """
    spend usdt having p2sh utxo
    WARNING!!! THIS FUNCTION IS NOT FULLY TESTED AS MY FUND WAS STOLEN BY A SON OF BITCH
        AFTER I BY ACCIDENT COMMITTED MY PRIVATE KEY!!!
    :param tx_ins: list with tuple(tx_id, idx, balance, address, redeem_script),
        redeem_script is required for p2sh utxo, set it None for p2pkh utxo
    :param wif_keys: private keys of the inputs
    :param send_amount: (display amount) * (10 ** 8)
    :param receiver: address to receive usdt
    :param change_address: address to receive btc change
    """
    _txs_in = []
    _un_spent = []
    total_bal = 0

    for tx_id, idx, balance, address, _ in tx_ins:
        total_bal += balance

        # must h2b_rev NOT h2b
        tx_id_b = h2b_rev(tx_id)
        _txs_in.append(TxIn(tx_id_b, idx))

        _un_spent.append(
            Spendable(balance, network.contract.for_address(address), tx_id_b,
                      idx))

    txn_fee = estimate_p2pkh_tx_bytes(len(tx_ins),
                                      3) * recommend_satoshi_per_byte() / 3

    _txs_out = [
        TxOut(total_bal - txn_fee - MIN_BTC_OUT,
              network.contract.for_address(change_address)),
        TxOut(0, binascii.unhexlify(omni_tether_script(send_amount))),
        TxOut(MIN_BTC_OUT, network.contract.for_address(receiver))
    ]

    version, lock_time = 1, 0
    tx = Tx(version, _txs_in, _txs_out, lock_time)
    tx.set_unspents(_un_spent)

    # construct hash160_lookup[hash160] = (secret_exponent, public_pair, compressed) for each individual key
    hash160_lookup = build_hash160_lookup(
        [network.parse.wif(wif_key).secret_exponent() for wif_key in wif_keys],
        [secp256k1_generator])

    for i in range(0, len(tx_ins)):
        if tx_ins[i][-1]:
            p2sh_lookup = build_p2sh_lookup(
                [binascii.unhexlify(tx_ins[i][-1])])
        else:
            p2sh_lookup = None

        r = BitcoinSolver(tx).solve(hash160_lookup,
                                    i,
                                    hash_type=SIGHASH_ALL,
                                    p2sh_lookup=p2sh_lookup)
        if isinstance(r, bytes):
            tx.txs_in[i].script = r
        else:
            tx.txs_in[i].script = r[0]
            tx.set_witness(i, r[1])

    return tx.as_hex(), tx.id()