2017-05-22 18:00:34 -07:00
import zXcat
import bXcat
from utils import *
from waiting import *
from time import sleep
import json
2017-05-23 13:34:48 -07:00
import os , sys
2017-05-22 18:00:34 -07:00
from pprint import pprint
def check_p2sh ( currency , address ) :
if currency == ' bitcoin ' :
2017-05-23 14:12:01 -07:00
print ( " Checking funds in Bitcoin p2sh " )
2017-05-22 18:00:34 -07:00
return bXcat . check_funds ( address )
else :
2017-05-23 14:12:01 -07:00
print ( " Checking funds in Zcash p2sh " )
2017-05-22 18:00:34 -07:00
return zXcat . check_funds ( address )
def set_price ( ) :
trade = { }
#TODO: make currencies interchangeable. Save to a tuple?
2017-05-23 18:15:05 -07:00
sell = input ( " Which currency would you like to trade out of (bitcoin or zcash)? " )
2017-05-26 09:23:49 -07:00
if sell == ' ' :
sell = ' bitcoin '
2017-05-23 18:15:05 -07:00
if sell == ' bitcoin ' :
buy = ' zcash '
else :
buy = ' bitcoin '
2017-05-26 09:23:49 -07:00
print ( sell )
2017-05-23 18:15:05 -07:00
sell_amt = input ( " How much {0} do you want to sell? " . format ( sell ) )
2017-05-23 13:34:48 -07:00
sell_amt = 3.5
print ( sell_amt )
2017-05-23 18:15:05 -07:00
buy_amt = input ( " How much {0} do you want to receive in exchange? " . format ( buy ) )
2017-05-23 13:34:48 -07:00
buy_amt = 1.2
print ( buy_amt )
sell = { ' currency ' : sell , ' amount ' : sell_amt }
buy = { ' currency ' : buy , ' amount ' : buy_amt }
2017-05-22 18:00:34 -07:00
trade [ ' sell ' ] = sell
trade [ ' buy ' ] = buy
save_trade ( trade )
def create_htlc ( currency , funder , redeemer , secret , locktime ) :
if currency == ' bitcoin ' :
sell_p2sh = bXcat . hashtimelockcontract ( funder , redeemer , secret , locktime )
else :
sell_p2sh = zXcat . hashtimelockcontract ( funder , redeemer , secret , locktime )
return sell_p2sh
def fund_htlc ( currency , p2sh , amount ) :
if currency == ' bitcoin ' :
txid = bXcat . fund_htlc ( p2sh , amount )
else :
txid = zXcat . fund_htlc ( p2sh , amount )
return txid
2017-05-26 09:23:49 -07:00
def create_trade ( ) :
2017-05-22 18:00:34 -07:00
trade = get_trade ( )
currency = trade [ ' sell ' ] [ ' currency ' ]
secret = input ( " Initiating trade: Enter a password to place the {0} you want to sell in escrow: " . format ( currency ) )
# TODO: hash and store secret only locally.
2017-05-26 09:23:49 -07:00
if secret == ' ' :
secret = generate_password ( )
2017-05-23 13:34:48 -07:00
print ( ' Remember your password: ' , secret )
2017-05-22 18:00:34 -07:00
locktime = 20 # Must be more than first tx
# Returns contract obj
contract = create_htlc ( currency , trade [ ' sell ' ] [ ' initiator ' ] , trade [ ' sell ' ] [ ' fulfiller ' ] , secret , locktime )
2017-05-26 09:23:49 -07:00
contracts = { }
2017-05-22 21:18:44 -07:00
sell_p2sh = contract [ ' p2sh ' ]
contracts [ contract [ ' p2sh ' ] ] = contract
save_contract ( contracts )
2017-05-26 09:23:49 -07:00
trade [ ' sell ' ] [ ' redeemblocknum ' ] = contract [ ' redeemblocknum ' ]
trade [ ' sell ' ] [ ' redeemScript ' ] = contract [ ' redeemScript ' ]
2017-05-22 18:00:34 -07:00
print ( ' To complete your sell, send {0} {1} to this p2sh: {2} ' . format ( trade [ ' sell ' ] [ ' amount ' ] , currency , contract [ ' p2sh ' ] ) )
response = input ( " Type ' enter ' to allow this program to send funds on your behalf. " )
print ( " Sent " )
sell_amt = trade [ ' sell ' ] [ ' amount ' ]
txid = fund_htlc ( currency , sell_p2sh , sell_amt )
trade [ ' sell ' ] [ ' p2sh ' ] = sell_p2sh
trade [ ' sell ' ] [ ' fund_tx ' ] = txid
trade [ ' sell ' ] [ ' status ' ] = ' funded '
# TODO: Save secret locally for seller
trade [ ' sell ' ] [ ' secret ' ] = secret
save_trade ( trade )
buy_currency = trade [ ' buy ' ] [ ' currency ' ]
buy_initiator = trade [ ' buy ' ] [ ' initiator ' ]
buy_fulfiller = trade [ ' buy ' ] [ ' fulfiller ' ]
2017-05-23 13:34:48 -07:00
print ( " Now creating buy contract on the {0} blockchain where you will wait for the buyer to send funds... " . format ( buy_currency ) )
2017-05-23 11:22:21 -07:00
buy_contract = create_htlc ( buy_currency , buy_fulfiller , buy_initiator , secret , locktime )
2017-05-26 09:23:49 -07:00
trade [ ' buy ' ] [ ' redeemblocknum ' ] = contract [ ' redeemblocknum ' ]
trade [ ' buy ' ] [ ' redeemScript ' ] = contract [ ' redeemScript ' ]
2017-05-23 11:22:21 -07:00
buy_p2sh = buy_contract [ ' p2sh ' ]
contracts [ buy_contract [ ' p2sh ' ] ] = buy_contract
save_contract ( contracts )
2017-05-23 13:34:48 -07:00
print ( " Now contact the buyer and tell them to send funds to this p2sh: " , buy_p2sh )
2017-05-22 18:00:34 -07:00
trade [ ' buy ' ] [ ' p2sh ' ] = buy_p2sh
save_trade ( trade )
def get_addresses ( ) :
trade = get_trade ( )
sell = trade [ ' sell ' ] [ ' currency ' ]
buy = trade [ ' buy ' ] [ ' currency ' ]
init_offer_addr = input ( " Enter your {0} address: " . format ( sell ) )
2017-05-23 12:28:48 -07:00
# init_offer_addr = bXcat.new_bitcoin_addr()
init_offer_addr = ' myfFr5twPYNwgeXyjCmGcrzXtCmfmWXKYp '
print ( init_offer_addr )
2017-05-22 18:00:34 -07:00
init_bid_addr = input ( " Enter your {0} address: " . format ( buy ) )
2017-05-23 12:28:48 -07:00
# init_bid_addr = zXcat.new_zcash_addr()
init_bid_addr = ' tmFRXyju7ANM7A9mg75ZjyhFW1UJEhUPwfQ '
print ( init_bid_addr )
2017-05-22 18:00:34 -07:00
trade [ ' sell ' ] [ ' initiator ' ] = init_offer_addr
trade [ ' buy ' ] [ ' initiator ' ] = init_bid_addr
fulfill_offer_addr = input ( " Enter the {0} address of the party you want to trade with: " . format ( sell ) )
2017-05-23 12:28:48 -07:00
# fulfill_offer_addr = bXcat.new_bitcoin_addr()
fulfill_offer_addr = ' mrQzUGU1dwsWRx5gsKKSDPNtrsP65vCA3Z '
print ( fulfill_offer_addr )
2017-05-22 18:00:34 -07:00
fulfill_bid_addr = input ( " Enter the {0} address of the party you want to trade with: " . format ( buy ) )
2017-05-23 12:28:48 -07:00
# fulfill_bid_addr = zXcat.new_zcash_addr()
fulfill_bid_addr = ' tmTjZSg4pX2Us6V5HttiwFZwj464fD2ZgpY '
2017-05-23 13:34:48 -07:00
print ( fulfill_bid_addr )
2017-05-22 18:00:34 -07:00
trade [ ' sell ' ] [ ' fulfiller ' ] = fulfill_offer_addr
trade [ ' buy ' ] [ ' fulfiller ' ] = fulfill_bid_addr
# zec_funder, zec_redeemer = zXcat.get_keys(zec_fund_addr, zec_redeem_addr)
trade [ ' id ' ] = 1
save_trade ( trade )
def check_blocks ( p2sh ) :
# blocks = []
with open ( ' watchdata ' , ' r ' ) as infile :
for line in infile :
res = bXcat . search_p2sh ( line . strip ( ' \n ' ) , p2sh )
# blocks.append(line.strip('\n'))
# print(blocks)
# for block in blocks:
# res = bXcat.search_p2sh(block, p2sh)
2017-05-23 11:22:21 -07:00
def redeem_p2sh ( currency , p2sh , action ) :
# action is buy or sell
2017-05-22 18:00:34 -07:00
if currency == ' bitcoin ' :
2017-05-23 11:22:21 -07:00
res = bXcat . redeem ( p2sh , action )
2017-05-22 18:00:34 -07:00
else :
2017-05-23 11:22:21 -07:00
res = zXcat . redeem ( p2sh , action )
2017-05-22 18:00:34 -07:00
return res
2017-05-26 09:23:49 -07:00
def print_trade ( role ) :
print ( " \n Trade status: " )
trade = get_trade ( )
if role == ' seller ' :
pprint ( trade )
else :
del trade [ ' sell ' ] [ ' secret ' ]
pprint ( trade )
## Main functions determining user workflow
def seller_initiate ( ) :
set_price ( )
get_addresses ( )
create_trade ( )
print_trade ( ' seller ' )
2017-05-22 18:00:34 -07:00
def seller_redeem ( ) :
trade = get_trade ( )
2017-05-26 09:23:49 -07:00
input ( " Buyer funded the contract where you offered to buy {0} , type ' enter ' to redeem {1} {0} from {2} . " . format ( trade [ ' buy ' ] [ ' currency ' ] , trade [ ' buy ' ] [ ' amount ' ] , trade [ ' buy ' ] [ ' p2sh ' ] ) )
2017-05-23 14:12:01 -07:00
if ' status ' in trade [ ' buy ' ] and trade [ ' buy ' ] [ ' status ' ] == ' redeemed ' :
2017-05-23 13:34:48 -07:00
print ( " You already redeemed the funds and acquired {0} {1} " . format ( trade [ ' buy ' ] [ ' amount ' ] , trade [ ' buy ' ] [ ' currency ' ] ) )
exit ( )
else :
# Seller redeems buyer's funded tx (contract in p2sh)
p2sh = trade [ ' buy ' ] [ ' p2sh ' ]
currency = trade [ ' buy ' ] [ ' currency ' ]
redeem_tx = redeem_p2sh ( currency , p2sh , ' buy ' )
trade [ ' buy ' ] [ ' redeem_tx ' ] = redeem_tx
trade [ ' buy ' ] [ ' status ' ] = ' redeemed '
save_trade ( trade )
2017-05-22 18:00:34 -07:00
2017-05-26 09:23:49 -07:00
print ( " You have redeemed {0} {1} ! " . format ( trade [ ' buy ' ] [ ' amount ' ] , trade [ ' buy ' ] [ ' currency ' ] ) )
print_trade ( ' seller ' )
def buyer_fulfill ( ) :
trade = get_trade ( )
buy_p2sh = trade [ ' buy ' ] [ ' p2sh ' ]
sell_p2sh = trade [ ' sell ' ] [ ' p2sh ' ]
buy_amount = check_p2sh ( trade [ ' buy ' ] [ ' currency ' ] , buy_p2sh )
sell_amount = check_p2sh ( trade [ ' sell ' ] [ ' currency ' ] , sell_p2sh )
amount = trade [ ' buy ' ] [ ' amount ' ]
currency = trade [ ' buy ' ] [ ' currency ' ]
if buy_amount == 0 :
input ( " The seller ' s p2sh is funded with {0} {1} , type ' enter ' if this is the amount you want to buy in {1} . " . format ( trade [ ' sell ' ] [ ' amount ' ] , trade [ ' sell ' ] [ ' currency ' ] ) )
input ( " You have not send funds to the contract to buy {1} (requested amount: {0} ), type ' enter ' to allow this program to send the agreed upon funds on your behalf. " . format ( amount , currency ) )
p2sh = trade [ ' buy ' ] [ ' p2sh ' ]
txid = fund_htlc ( currency , p2sh , amount )
trade [ ' buy ' ] [ ' fund_tx ' ] = txid
save_trade ( trade )
else :
print ( " It looks like you ' ve already funded the contract to buy {1} , the amount in escrow in the p2sh is {0} . " . format ( amount , currency ) )
print ( " Please wait for the seller to remove your funds from escrow to complete the trade. " )
2017-05-22 18:00:34 -07:00
def buyer_redeem ( ) :
trade = get_trade ( )
2017-05-26 09:23:49 -07:00
input ( " Buyer funded the contract where you paid them in {0} to buy {1} , type ' enter ' to redeem {2} {1} from {3} . " . format ( trade [ ' buy ' ] [ ' currency ' ] , trade [ ' sell ' ] [ ' currency ' ] , trade [ ' buy ' ] [ ' amount ' ] , trade [ ' buy ' ] [ ' p2sh ' ] ) )
2017-05-23 14:12:01 -07:00
if ' status ' in trade [ ' sell ' ] and trade [ ' sell ' ] [ ' status ' ] == ' redeemed ' :
print ( " You already redeemed the funds and acquired {0} {1} " . format ( trade [ ' sell ' ] [ ' amount ' ] , trade [ ' sell ' ] [ ' currency ' ] ) )
exit ( )
else :
# Buyer redeems seller's funded tx
p2sh = trade [ ' sell ' ] [ ' p2sh ' ]
currency = trade [ ' sell ' ] [ ' currency ' ]
redeem_tx = redeem_p2sh ( currency , p2sh , ' sell ' )
trade [ ' sell ' ] [ ' redeem_tx ' ] = redeem_tx
trade [ ' sell ' ] [ ' status ' ] = ' redeemed '
save_trade ( trade )
2017-05-22 18:00:34 -07:00
if __name__ == ' __main__ ' :
2017-05-26 09:23:49 -07:00
# Note: there is some little endian weirdness in the bXcat and zXcat files, need to handle the endianness of txids better & more consistently
2017-05-23 12:28:48 -07:00
print ( " ZEC <-> BTC XCAT (Cross-Chain Atomic Transactions) " )
2017-05-23 18:15:05 -07:00
print ( " = " * 50 )
2017-05-22 18:00:34 -07:00
# TODO: Get trade indicated by id number
2017-05-23 00:03:42 -07:00
# TODO: workflow framed as currency you're trading out of being sell. appropriate?
2017-05-22 18:00:34 -07:00
trade = get_trade ( )
2017-05-23 13:34:48 -07:00
try :
2017-05-23 14:12:01 -07:00
if sys . argv [ 1 ] == ' new ' :
erase_trade ( )
role = ' seller '
trade = get_trade ( )
2017-05-23 18:15:05 -07:00
print ( " Creating new XCAT transaction... " )
2017-05-23 14:12:01 -07:00
else :
role = sys . argv [ 1 ]
print ( " Your role in demo: " , role )
2017-05-23 13:34:48 -07:00
except :
if trade == None :
print ( " No active trades available. " )
res = input ( " Would you like to initiate a trade? (y/n) " )
if res == ' y ' :
role = ' seller '
else :
exit ( )
else :
print ( " Trade exists, run script as buyer or seller to complete trade. " )
exit ( )
if trade is not None :
if trade [ ' sell ' ] [ ' status ' ] == ' redeemed ' and trade [ ' buy ' ] [ ' status ' ] == ' redeemed ' :
print ( " This trade is already complete! Trade details: " )
pprint ( trade )
exit ( )
if role == " seller " :
if trade == None or ' status ' not in trade [ ' sell ' ] :
2017-05-26 09:23:49 -07:00
seller_initiate ( )
2017-05-22 21:18:44 -07:00
elif ' status ' in trade [ ' sell ' ] :
2017-05-23 14:12:01 -07:00
if ' fund_tx ' in trade [ ' buy ' ] :
2017-05-22 21:18:44 -07:00
# Means buyer has already funded the currency the transaction initiator wants to exchange into
seller_redeem ( )
2017-05-23 14:12:01 -07:00
else :
print ( " Buyer has not yet funded the contract where you offered to buy {0} , please wait for them to complete their part. " . format ( trade [ ' buy ' ] [ ' currency ' ] ) )
print_trade ( ' seller ' )
2017-05-22 18:00:34 -07:00
else :
2017-05-23 14:12:01 -07:00
# Need better way of preventing buyer from having secret
2017-05-23 13:34:48 -07:00
if ' status ' not in trade [ ' buy ' ] and trade [ ' sell ' ] [ ' status ' ] == ' funded ' :
print ( " One active trade available, fulfilling buyer contract... " )
2017-05-22 18:00:34 -07:00
buyer_fulfill ( )
2017-05-26 09:23:49 -07:00
# How to monitor if txs are included in blocks?
2017-05-23 13:34:48 -07:00
elif trade [ ' buy ' ] [ ' status ' ] == ' redeemed ' :
# Seller has redeemed buyer's tx, buyer can now redeem.
buyer_redeem ( )
2017-05-23 14:12:01 -07:00
print ( " XCAT trade complete! " )
print_trade ( ' buyer ' )