def spend_pkh_fund(tx_ins, in_keys, tx_outs): """ p2pkh address send to p2pkh p2sh transaction :param tx_ins: list with tuple(tx_id, idx, balance, address) :param in_keys: list of private keys in hex format corresponding to each input :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)) script = network.contract.for_address(address) _un_spent.append(Spendable(balance, script, 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) solver = build_hash160_lookup([int(pri_hex, 16) for pri_hex in in_keys], [secp256k1_generator]) tx.sign(solver, hash_type=SIGHASH_ALL) return tx.as_hex(), tx.id()
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()
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()