def hashtimelockcontract(self, funder, redeemer, commitment, locktime): funderAddr = CBitcoinAddress(funder) redeemerAddr = CBitcoinAddress(redeemer) if type(commitment) == str: commitment = x(commitment) # h = sha256(secret) blocknum = self.zcashd.getblockcount() print("Current blocknum on Zcash: ", blocknum) redeemblocknum = blocknum + locktime print("Redeemblocknum on Zcash: ", redeemblocknum) # can rm op_dup and op_hash160 if you replace addrs with pubkeys (as raw hex/bin data?), and can rm last op_equalverify (for direct pubkey comparison) zec_redeemScript = CScript([ OP_IF, OP_SHA256, commitment, OP_EQUALVERIFY, OP_DUP, OP_HASH160, redeemerAddr, OP_ELSE, redeemblocknum, OP_CHECKLOCKTIMEVERIFY, OP_DROP, OP_DUP, OP_HASH160, funderAddr, OP_ENDIF, OP_EQUALVERIFY, OP_CHECKSIG ]) # print("Redeem script for p2sh contract on Zcash blockchain: ", b2x(zec_redeemScript)) txin_scriptPubKey = zec_redeemScript.to_p2sh_scriptPubKey() # Convert the P2SH scriptPubKey to a base58 Bitcoin address txin_p2sh_address = CBitcoinAddress.from_scriptPubKey( txin_scriptPubKey) p2sh = str(txin_p2sh_address) print("p2sh computed: ", p2sh) # Import address as soon as you create it self.zcashd.importaddress(p2sh, "", False) # Returning all this to be saved locally in p2sh.json return { 'p2sh': p2sh, 'redeemblocknum': redeemblocknum, 'redeemScript': b2x(zec_redeemScript), 'redeemer': redeemer, 'funder': funder, 'locktime': locktime }
def make_htlc(data): contract = {} print('making htlc') funderAddr = CBitcoinAddress(data['initiator']) redeemerAddr = CBitcoinAddress(data['fulfiller']) blocknum = zcashd.getblockcount() print("Current blocknum", blocknum) redeemblocknum = blocknum + int(data['timeLock']) print("redeemblocknum", redeemblocknum) # secret = get_secret() # print(secret) secret = data['secret'] hash_of_secret = sha256(secret) print(b2x(hash_of_secret)) print(type(hash_of_secret)) print("REDEEMBLOCKNUM ZCASH", redeemblocknum) zec_redeemScript = CScript([ OP_IF, OP_SHA256, hash_of_secret, OP_EQUALVERIFY, OP_DUP, OP_HASH160, redeemerAddr, OP_ELSE, redeemblocknum, OP_CHECKLOCKTIMEVERIFY, OP_DROP, OP_DUP, OP_HASH160, funderAddr, OP_ENDIF, OP_EQUALVERIFY, OP_CHECKSIG ]) print("Redeem script for p2sh contract on Zcash blockchain:", b2x(zec_redeemScript)) txin_scriptPubKey = zec_redeemScript.to_p2sh_scriptPubKey() # Convert the P2SH scriptPubKey to a base58 Bitcoin address txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey) p2sh = str(txin_p2sh_address) # Returning all this to be saved locally in contract.json contract['hash_of_secret'] = b2x(hash_of_secret) contract['redeemblocknum'] = redeemblocknum contract['redeemScript'] = b2x(zec_redeemScript) contract['p2sh'] = p2sh save_contract(contract) return contract
def hashtimelockcontract(funder, redeemer, secret, locktime): funderAddr = CBitcoinAddress(funder) redeemerAddr = CBitcoinAddress(redeemer) h = sha256(secret) blocknum = zcashd.getblockcount() print("Current blocknum", blocknum) redeemblocknum = blocknum + locktime print("REDEEMBLOCKNUM ZCASH", redeemblocknum) zec_redeemScript = CScript([ OP_IF, OP_SHA256, h, OP_EQUALVERIFY, OP_DUP, OP_HASH160, redeemerAddr, OP_ELSE, redeemblocknum, OP_CHECKLOCKTIMEVERIFY, OP_DROP, OP_DUP, OP_HASH160, funderAddr, OP_ENDIF, OP_EQUALVERIFY, OP_CHECKSIG ]) print("Redeem script for p2sh contract on Zcash blockchain:", b2x(zec_redeemScript)) txin_scriptPubKey = zec_redeemScript.to_p2sh_scriptPubKey() # Convert the P2SH scriptPubKey to a base58 Bitcoin address txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey) p2sh = str(txin_p2sh_address) # Returning all this to be saved locally in p2sh.json return { 'p2sh': p2sh, 'redeemblocknum': redeemblocknum, 'redeemScript': b2x(zec_redeemScript), 'redeemer': redeemer, 'funder': funder }
def get_keys(funder_address, redeemer_address): fundpubkey = CBitcoinAddress(funder_address) redeempubkey = CBitcoinAddress(redeemer_address) # fundpubkey = zcashd.getnewaddress() # redeempubkey = zcashd.getnewaddress() return (fundpubkey, redeempubkey)
def listunspent(self, minconf=0, maxconf=9999999, addrs=None): """Return unspent transaction outputs in wallet Outputs will have between minconf and maxconf (inclusive) confirmations, optionally filtered to only include txouts paid to addresses in addrs. """ r = None if addrs is None: r = self._call('listunspent', minconf, maxconf) else: addrs = [str(addr) for addr in addrs] r = self._call('listunspent', minconf, maxconf, addrs) r2 = [] for unspent in r: unspent['outpoint'] = COutPoint(lx(unspent['txid']), unspent['vout']) unspent['address'] = CBitcoinAddress(unspent['address']) unspent['scriptPubKey'] = CScript( unhexlify(unspent['scriptPubKey'])) unspent['amount'] = int(unspent['amount'] * COIN) r2.append(unspent) return r2
def getrawchangeaddress(self): """Returns a new zcash address, for receiving change. This is for use with raw transactions, NOT normal use. """ r = self._call('getrawchangeaddress') return CBitcoinAddress(r)
def find_recipient(self, contract): # make this dependent on actual fund tx to p2sh, not contract txid = contract.fund_tx raw = self.zcashd.gettransaction(lx(txid), True)['hex'] decoded = self.zcashd.decoderawtransaction(raw) scriptSig = decoded['vin'][0]['scriptSig'] print("Decoded", scriptSig) asm = scriptSig['asm'].split(" ") pubkey = asm[1] initiator = CBitcoinAddress(contract.initiator) fulfiller = CBitcoinAddress(contract.fulfiller) print("Initiator", b2x(initiator)) print("Fulfiller", b2x(fulfiller)) print('pubkey', pubkey) redeemPubkey = P2PKHBitcoinAddress.from_pubkey(x(pubkey)) print('redeemPubkey', redeemPubkey)
def find_transaction_to_address(p2sh): zcashd.importaddress(p2sh, '', False) txs = zcashd.listunspent() for tx in txs: if tx['address'] == CBitcoinAddress(p2sh): print ('Found tx to p2sh', p2sh) return tx
def find_transaction_to_address(self, p2sh): self.zcashd.importaddress(p2sh, "", False) txs = self.zcashd.listunspent(0, 100) for tx in txs: if tx['address'] == CBitcoinAddress(p2sh): print("Found tx to p2sh", p2sh) return tx
def validateaddress(self, address): """Return information about an address""" r = self._call('validateaddress', str(address)) if r['isvalid']: r['address'] = CBitcoinAddress(r['address']) if 'pubkey' in r: r['pubkey'] = unhexlify(r['pubkey']) return r
def getnewaddress(self, account=None): """Return a new zcash address for receiving payments. If account is not None, it is added to the address book so payments received with the address will be credited to account. """ r = None if account is not None: r = self._call('getnewaddress', account) else: r = self._call('getnewaddress') return CBitcoinAddress(r)
def payment_ack(serialized_Payment_message): """Generates a PaymentACK object, captures client refund address and returns a message""" pao = o.PaymentACK() pao.payment.ParseFromString(serialized_Payment_message) pao.memo = 'String shown to user after payment confirmation' refund_address = CBitcoinAddress.from_scriptPubKey( CScript(pao.payment.refund_to[0].script)) sds_pa = pao.SerializeToString() open('sds_pa_blob', 'wb').write(sds_pa) headers = { 'Content-Type': 'application/bitcoin-payment', 'Accept': 'application/bitcoin-paymentack' } http_response_object = urllib2.Request('file:sds_pa_blob', None, headers) return http_response_object
# Create a redeemScript. Similar to a scriptPubKey the redeemScript must be # satisfied for the funds to be spent. txin_redeemScript = CScript([seckey.pub, OP_CHECKSIG]) print(b2x(txin_redeemScript)) # Create the magic P2SH scriptPubKey format from that redeemScript. You should # look at the CScript.to_p2sh_scriptPubKey() function in zcash.core.script to # understand what's happening, as well as read BIP16: # https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki txin_scriptPubKey = txin_redeemScript.to_p2sh_scriptPubKey() print('scriptPubKey:', str(txin_scriptPubKey)) # Convert the P2SH scriptPubKey to a base58 zcash address and print it. # You'll need to send some funds to it to create a txout to spend. txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey) print('Pay to:', str(txin_p2sh_address)) # Same as the txid:vout the createrawtransaction RPC call requires # # lx() takes *little-endian* hex and converts it to bytes; in Bitcoin # transaction hashes are shown little-endian rather than the usual big-endian. # There's also a corresponding x() convenience function that takes big-endian # hex and converts it to bytes. txid = lx('bff785da9f8169f49be92fa95e31f0890c385bfb1bd24d6b94d7900057c617ae') vout = 0 # Create the txin structure, which includes the outpoint. The scriptSig # defaults to being empty. txin = CMutableTxIn(COutPoint(txid, vout))
# ========================= LOCKTIME SCRIPT CREATION ========================= lockduration = 20 # Must be more than first tx blocknum = zcashd.getblockcount() redeemblocknum = blocknum + lockduration zec_redeemScript = CScript([ OP_IF, OP_SHA256, h, OP_EQUALVERIFY, OP_DUP, OP_HASH160, bobpubkey, OP_ELSE, redeemblocknum, OP_CHECKLOCKTIMEVERIFY, OP_DROP, OP_DUP, OP_HASH160, alicepubkey, OP_ENDIF, OP_EQUALVERIFY, OP_CHECKSIG ]) print("TX2 Redeem script on Zcash blockchain:", b2x(zec_redeemScript)) # ========================= TX1: CREATE BITCOIN P2SH FROM SCRIPT ========================= txin_scriptPubKey = zec_redeemScript.to_p2sh_scriptPubKey() # Convert the P2SH scriptPubKey to a base58 Bitcoin address txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey) p2sh = str(txin_p2sh_address) print('Alice -- send funds to this p2sh address to initiate atomic swap:', p2sh) response = input( "Alice -- Type 'enter' to allow zbxcat to fund the Zcash p2sh on your behalf:" ) send_amount = 10.0 * COIN fund_tx = zcashd.sendtoaddress(txin_p2sh_address, send_amount) print( 'Bob -- Alice send fund tx to the Zcash p2sh. Please wait for confirmation. Txid:', b2x(lx(b2x(fund_tx)))) # ========================= CONFIRM ZCASH FUNDING TX TO P2SH ========================= zcashd.importaddress(p2sh)
# Preimage for HTLC preimage = b'helloworld' print('preimage to hex', b2x(preimage)) hashstring = hashlib.sha256(preimage).digest() print('hashstring: ', b2x(hashstring)) # Create a redeemScript. Similar to a scriptPubKey the redeemScript must be # satisfied for the funds to be spent. txin_redeemScript = CScript([OP_SHA256, hashstring, OP_EQUAL]) print(b2x(txin_redeemScript)) # Create the magic P2SH scriptPubKey format from redeemScript txin_scriptPubKey = txin_redeemScript.to_p2sh_scriptPubKey() # Convert the P2SH scriptPubKey to a base58 Zcash address txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey) print('Pay to:', str(txin_p2sh_address)) # Fund the P2SH address amount = 1.0 * COIN txid = proxy.sendtoaddress(txin_p2sh_address, amount) print('fund tx', b2x(txid)) #### # lx() takes *little-endian* hex and converts it to bytes; in Bitcoin # transaction hashes are shown little-endian rather than the usual big-endian. # txid = lx('7064c9c78c4839c456ae13be70a184c0f773ec57c083a17ed18846be9072a61a') # vout = 1 txinfo = proxy.gettransaction(txid) details = txinfo['details'][0]
txin = CMutableTxIn(COutPoint(txid, vout)) # We also need the scriptPubKey of the output we're spending because # SignatureHash() replaces the transaction scriptSig's with it. # # Here we'll create that scriptPubKey from scratch using the pubkey that # corresponds to the secret key we generated above. txin_scriptPubKey = CScript( [OP_DUP, OP_HASH160, Hash160(seckey.pub), OP_EQUALVERIFY, OP_CHECKSIG]) # Create the txout. This time we create the scriptPubKey from a Bitcoin # address. txout = CMutableTxOut( 0.001 * COIN, CBitcoinAddress('1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8').to_scriptPubKey()) # Create the unsigned transaction. tx = CMutableTransaction([txin], [txout]) # Calculate the signature hash for that transaction. sighash = SignatureHash(txin_scriptPubKey, 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]) # Verify the signature worked. This calls EvalScript() and actually executes
def get_keys(self, funder_address, redeemer_address): fundpubkey = CBitcoinAddress(funder_address) redeempubkey = CBitcoinAddress(redeemer_address) return fundpubkey, redeempubkey
def getaccountaddress(self, account=None): """Return the current zcash address for receiving payments to this account.""" r = self._call('getaccountaddress', account) return CBitcoinAddress(r)