diff --git a/zec-p2sh-htlc.py b/zec-p2sh-htlc.py new file mode 100644 index 0000000..c12d3ff --- /dev/null +++ b/zec-p2sh-htlc.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python3 + +# Copyright (C) 2017 the python-zcashlib developers + +import sys +if sys.version_info.major < 3: + sys.stderr.write('Sorry, Python 3.x required by this example.\n') + sys.exit(1) + +import zcash +import zcash.rpc +from zcash import SelectParams +from zcash.core import b2x, lx, COIN, COutPoint, CMutableTxOut, CMutableTxIn, CMutableTransaction, Hash160 +from zcash.core.script import CScript, OP_DUP, OP_IF, OP_ELSE, OP_DROP, OP_ENDIF, OP_HASH160, OP_SHA256, OP_EQUAL, OP_EQUALVERIFY, OP_CHECKSIG, SignatureHash, SIGHASH_ALL, SIGHASH_ANYONECANPAY, OP_TRUE +from zcash.core.scripteval import VerifyScript, SCRIPT_VERIFY_P2SH +from zcash.wallet import CBitcoinAddress, CBitcoinSecret +import hashlib + +SelectParams('regtest') +proxy = zcash.rpc.Proxy() + +# The parameters needed for the htlc - hash preimage, sender/seller address, recipient/buyer address, num of blocks for timeout +preimage = b'preimage' +h = hashlib.sha256(preimage).digest() + +# proxy.getnewaddress() returns CBitcoinAddress +recipientpubkey = proxy.getnewaddress() +senderpubkey = proxy.getnewaddress() +# privkey of the recipient, used to sign the redeemTx +seckey = proxy.dumpprivkey(recipientpubkey) + +blocknum = 7 +# Create a htlc redeemScript. Similar to a scriptPubKey the redeemScript must be +# satisfied for the funds to be spent. +txin_redeemScript = CScript([OP_IF, OP_SHA256, h, OP_EQUALVERIFY,OP_DUP, OP_HASH160, + recipientpubkey, OP_ELSE, blocknum, OP_DROP, OP_HASH160, + senderpubkey, OP_ENDIF,OP_EQUALVERIFY, OP_CHECKSIG]) +print("redeem script:", b2x(txin_redeemScript)) + +# Create P2SH scriptPubKey from redeemScript. +txin_scriptPubKey = txin_redeemScript.to_p2sh_scriptPubKey() +print("p2sh_scriptPubKey", b2x(txin_scriptPubKey)) + +# Convert the P2SH scriptPubKey to a base58 Bitcoin address +txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey) +p2sh = str(txin_p2sh_address) +print('Pay to:', p2sh) + +# AUTOMATE Send funds to p2sh +amount = 1.0*COIN +fund_tx = proxy.sendtoaddress(txin_p2sh_address, amount) + +print('Now redeeming.........') + +# AUTOMATE getting vout of funding tx +txinfo = proxy.gettransaction(fund_tx) +details = txinfo['details'][0] +vout = details['vout'] + +# Create the txin structure. scriptSig defaults to being empty. +# The input is the p2sh funding transaction txid, vout is its index +txin = CMutableTxIn(COutPoint(fund_tx, vout)) + +# Create the txout. Pays out to recipient, so uses recipient's pubkey +# Withdraw full amount minus fee +default_fee = 0.001*COIN +txout = CMutableTxOut(amount - default_fee, recipientpubkey.to_scriptPubKey()) + +# Create the unsigned raw transaction. +tx = CMutableTransaction([txin], [txout]) + +# Calculate the signature hash for that transaction. Note how the script we use +# is the redeemScript, not the scriptPubKey. EvalScript() will be evaluating the redeemScript +sighash = SignatureHash(txin_redeemScript, tx, 0, SIGHASH_ALL) + +# Now sign it. We have to append the type of signature we want to the end, in +# this case the usual SIGHASH_ALL. +sig = seckey.sign(sighash) + bytes([SIGHASH_ALL]) + +# Set the scriptSig of our transaction input appropriately. +txin.scriptSig = CScript([ sig, seckey.pub, preimage, OP_TRUE, txin_redeemScript]) + +print("Redeem tx hex:", b2x(tx.serialize())) + +# Verify the signature worked. +VerifyScript(txin.scriptSig, txin_scriptPubKey, tx, 0, (SCRIPT_VERIFY_P2SH,)) + +print("Now sending redeem transaction.......") +txid = proxy.sendrawtransaction(tx) +print("Txid of submitted redeem tx: ", b2x(txid))