mirror of
https://github.com/bisq-network/bisq-api-reference.git
synced 2026-01-27 17:43:33 +00:00
This might give Python devs an easier time than if all the sample code lived deep inside a gradle project. This means there is no root project gradle build file; the reference-doc-builder and java-examples modules are separate java projects, with their own build files.
169 lines
7.6 KiB
Python
169 lines
7.6 KiB
Python
import grpc
|
|
|
|
import bisq.api.grpc_pb2 as bisq_messages
|
|
from logger import log
|
|
|
|
WAIT_FOR_TRADE_DEPOSIT_CONFIRMATION = 'WAIT_FOR_TRADE_DEPOSIT_CONFIRMATION'
|
|
WAIT_FOR_PAYMENT_STARTED_MSG = 'WAIT_FOR_PAYMENT_STARTED_MSG'
|
|
WAIT_FOR_PAYMENT_RECEIVED_MSG = 'WAIT_FOR_PAYMENT_RECEIVED_MSG'
|
|
WAIT_FOR_PAYOUT_IS_PUBLISHED = 'WAIT_FOR_PAYOUT_IS_PUBLISHED'
|
|
|
|
SEND_PAYMENT_STARTED_MSG = 'SEND_PAYMENT_STARTED_MSG'
|
|
SEND_PAYMENT_RECEIVED_MSG = 'SEND_PAYMENT_RECEIVED_MSG'
|
|
CLOSE_TRADE = 'CLOSE_TRADE'
|
|
STOP_BOT_OPEN_UI_CONTACT_SUPPORT = 'STOP_BOT_OPEN_UI_CONTACT_SUPPORT'
|
|
|
|
|
|
class ProtocolStep():
|
|
def __init__(self, trades_stub, api_password, trade_id):
|
|
self.trades_stub = trades_stub
|
|
self.api_password = api_password
|
|
self.trade_id = trade_id
|
|
self.timer = None
|
|
|
|
def run(self):
|
|
log.info('Execute automatic protocol step for trade %s.', self.trade_id)
|
|
trade = self.get_trade()
|
|
if self.i_am_buyer(trade) is True:
|
|
self.do_next_buy_step(trade)
|
|
else:
|
|
self.do_next_sell_step(trade)
|
|
|
|
def can_execute(self):
|
|
trade = self.get_trade()
|
|
if self.i_am_buyer(trade) is True:
|
|
next_buy_step = self.get_next_buy_step(trade)
|
|
return next_buy_step != SEND_PAYMENT_STARTED_MSG
|
|
else:
|
|
next_sell_step = self.get_next_sell_step(trade)
|
|
return next_sell_step != SEND_PAYMENT_RECEIVED_MSG
|
|
|
|
def do_next_buy_step(self, trade):
|
|
next_buy_step = self.get_next_buy_step(trade)
|
|
log.info('\tTrade %s: next buy step: %s', trade.trade_id, next_buy_step)
|
|
if next_buy_step == SEND_PAYMENT_STARTED_MSG:
|
|
log.warn('\tPayment must be sent manually, and payment sent msg must be sent from UI.')
|
|
elif next_buy_step == WAIT_FOR_PAYMENT_RECEIVED_MSG:
|
|
log.info('\tPayment sent, waiting for payment received msg ...')
|
|
elif next_buy_step == WAIT_FOR_PAYOUT_IS_PUBLISHED:
|
|
log.info('\tPayment received, waiting for payout tx to be published ...')
|
|
elif next_buy_step == CLOSE_TRADE:
|
|
log.info('\tPayment received, payout tx is published, closing trade ...')
|
|
self.close_trade()
|
|
elif next_buy_step == STOP_BOT_OPEN_UI_CONTACT_SUPPORT:
|
|
log.error('Something bad happened. You have to shutdown the bot,'
|
|
+ ' start the desktop UI, and open a support ticked for trade %s',
|
|
self.trade_id)
|
|
|
|
def do_next_sell_step(self, trade):
|
|
next_sell_step = self.get_next_sell_step(trade)
|
|
log.info('\tTrade %s: next sell step: %s', trade.trade_id, next_sell_step)
|
|
if next_sell_step == WAIT_FOR_PAYMENT_STARTED_MSG:
|
|
log.info('\tWaiting for buyer to start payment ...')
|
|
if next_sell_step == SEND_PAYMENT_RECEIVED_MSG:
|
|
log.warn('\tPayment receipt must be confirmed manually, and payment received'
|
|
+ ' confirmation msg must be sent from UI.')
|
|
elif next_sell_step == WAIT_FOR_PAYOUT_IS_PUBLISHED:
|
|
log.info('\tPayment received, waiting for payout tx to be published ...')
|
|
elif next_sell_step == CLOSE_TRADE:
|
|
log.info('\tPayment received, payout tx is published, closing trade ...')
|
|
self.close_trade()
|
|
elif next_sell_step == STOP_BOT_OPEN_UI_CONTACT_SUPPORT:
|
|
log.error('Something bad happened. You have to shutdown the bot,'
|
|
+ ' start the desktop UI, and open a support ticked for trade %s',
|
|
self.trade_id)
|
|
|
|
@staticmethod
|
|
def get_next_buy_step(trade):
|
|
if trade.is_deposit_published is False:
|
|
return WAIT_FOR_TRADE_DEPOSIT_CONFIRMATION
|
|
elif trade.is_deposit_confirmed is False:
|
|
return WAIT_FOR_TRADE_DEPOSIT_CONFIRMATION
|
|
elif trade.is_payment_started_message_sent is False:
|
|
return SEND_PAYMENT_STARTED_MSG
|
|
elif trade.is_payment_started_message_sent is True and trade.is_payment_received_message_sent is False:
|
|
return WAIT_FOR_PAYMENT_RECEIVED_MSG
|
|
elif trade.is_payment_received_message_sent is True and trade.is_payout_published is False:
|
|
return WAIT_FOR_PAYOUT_IS_PUBLISHED
|
|
elif trade.is_payout_published is True:
|
|
return CLOSE_TRADE
|
|
else:
|
|
return STOP_BOT_OPEN_UI_CONTACT_SUPPORT
|
|
|
|
@staticmethod
|
|
def get_next_sell_step(trade):
|
|
if trade.is_deposit_published is False:
|
|
return WAIT_FOR_TRADE_DEPOSIT_CONFIRMATION
|
|
elif trade.is_deposit_confirmed is False:
|
|
return WAIT_FOR_TRADE_DEPOSIT_CONFIRMATION
|
|
elif trade.is_payment_started_message_sent is False:
|
|
return WAIT_FOR_PAYMENT_STARTED_MSG
|
|
elif trade.is_payment_started_message_sent is True and trade.is_payment_received_message_sent is False:
|
|
return SEND_PAYMENT_RECEIVED_MSG
|
|
elif trade.is_payment_received_message_sent is True and trade.is_payout_published is False:
|
|
return WAIT_FOR_PAYOUT_IS_PUBLISHED
|
|
elif trade.is_payout_published is True:
|
|
return CLOSE_TRADE
|
|
else:
|
|
return STOP_BOT_OPEN_UI_CONTACT_SUPPORT
|
|
|
|
@staticmethod
|
|
def i_am_buyer(trade):
|
|
offer = trade.offer
|
|
if offer.is_my_offer is True:
|
|
return offer.direction == 'BUY'
|
|
else:
|
|
return offer.direction == 'SELL'
|
|
|
|
def send_payment_started_msg(self):
|
|
trade = self.get_trade()
|
|
next_buy_step = self.get_next_buy_step(trade)
|
|
if next_buy_step != SEND_PAYMENT_STARTED_MSG:
|
|
raise 'Trade {0} is not in proper state to send a payment started msg.' \
|
|
+ ' Next step should be {1}.'.format(trade.trade_id, next_buy_step)
|
|
log.info('Sending payment started msg for trade %s.', self.trade_id)
|
|
try:
|
|
self.trades_stub.ConfirmPaymentStarted.with_call(
|
|
bisq_messages.ConfirmPaymentStartedRequest(trade_id=self.trade_id),
|
|
metadata=[('password', self.api_password)])
|
|
|
|
except grpc.RpcError as rpc_error:
|
|
print('gRPC API Exception: %s', rpc_error)
|
|
|
|
def send_payment_received_msg(self):
|
|
trade = self.get_trade()
|
|
next_sell_step = self.get_next_sell_step(trade)
|
|
if next_sell_step != SEND_PAYMENT_RECEIVED_MSG:
|
|
raise 'Trade {0} is not in proper state to send a payment received confirmation msg.' \
|
|
+ ' Next step should be {1}.'.format(trade.trade_id, next_sell_step)
|
|
log.info('Sending payment received confirmation msg for trade %s.', self.trade_id)
|
|
try:
|
|
self.trades_stub.ConfirmPaymentReceived.with_call(
|
|
bisq_messages.ConfirmPaymentReceivedRequest(trade_id=self.trade_id),
|
|
metadata=[('password', self.api_password)])
|
|
except grpc.RpcError as rpc_error:
|
|
print('gRPC API Exception: %s', rpc_error)
|
|
|
|
def close_trade(self):
|
|
try:
|
|
self.trades_stub.CloseTrade.with_call(
|
|
bisq_messages.CloseTradeRequest(trade_id=self.trade_id),
|
|
metadata=[('password', self.api_password)])
|
|
except grpc.RpcError as rpc_error:
|
|
print('gRPC API Exception: %s', rpc_error)
|
|
|
|
def get_trade(self):
|
|
try:
|
|
response = self.trades_stub.GetTrade.with_call(
|
|
bisq_messages.GetTradeRequest(trade_id=self.trade_id),
|
|
metadata=[('password', self.api_password)])
|
|
return response[0].trade
|
|
except grpc.RpcError as rpc_error:
|
|
print('gRPC API Exception: %s', rpc_error)
|
|
|
|
def __str__(self):
|
|
description = 'ProtocolStep: trades_stub={0}, trade_id={1}' \
|
|
.format(self.trades_stub,
|
|
str(self.trade_id))
|
|
return description
|