2017-05-22 18:00:34 -07:00
import zXcat
import bXcat
from utils import *
from waiting import *
from time import sleep
import json
import os
from pprint import pprint
def check_p2sh ( currency , address ) :
if currency == ' bitcoin ' :
print ( " Checking funds in btc p2sh " )
return bXcat . check_funds ( address )
else :
print ( " Checking funds in zec p2sh " )
return zXcat . check_funds ( address )
def set_price ( ) :
trade = { }
#TODO: make currencies interchangeable. Save to a tuple?
2017-05-23 00:03:42 -07:00
sell = input ( " Which currency would you like to trade out of? (bitcoin) " )
2017-05-22 18:00:34 -07:00
sell = ' bitcoin '
buy = ' zcash '
sell_amt = input ( " How much {0} do you want to sell? " . format ( sell ) )
buy_amt = input ( " How much {0} do you want to receive in exchange? " . format ( buy ) )
2017-05-22 21:18:44 -07:00
sell = { ' currency ' : sell , ' amount ' : 1.2 }
buy = { ' currency ' : buy , ' amount ' : 2.45 }
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
def initiate_trade ( ) :
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.
secret = ' test '
locktime = 20 # Must be more than first tx
# Returns contract obj
2017-05-22 21:18:44 -07:00
contracts = { }
2017-05-22 18:00:34 -07:00
contract = create_htlc ( currency , trade [ ' sell ' ] [ ' initiator ' ] , trade [ ' sell ' ] [ ' fulfiller ' ] , secret , locktime )
2017-05-22 21:18:44 -07:00
sell_p2sh = contract [ ' p2sh ' ]
contracts [ contract [ ' p2sh ' ] ] = contract
save_contract ( contracts )
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 ' ]
print ( " Now creating buy contract on the {0} blockchain where you will wait for fulfiller 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 )
buy_p2sh = buy_contract [ ' p2sh ' ]
contracts [ buy_contract [ ' p2sh ' ] ] = buy_contract
save_contract ( contracts )
2017-05-22 18:00:34 -07:00
print ( " Waiting for buyer to send funds to this p2sh " , buy_p2sh )
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()
print ( fulfill_bid_addr )
fulfill_bid_addr = ' tmTjZSg4pX2Us6V5HttiwFZwj464fD2ZgpY '
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 buyer_fulfill ( ) :
trade = get_trade ( )
print ( ' trade ' , 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 )
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 ' ] ) )
amount = trade [ ' buy ' ] [ ' amount ' ]
currency = trade [ ' buy ' ] [ ' currency ' ]
if buy_amount == 0 :
input ( " You have not send funds to the contract to buy {1} (amount: {0} ), type ' enter ' to fund. " . format ( amount , currency ) )
p2sh = trade [ ' buy ' ] [ ' p2sh ' ]
input ( " Type ' enter ' to allow this program to send the agreed upon funds on your behalf " )
txid = fund_htlc ( currency , p2sh , amount )
trade [ ' buy ' ] [ ' fund_tx ' ] = txid
2017-05-23 12:28:48 -07:00
save_trade ( trade )
2017-05-22 18:00:34 -07:00
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. " )
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
def seller_redeem ( ) :
# add locktime as variable?
trade = get_trade ( )
2017-05-22 21:57:06 -07:00
# Seller redeems buyer's funded tx (contract in p2sh)
p2sh = trade [ ' buy ' ] [ ' p2sh ' ]
2017-05-23 11:22:21 -07:00
currency = trade [ ' buy ' ] [ ' currency ' ]
2017-05-23 12:28:48 -07:00
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
def buyer_redeem ( ) :
trade = get_trade ( )
2017-05-22 21:57:06 -07:00
# Buyer redeems seller's funded tx
p2sh = trade [ ' sell ' ] [ ' p2sh ' ]
2017-05-23 11:22:21 -07:00
currency = trade [ ' sell ' ] [ ' currency ' ]
2017-05-23 12:28:48 -07:00
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-23 12:28:48 -07:00
print ( " ZEC <-> BTC XCAT (Cross-Chain Atomic Transactions) " )
2017-05-22 18:00:34 -07:00
role = input ( " Would you like to initiate or accept a trade? " )
# Have initiator propose amounts to trade
# TODO: Get trade indicated by id number
# TODO: pass trade into functions?
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 11:22:21 -07:00
# If there is no status on a sell order (for this json file db...) we assume you must initiate_trade
if ' status ' not in trade [ ' sell ' ] :
role = ' i '
2017-05-23 12:28:48 -07:00
elif trade [ ' sell ' ] [ ' status ' ] == ' redeemed ' and trade [ ' buy ' ] [ ' status ' ] == ' redeemed ' :
print ( " This trade is already complete! Trade details: " )
pprint ( trade )
exit ( )
2017-05-23 11:22:21 -07:00
2017-05-22 18:00:34 -07:00
if role == " i " :
2017-05-22 21:18:44 -07:00
if ' status ' not in trade [ ' sell ' ] :
2017-05-22 18:00:34 -07:00
set_price ( )
get_addresses ( )
initiate_trade ( )
print ( " XCATDB Trade " , trade )
2017-05-22 21:18:44 -07:00
elif ' status ' in trade [ ' sell ' ] :
if trade [ ' sell ' ] [ ' status ' ] == ' funded ' :
# Means buyer has already funded the currency the transaction initiator wants to exchange into
2017-05-23 11:22:21 -07:00
print ( " Buyer funded the contract where you offered to buy {0} , redeeming funds from {1} ... " . format ( trade [ ' buy ' ] [ ' currency ' ] , trade [ ' buy ' ] [ ' p2sh ' ] ) )
2017-05-22 21:18:44 -07:00
seller_redeem ( )
2017-05-22 18:00:34 -07:00
else :
2017-05-23 12:28:48 -07:00
if trade [ ' buy ' ] [ ' status ' ] == ' redeemed ' :
# Seller has redeemed buyer's tx, buyer can now redeem.
print ( " The seller has redeemed the contract where you paid them in {0} , now redeeming your funds from {1} " . format ( trade [ ' buy ' ] [ ' currency ' ] , trade [ ' sell ' ] [ ' p2sh ' ] ) )
buyer_redeem ( )
elif trade [ ' sell ' ] [ ' status ' ] == ' funded ' :
2017-05-22 18:00:34 -07:00
trade = get_trade ( )
buyer_fulfill ( )
# How to monitor if txs are included in blocks -- should use blocknotify and a monitor daemon?
# For regtest, can mock in a function
# p2sh = trade['buy']['p2sh']
# check_blocks(p2sh)
pprint ( get_trade ( ) )
2017-05-23 12:28:48 -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