zbxcat/xcat.py

233 lines
8.8 KiB
Python
Raw Normal View History

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()
# 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()
# 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