Move js functions to new file.

This commit is contained in:
tecnovert 2020-11-28 00:20:35 +02:00
parent bc60527940
commit 327394e81b
No known key found for this signature in database
GPG key ID: 8ED6D8750C4E3F93
8 changed files with 221 additions and 168 deletions

View file

@ -751,7 +751,7 @@ class BasicSwap(BaseApp):
assert(amount > chainparams[coin_from][self.chain]['min_amount']), 'From amount below min value for chain'
assert(amount < chainparams[coin_from][self.chain]['max_amount']), 'From amount above max value for chain'
amount_to = (amount * rate) // COIN
amount_to = (amount * rate) // (10 ** chainparams[coin_from]['decimal_places'])
assert(amount_to > chainparams[coin_to][self.chain]['min_amount']), 'To amount below min value for chain'
assert(amount_to < chainparams[coin_to][self.chain]['max_amount']), 'To amount above max value for chain'
@ -992,15 +992,8 @@ class BasicSwap(BaseApp):
override_feerate = self.coin_clients[coin_type].get('override_feerate', None)
if override_feerate:
return override_feerate
try:
return self.callcoinrpc(coin_type, 'estimatesmartfee', [2])['feerate']
except Exception:
try:
fee_rate = self.callcoinrpc(coin_type, 'getwalletinfo')['paytxfee']
assert(fee_rate > 0.0), '0 feerate'
return fee_rate
except Exception:
return self.callcoinrpc(coin_type, 'getnetworkinfo')['relayfee']
return self.ci(coin_type).get_fee_rate()
def withdrawCoin(self, coin_type, value, addr_to, subfee):
self.log.info('withdrawCoin %s %s to %s %s', value, self.getTicker(coin_type), addr_to, ' subfee' if subfee else '')
@ -1719,7 +1712,6 @@ class BasicSwap(BaseApp):
self.log.error('Bid %s - Error: %s', bid_id.hex(), error_str)
bid.setState(BidStates.BID_ERROR)
bid.state_note = 'error msg: ' + error_str
print('[rm] saveBid 5')
self.saveBid(bid_id, bid)
def createInitiateTxn(self, coin_type, bid_id, bid, initiate_script):
@ -3502,7 +3494,6 @@ class BasicSwap(BaseApp):
bid.xmr_b_lock_tx.setState(TxStates.TX_NONE)
#bid.txns[TxTypes.XMR_SWAP_B_LOCK] = xmr_b_lock_tx
print('[rm] saveBidInSession 23')
self.saveBidInSession(bid_id, bid, session, xmr_swap)
# Update copy of bid in swaps_in_progress
@ -3538,7 +3529,6 @@ class BasicSwap(BaseApp):
xmr_swap.coin_a_lock_refund_spend_tx_msg_id = bytes.fromhex(ro['msgid'])
bid.setState(BidStates.XMR_SWAP_SECRET_SHARED)
print('[rm] saveBidInSession 24')
self.saveBidInSession(bid_id, bid, session, xmr_swap)
# Update copy of bid in swaps_in_progress
self.swaps_in_progress[bid_id] = (bid, offer)
@ -3590,7 +3580,6 @@ class BasicSwap(BaseApp):
)
bid.xmr_a_lock_spend_tx.setState(TxStates.TX_NONE)
print('[rm] saveBidInSession 25')
self.saveBidInSession(bid_id, bid, session, xmr_swap)
# Update copy of bid in swaps_in_progress
self.swaps_in_progress[bid_id] = (bid, offer)
@ -3633,7 +3622,6 @@ class BasicSwap(BaseApp):
#print('[rm] TxTypes.XMR_SWAP_B_LOCK', txn.bid_id.hex())
#txn.spend_txid = txid
#bid.txns[TxTypes.XMR_SWAP_B_LOCK].spend_txid = txid
print('[rm] saveBidInSession 26')
self.saveBidInSession(bid_id, bid, session, xmr_swap)
# Update copy of bid in swaps_in_progress
self.swaps_in_progress[bid_id] = (bid, offer)
@ -3674,7 +3662,6 @@ class BasicSwap(BaseApp):
bid.xmr_b_lock_tx.spend_txid = txid
bid.setState(BidStates.XMR_SWAP_NOSCRIPT_TX_RECOVERED)
print('[rm] saveBidInSession 32')
self.saveBidInSession(bid_id, bid, session, xmr_swap)
# Update copy of bid in swaps_in_progress
self.swaps_in_progress[bid_id] = (bid, offer)
@ -3734,7 +3721,6 @@ class BasicSwap(BaseApp):
self.createEvent(delay, EventTypes.SEND_XMR_SWAP_LOCK_TX_A, bid_id)
bid.setState(BidStates.SWAP_DELAYING)
print('[rm] saveBid 27')
self.saveBid(bid_id, bid, xmr_swap=xmr_swap)
except Exception as ex:
if self.debug:
@ -3780,7 +3766,6 @@ class BasicSwap(BaseApp):
assert(v), 'verifyTxOtVES failed'
bid.setState(BidStates.XMR_SWAP_HAVE_SCRIPT_COIN_SPEND_TX)
print('[rm] saveBid 28')
self.saveBid(bid_id, bid, xmr_swap=xmr_swap)
except Exception as ex:
if self.debug:
@ -3835,7 +3820,6 @@ class BasicSwap(BaseApp):
self.createEvent(delay, EventTypes.REDEEM_XMR_SWAP_LOCK_TX_A, bid_id)
bid.setState(BidStates.XMR_SWAP_SECRET_SHARED)
print('[rm] saveBid 29')
self.saveBid(bid_id, bid, xmr_swap=xmr_swap)
self.swaps_in_progress[bid_id] = (bid, offer)
@ -3905,7 +3889,6 @@ class BasicSwap(BaseApp):
for bid_id, v in self.swaps_in_progress.items():
try:
if self.checkBidState(bid_id, v[0], v[1]) is True:
self.log.debug('[rm] removing state: %s', BidStates(v[0].state))
to_remove.append(bid_id)
except Exception as ex:
self.log.error('checkBidState %s %s', bid_id.hex(), str(ex))
@ -3960,7 +3943,6 @@ class BasicSwap(BaseApp):
if has_changed:
session = scoped_session(self.session_factory)
try:
print('[rm] saveBidInSession 30')
self.saveBidInSession(bid_id, bid, session)
session.commit()
if bid.state and bid.state > BidStates.BID_RECEIVED and bid.state < BidStates.SWAP_COMPLETED:
@ -4213,5 +4195,4 @@ class BasicSwap(BaseApp):
self.log.debug('Bid %s Setting debug flag: %s', bid_id.hex(), debug_ind)
bid = self.getBid(bid_id)
bid.debug_ind = debug_ind
print('[rm] saveBid 31')
self.saveBid(bid_id, bid)

View file

@ -192,4 +192,8 @@ chainparams = {
class CoinInterface:
pass
def format_amount(self, amount_int):
return format_amount(feerate, self.exp())
def coin_name(self):
return chainparams[self.coin_type()]['name'].capitalize()

View file

@ -38,6 +38,15 @@ from .basicswap import (
SEQUENCE_LOCK_TIME,
ABS_LOCK_TIME,
)
from .js_server import (
js_error,
js_wallets,
js_offers,
js_sentoffers,
js_bids,
js_sentbids,
js_index,
)
def format_timestamp(value):
@ -250,126 +259,6 @@ class HttpHandler(BaseHTTPRequestHandler):
self.server.last_form_id[name] = form_id
return form_data
def js_error(self, error_str):
error_str_json = json.dumps({'error': error_str})
return bytes(error_str_json, 'UTF-8')
def js_wallets(self, url_split, post_string):
return bytes(json.dumps(self.server.swap_client.getWalletsInfo()), 'UTF-8')
def js_offers(self, url_split, post_string, sent=False):
if len(url_split) > 3:
if url_split[3] == 'new':
if post_string == '':
raise ValueError('No post data')
form_data = urllib.parse.parse_qs(post_string)
offer_id = self.postNewOffer(form_data)
rv = {'offer_id': offer_id.hex()}
return bytes(json.dumps(rv), 'UTF-8')
offer_id = bytes.fromhex(url_split[3])
filters = {
'coin_from': -1,
'coin_to': -1,
'page_no': 1,
'limit': PAGE_LIMIT,
'sort_by': 'created_at',
'sort_dir': 'desc',
}
if post_string != '':
post_data = urllib.parse.parse_qs(post_string)
filters['coin_from'] = setCoinFilter(form_data, b'coin_from')
filters['coin_to'] = setCoinFilter(form_data, b'coin_to')
if b'sort_by' in post_data:
sort_by = post_data[b'sort_by'][0].decode('utf-8')
assert(sort_by in ['created_at', 'rate']), 'Invalid sort by'
filters['sort_by'] = sort_by
if b'sort_dir' in post_data:
sort_dir = post_data[b'sort_dir'][0].decode('utf-8')
assert(sort_dir in ['asc', 'desc']), 'Invalid sort dir'
filters['sort_dir'] = sort_dir
if b'offset' in post_data:
filters['offset'] = int(post_data[b'offset'][0])
if b'limit' in post_data:
filters['limit'] = int(post_data[b'limit'][0])
assert(filters['limit'] > 0 and filters['limit'] <= PAGE_LIMIT), 'Invalid limit'
offers = self.server.swap_client.listOffers(sent, filters)
rv = []
for o in offers:
rv.append({
'offer_id': o.offer_id.hex(),
'created_at': time.strftime('%Y-%m-%d %H:%M', time.localtime(o.created_at)),
'coin_from': getCoinName(Coins(o.coin_from)),
'coin_to': getCoinName(Coins(o.coin_to)),
'amount_from': format8(o.amount_from),
'amount_to': format8((o.amount_from * o.rate) // COIN),
'rate': format8(o.rate)
})
return bytes(json.dumps(rv), 'UTF-8')
def js_sentoffers(self, url_split, post_string):
return self.js_offers(url_split, post_string, True)
def js_bids(self, url_split, post_string):
swap_client = self.server.swap_client
if len(url_split) > 3:
if url_split[3] == 'new':
if post_string == '':
raise ValueError('No post data')
post_data = urllib.parse.parse_qs(post_string)
offer_id = bytes.fromhex(post_data[b'offer_id'][0].decode('utf-8'))
assert(len(offer_id) == 28)
amount_from = inputAmount(post_data[b'amount_from'][0].decode('utf-8'))
addr_from = None
if b'addr_from' in post_data:
addr_from = post_data[b'addr_from'][0].decode('utf-8')
if addr_from == '-1':
addr_from = None
bid_id = swap_client.postBid(offer_id, amount_from, addr_send_from=addr_from).hex()
rv = {'bid_id': bid_id}
return bytes(json.dumps(rv), 'UTF-8')
bid_id = bytes.fromhex(url_split[3])
assert(len(bid_id) == 28)
if post_string != '':
post_data = urllib.parse.parse_qs(post_string)
if b'accept' in post_data:
swap_client.acceptBid(bid_id)
bid, offer = swap_client.getBidAndOffer(bid_id)
assert(bid), 'Unknown bid ID'
edit_bid = False
show_txns = False
data = describeBid(swap_client, bid, offer, edit_bid, show_txns)
return bytes(json.dumps(data), 'UTF-8')
bids = swap_client.listBids()
return bytes(json.dumps([{
'bid_id': b[1].hex(),
'offer_id': b[2].hex(),
'created_at': time.strftime('%Y-%m-%d %H:%M', time.localtime(b[0])),
'amount_from': format8(b[3]),
'bid_state': strBidState(b[4])
} for b in bids]), 'UTF-8')
def js_sentbids(self, url_split, post_string):
return bytes(json.dumps(self.server.swap_client.listBids(sent=True)), 'UTF-8')
def js_index(self, url_split, post_string):
return bytes(json.dumps(self.server.swap_client.getSummary()), 'UTF-8')
def page_explorers(self, url_split, post_string):
swap_client = self.server.swap_client
@ -615,16 +504,19 @@ class HttpHandler(BaseHTTPRequestHandler):
coin_from = Coins(offer.coin_from)
coin_to = Coins(offer.coin_to)
ci_from = swap_client.ci(coin_from)
ci_to = swap_client.ci(coin_to)
ticker_from = swap_client.getTicker(coin_from)
ticker_to = swap_client.getTicker(coin_to)
data = {
'tla_from': swap_client.getTicker(coin_from),
'tla_to': swap_client.getTicker(coin_to),
'state': strOfferState(offer.state),
'coin_from': getCoinName(coin_from),
'coin_to': getCoinName(coin_to),
'amt_from': format8(offer.amount_from),
'amt_to': format8((offer.amount_from * offer.rate) // COIN),
'coin_from': ci_from.coin_name(),
'coin_to': ci_to.coin_name(),
'amt_from': ci_from.format_amount(offer.amount_from),
'amt_to': ci_to.format_amount((offer.amount_from * offer.rate) // COIN),
'rate': format8(offer.rate),
'lock_type': getLockName(offer.lock_type),
'lock_value': offer.lock_value,
@ -852,19 +744,19 @@ class HttpHandler(BaseHTTPRequestHandler):
if len(url_split) > 1 and url_split[1] == 'json':
try:
self.putHeaders(status_code, 'text/plain')
func = self.js_index
func = js_index
if len(url_split) > 2:
func = {'wallets': self.js_wallets,
'offers': self.js_offers,
'sentoffers': self.js_sentoffers,
'bids': self.js_bids,
'sentbids': self.js_sentbids,
}.get(url_split[2], self.js_index)
return func(url_split, post_string)
func = {'wallets': js_wallets,
'offers': js_offers,
'sentoffers': js_sentoffers,
'bids': js_bids,
'sentbids': js_sentbids,
}.get(url_split[2], js_index)
return func(self, url_split, post_string)
except Exception as ex:
if self.server.swap_client.debug is True:
traceback.print_exc()
return self.js_error(str(ex))
return js_error(self, str(ex))
try:
self.putHeaders(status_code, 'text/html')
if len(url_split) > 1:

View file

@ -139,6 +139,17 @@ class BTCInterface(CoinInterface):
args.append('bech32')
return self.rpc_callback('getnewaddress', args)
def get_fee_rate(self):
try:
return self.rpc_callback('estimatesmartfee', [2])['feerate']
except Exception:
try:
fee_rate = self.rpc_callback('getwalletinfo')['paytxfee']
assert(fee_rate > 0.0), '0 feerate'
return fee_rate
except Exception:
return self.rpc_callback('getnetworkinfo')['relayfee']
def decodeAddress(self, address):
bech32_prefix = chainparams[self.coin_type()][self._network]['hrp']
if address.startswith(bech32_prefix):
@ -926,5 +937,6 @@ def testBTCInterface():
print('Passed.')
if __name__ == "__main__":
testBTCInterface()

View file

@ -77,6 +77,7 @@ class XMRInterface(CoinInterface):
return self.rpc_cb('get_block_count')['count']
def getWalletInfo(self):
self.rpc_wallet_cb('open_wallet', {'filename': self._wallet_filename})
rv = {}
balance_info = self.rpc_wallet_cb('get_balance')
rv['balance'] = format_amount(balance_info['unlocked_balance'], XMRInterface.exp())
@ -88,10 +89,14 @@ class XMRInterface(CoinInterface):
return self.rpc_wallet_cb('get_address')['address']
def getNewAddress(self, placeholder):
logging.debug('TODO - subaddress?')
logging.warning('TODO - subaddress?')
self.rpc_wallet_cb('open_wallet', {'filename': self._wallet_filename})
return self.rpc_wallet_cb('get_address')['address']
def get_fee_rate(self):
logging.warning('TODO - estimate fee rate?')
return 0.0012595
def isValidKey(self, key_bytes):
ki = b2i(key_bytes)
return ki < edf.l and ki > 8

160
basicswap/js_server.py Normal file
View file

@ -0,0 +1,160 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2020 tecnovert
# Distributed under the MIT software license, see the accompanying
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
import os
import json
import time
import struct
import traceback
import threading
import urllib.parse
from . import __version__
from .util import (
COIN,
format8,
make_int,
dumpj,
)
from .chainparams import (
chainparams,
Coins,
)
from .basicswap import (
SwapTypes,
BidStates,
TxStates,
TxTypes,
strOfferState,
strBidState,
strTxState,
getLockName,
SEQUENCE_LOCK_TIME,
ABS_LOCK_TIME,
)
def js_error(self, error_str):
error_str_json = json.dumps({'error': error_str})
return bytes(error_str_json, 'UTF-8')
def js_wallets(self, url_split, post_string):
return bytes(json.dumps(self.server.swap_client.getWalletsInfo()), 'UTF-8')
def js_offers(self, url_split, post_string, sent=False):
if len(url_split) > 3:
if url_split[3] == 'new':
if post_string == '':
raise ValueError('No post data')
form_data = urllib.parse.parse_qs(post_string)
offer_id = self.postNewOffer(form_data)
rv = {'offer_id': offer_id.hex()}
return bytes(json.dumps(rv), 'UTF-8')
offer_id = bytes.fromhex(url_split[3])
filters = {
'coin_from': -1,
'coin_to': -1,
'page_no': 1,
'limit': PAGE_LIMIT,
'sort_by': 'created_at',
'sort_dir': 'desc',
}
if post_string != '':
post_data = urllib.parse.parse_qs(post_string)
filters['coin_from'] = setCoinFilter(form_data, b'coin_from')
filters['coin_to'] = setCoinFilter(form_data, b'coin_to')
if b'sort_by' in post_data:
sort_by = post_data[b'sort_by'][0].decode('utf-8')
assert(sort_by in ['created_at', 'rate']), 'Invalid sort by'
filters['sort_by'] = sort_by
if b'sort_dir' in post_data:
sort_dir = post_data[b'sort_dir'][0].decode('utf-8')
assert(sort_dir in ['asc', 'desc']), 'Invalid sort dir'
filters['sort_dir'] = sort_dir
if b'offset' in post_data:
filters['offset'] = int(post_data[b'offset'][0])
if b'limit' in post_data:
filters['limit'] = int(post_data[b'limit'][0])
assert(filters['limit'] > 0 and filters['limit'] <= PAGE_LIMIT), 'Invalid limit'
ci_from = self.server.swap_client.ci(o.coin_from)
ci_to = self.server.swap_client.ci(o.coin_to)
offers = self.server.swap_client.listOffers(sent, filters)
rv = []
for o in offers:
rv.append({
'offer_id': o.offer_id.hex(),
'created_at': time.strftime('%Y-%m-%d %H:%M', time.localtime(o.created_at)),
'coin_from': ci_from.coin_name(),
'coin_to': ci_to.coin_name(),
'amount_from': ci_from.format_amount(o.amount_from),
'amount_to': ci_to.format_amount((o.amount_from * o.rate) // COIN),
'rate': format8(o.rate)
})
return bytes(json.dumps(rv), 'UTF-8')
def js_sentoffers(self, url_split, post_string):
return self.js_offers(url_split, post_string, True)
def js_bids(self, url_split, post_string):
swap_client = self.server.swap_client
if len(url_split) > 3:
if url_split[3] == 'new':
if post_string == '':
raise ValueError('No post data')
post_data = urllib.parse.parse_qs(post_string)
offer_id = bytes.fromhex(post_data[b'offer_id'][0].decode('utf-8'))
assert(len(offer_id) == 28)
amount_from = inputAmount(post_data[b'amount_from'][0].decode('utf-8'))
addr_from = None
if b'addr_from' in post_data:
addr_from = post_data[b'addr_from'][0].decode('utf-8')
if addr_from == '-1':
addr_from = None
bid_id = swap_client.postBid(offer_id, amount_from, addr_send_from=addr_from).hex()
rv = {'bid_id': bid_id}
return bytes(json.dumps(rv), 'UTF-8')
bid_id = bytes.fromhex(url_split[3])
assert(len(bid_id) == 28)
if post_string != '':
post_data = urllib.parse.parse_qs(post_string)
if b'accept' in post_data:
swap_client.acceptBid(bid_id)
bid, offer = swap_client.getBidAndOffer(bid_id)
assert(bid), 'Unknown bid ID'
edit_bid = False
show_txns = False
data = describeBid(swap_client, bid, offer, edit_bid, show_txns)
return bytes(json.dumps(data), 'UTF-8')
bids = swap_client.listBids()
return bytes(json.dumps([{
'bid_id': b[1].hex(),
'offer_id': b[2].hex(),
'created_at': time.strftime('%Y-%m-%d %H:%M', time.localtime(b[0])),
'amount_from': format8(b[3]),
'bid_state': strBidState(b[4])
} for b in bids]), 'UTF-8')
def js_sentbids(self, url_split, post_string):
return bytes(json.dumps(self.server.swap_client.listBids(sent=True)), 'UTF-8')
def js_index(self, url_split, post_string):
return bytes(json.dumps(self.server.swap_client.getSummary()), 'UTF-8')

View file

@ -194,6 +194,12 @@ class Test(unittest.TestCase):
proof = ci.proveDLEAG(key)
assert(ci.verifyDLEAG(proof))
def test_rate(self):
scale_from = 8
scale_to = 12
amount_from = 100 * (10 ** scale_from)
rate = 0.1 * (10 ** scale_to)
if __name__ == '__main__':
unittest.main()

View file

@ -539,7 +539,7 @@ class Test(unittest.TestCase):
assert(make_int(js_0[str(int(Coins.XMR))]['balance'], scale=12) > 0)
assert(make_int(js_0[str(int(Coins.XMR))]['unconfirmed'], scale=12) > 0)
offer_id = swap_clients[0].postOffer(Coins.PART, Coins.XMR, 100 * COIN, 10 * XMR_COIN, 100 * COIN, SwapTypes.XMR_SWAP)
offer_id = swap_clients[0].postOffer(Coins.PART, Coins.XMR, 100 * COIN, 0.11 * XMR_COIN, 100 * COIN, SwapTypes.XMR_SWAP)
self.wait_for_offer(swap_clients[1], offer_id)
offers = swap_clients[1].listOffers(filters={'offer_id': offer_id})
assert(len(offers) == 1)
@ -554,13 +554,6 @@ class Test(unittest.TestCase):
swap_clients[0].acceptXmrBid(bid_id)
#self.wait_for_bid(swap_clients[1], bid_id, BidStates.BID_ACCEPTED, sent=True, wait_for=40)
#self.wait_for_bid(swap_clients[0], bid_id, BidStates.XMR_SWAP_SCRIPT_COIN_LOCKED)
#self.wait_for_bid(swap_clients[1], bid_id, BidStates.XMR_SWAP_SCRIPT_COIN_LOCKED, wait_for=40, sent=True)
#self.wait_for_bid(swap_clients[0], bid_id, BidStates.XMR_SWAP_NOSCRIPT_COIN_LOCKED, wait_for=80)
#self.wait_for_bid(swap_clients[1], bid_id, BidStates.XMR_SWAP_NOSCRIPT_COIN_LOCKED, sent=True)
self.wait_for_bid(swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=180)
self.wait_for_bid(swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True)
@ -570,7 +563,7 @@ class Test(unittest.TestCase):
js_w0_before = json.loads(urlopen('http://localhost:1800/json/wallets').read())
offer_id = swap_clients[0].postOffer(Coins.PART, Coins.XMR, 101 * COIN, 1.1 * XMR_COIN, 101 * COIN, SwapTypes.XMR_SWAP,
offer_id = swap_clients[0].postOffer(Coins.PART, Coins.XMR, 101 * COIN, 0.12 * XMR_COIN, 101 * COIN, SwapTypes.XMR_SWAP,
lock_type=SEQUENCE_LOCK_BLOCKS, lock_value=12)
self.wait_for_offer(swap_clients[1], offer_id)
offer = swap_clients[1].getOffer(offer_id)
@ -599,7 +592,7 @@ class Test(unittest.TestCase):
js_w0_before = json.loads(urlopen('http://localhost:1800/json/wallets').read())
offer_id = swap_clients[0].postOffer(Coins.PART, Coins.XMR, 101 * COIN, 1.1 * XMR_COIN, 101 * COIN, SwapTypes.XMR_SWAP,
offer_id = swap_clients[0].postOffer(Coins.PART, Coins.XMR, 101 * COIN, 0.13 * XMR_COIN, 101 * COIN, SwapTypes.XMR_SWAP,
lock_type=SEQUENCE_LOCK_BLOCKS, lock_value=12)
self.wait_for_offer(swap_clients[1], offer_id)
offer = swap_clients[1].getOffer(offer_id)
@ -626,7 +619,7 @@ class Test(unittest.TestCase):
swap_clients = self.swap_clients
offer_id = swap_clients[0].postOffer(Coins.PART, Coins.XMR, 101 * COIN, 1.1 * XMR_COIN, 101 * COIN, SwapTypes.XMR_SWAP,
offer_id = swap_clients[0].postOffer(Coins.PART, Coins.XMR, 101 * COIN, 0.14 * XMR_COIN, 101 * COIN, SwapTypes.XMR_SWAP,
lock_type=SEQUENCE_LOCK_BLOCKS, lock_value=18)
self.wait_for_offer(swap_clients[1], offer_id)
offer = swap_clients[1].getOffer(offer_id)