From 4c200fe8d4e0f75ed410cd10e40745d3a36611a1 Mon Sep 17 00:00:00 2001 From: tecnovert Date: Sat, 5 Dec 2020 13:22:22 +0200 Subject: [PATCH] XMR withdrawals work. spendBLockTx uses sweep_all. --- .cirrus.yml | 11 ++++-- .travis.yml | 12 +++++-- Dockerfile | 5 ++- basicswap/basicswap.py | 53 ++++++++++++++++++--------- basicswap/http_server.py | 5 ++- basicswap/interface_btc.py | 5 +++ basicswap/interface_part.py | 5 +++ basicswap/interface_xmr.py | 28 +++++++++++++-- basicswap/util.py | 17 +++++++-- bin/basicswap_prepare.py | 1 - bin/basicswap_run.py | 0 doc/install.md | 68 +++++++++++++++++++++++------------ requirements.txt | 7 ++++ tests/basicswap/__init__.py | 3 +- tests/basicswap/test_other.py | 4 +-- tests/basicswap/test_xmr.py | 14 ++++++-- 16 files changed, 177 insertions(+), 61 deletions(-) mode change 100644 => 100755 bin/basicswap_run.py create mode 100644 requirements.txt diff --git a/.cirrus.yml b/.cirrus.yml index f3ea58b..bf08d49 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -14,24 +14,31 @@ test_task: - PART_VERSION: 0.19.1.2 - BTC_VERSION: 0.20.1 - LTC_VERSION: 0.18.1 + - XMR_VERSION: 0.17.1.5 - TEST_RELOAD_PATH: $HOME/test_basicswap1/ - TEST_DIR: $HOME/test_basicswap2/ - BIN_DIRS: $HOME/binaries - PARTICL_BINDIR: ${BIN_DIRS}/particl-${PART_VERSION}/bin - BITCOIN_BINDIR: ${BIN_DIRS}/bitcoin-${BTC_VERSION}/bin - LITECOIN_BINDIR: ${BIN_DIRS}/litecoin-${LTC_VERSION}/bin + - MONERO_BINDIR: ${BIN_DIRS}/monero-${XMR_VERSION}/bin setup_script: + - sudo apt-get install -y wget python3-pip gnupg unzip protobuf-compiler automake libtool pkg-config - if [ ! -d "$BIN_DIRS" ]; then mkdir -p "$BIN_DIRS" ; fi - if [ ! -d "$PARTICL_BINDIR" ]; then cd "$BIN_DIRS" && wget https://github.com/tecnovert/particl-core/releases/download/v${PART_VERSION}/particl-${PART_VERSION}-x86_64-linux-gnu.tar.gz && tar xvf particl-${PART_VERSION}-x86_64-linux-gnu.tar.gz; fi - if [ ! -d "$BITCOIN_BINDIR" ]; then cd "$BIN_DIRS" && wget https://bitcoincore.org/bin/bitcoin-core-${BTC_VERSION}/bitcoin-${BTC_VERSION}-x86_64-linux-gnu.tar.gz && tar xvf bitcoin-${BTC_VERSION}-x86_64-linux-gnu.tar.gz; fi - if [ ! -d "$LITECOIN_BINDIR" ]; then cd "$BIN_DIRS" && wget https://download.litecoin.org/litecoin-${LTC_VERSION}/linux/litecoin-${LTC_VERSION}-x86_64-linux-gnu.tar.gz && tar xvf litecoin-${LTC_VERSION}-x86_64-linux-gnu.tar.gz ; fi + - wget -O coincurve-anonswap.zip https://github.com/tecnovert/coincurve/archive/anonswap.zip + - unzip coincurve-anonswap.zip + - cd coincurve-anonswap + - python3 setup.py install --force script: - cd "${CIRRUS_WORKING_DIR}" - export DATADIRS="${TEST_DIR}" - - mkdir -p ${DATADIRS}/bin/{particl,bitcoin} + - mkdir -p ${DATADIRS}/bin/{particl,bitcoin,monero} - cp "${BIN_DIRS}/bitcoin-${BTC_VERSION}-x86_64-linux-gnu.tar.gz" "${DATADIRS}/bin/bitcoin" - cp "${BIN_DIRS}/particl-${PART_VERSION}-x86_64-linux-gnu.tar.gz" "${DATADIRS}/bin/particl" - - mkdir -p ${TEST_RELOAD_PATH}/bin/{particl,bitcoin} + - mkdir -p ${TEST_RELOAD_PATH}/bin/{particl,bitcoin,monero} - cp "${BIN_DIRS}/particl-${PART_VERSION}-x86_64-linux-gnu.tar.gz" "${TEST_RELOAD_PATH}/bin/particl" - cp "${BIN_DIRS}/bitcoin-${BTC_VERSION}-x86_64-linux-gnu.tar.gz" "${TEST_RELOAD_PATH}/bin/bitcoin" - python setup.py test diff --git a/.travis.yml b/.travis.yml index 04d6070..7c7707f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,28 +10,34 @@ env: - PART_VERSION=0.19.1.2 - BTC_VERSION=0.20.1 - LTC_VERSION=0.18.1 + - XMR_VERSION=0.17.1.5 - TEST_DIR=~/test_basicswap2/ - TEST_RELOAD_PATH=~/test_basicswap1/ - BIN_DIRS=~/binaries - PARTICL_BINDIR=${BIN_DIRS}/particl-${PART_VERSION}/bin/ - BITCOIN_BINDIR=${BIN_DIRS}/bitcoin-${BTC_VERSION}/bin/ - LITECOIN_BINDIR=${BIN_DIRS}/litecoin-${LTC_VERSION}/bin/ + - MONERO_BINDIR=${BIN_DIRS}/monero-${XMR_VERSION}/bin/ cache: directories: - "$BIN_DIRS" before_install: - - sudo apt-get install -y wget gnupg2 + - sudo apt-get install -y wget python3-pip gnupg unzip protobuf-compiler automake libtool pkg-config before_script: - if [ ! -d "$BIN_DIRS" ]; then mkdir -p "$BIN_DIRS" ; fi - if [ ! -d "$PARTICL_BINDIR" ]; then cd "$BIN_DIRS" && wget https://github.com/tecnovert/particl-core/releases/download/v${PART_VERSION}/particl-${PART_VERSION}-x86_64-linux-gnu.tar.gz && tar xvf particl-${PART_VERSION}-x86_64-linux-gnu.tar.gz ; fi - if [ ! -d "$BITCOIN_BINDIR" ]; then cd "$BIN_DIRS" && wget https://bitcoincore.org/bin/bitcoin-core-${BTC_VERSION}/bitcoin-${BTC_VERSION}-x86_64-linux-gnu.tar.gz && tar xvf bitcoin-${BTC_VERSION}-x86_64-linux-gnu.tar.gz ; fi - if [ ! -d "$LITECOIN_BINDIR" ]; then cd "$BIN_DIRS" && wget https://download.litecoin.org/litecoin-${LTC_VERSION}/linux/litecoin-${LTC_VERSION}-x86_64-linux-gnu.tar.gz && tar xvf litecoin-${LTC_VERSION}-x86_64-linux-gnu.tar.gz ; fi + - wget -O coincurve-anonswap.zip https://github.com/tecnovert/coincurve/archive/anonswap.zip + - unzip coincurve-anonswap.zip + - cd coincurve-anonswap + - python3 setup.py install --force script: - cd $TRAVIS_BUILD_DIR - export DATADIRS="${TEST_DIR}" - - mkdir -p ${DATADIRS}/bin/{particl,bitcoin} + - mkdir -p ${DATADIRS}/bin/{particl,bitcoin,monero} - cp "${BIN_DIRS}/bitcoin-${BTC_VERSION}-x86_64-linux-gnu.tar.gz" "${DATADIRS}/bin/bitcoin" - - mkdir -p ${TEST_RELOAD_PATH}/bin/{particl,bitcoin} + - mkdir -p ${TEST_RELOAD_PATH}/bin/{particl,bitcoin,monero} - cp "${BIN_DIRS}/particl-${PART_VERSION}-x86_64-linux-gnu.tar.gz" "${TEST_RELOAD_PATH}/bin/particl" - cp "${BIN_DIRS}/bitcoin-${BTC_VERSION}-x86_64-linux-gnu.tar.gz" "${TEST_RELOAD_PATH}/bin/bitcoin" - python setup.py test diff --git a/Dockerfile b/Dockerfile index e5a8581..acbf94a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,7 +12,10 @@ RUN wget -O coincurve-anonswap.zip https://github.com/tecnovert/coincurve/archiv cd coincurve-anonswap && \ python3 setup.py install --force -# TODO: move coindata dir out of src dir +# Install requirements first so as to skip in subsequent rebuilds +COPY ./requirements.txt requirements.txt +RUN pip3 install -r requirements.txt + COPY . basicswap-master RUN cd basicswap-master; \ protoc -I=basicswap --python_out=basicswap basicswap/messages.proto; \ diff --git a/basicswap/basicswap.py b/basicswap/basicswap.py index a5e6c74..b8e4bdb 100644 --- a/basicswap/basicswap.py +++ b/basicswap/basicswap.py @@ -816,14 +816,12 @@ class BasicSwap(BaseApp): if bid.participate_tx and bid.participate_tx.txid: self.addWatchedOutput(coin_to, bid.bid_id, bid.participate_tx.txid.hex(), bid.participate_tx.vout, BidStates.SWAP_PARTICIPATING) - # TODO: watch for xmr bid outputs - - if self.coin_clients[coin_from]['last_height_checked'] < 1: - if bid.initiate_tx and bid.initiate_tx.chain_height: - self.coin_clients[coin_from]['last_height_checked'] = bid.initiate_tx.chain_height - if self.coin_clients[coin_to]['last_height_checked'] < 1: - if bid.participate_tx and bid.participate_tx.chain_height: - self.coin_clients[coin_to]['last_height_checked'] = bid.participate_tx.chain_height + if self.coin_clients[coin_from]['last_height_checked'] < 1: + if bid.initiate_tx and bid.initiate_tx.chain_height: + self.coin_clients[coin_from]['last_height_checked'] = bid.initiate_tx.chain_height + if self.coin_clients[coin_to]['last_height_checked'] < 1: + if bid.participate_tx and bid.participate_tx.chain_height: + self.coin_clients[coin_to]['last_height_checked'] = bid.participate_tx.chain_height # TODO process addresspool if bid has previously been abandoned @@ -980,7 +978,9 @@ class BasicSwap(BaseApp): # TODO: Dynamic fee selection xmr_offer.a_fee_rate = make_int(0.00032595, self.ci(coin_from).exp()) - xmr_offer.b_fee_rate = make_int(0.0012595, self.ci(coin_to).exp()) + # xmr_offer.b_fee_rate = make_int(0.0012595, self.ci(coin_to).exp()) + xmr_offer.b_fee_rate = make_int(0.00002, self.ci(coin_to).exp()) # abs fee + msg_buf.fee_rate_from = xmr_offer.a_fee_rate msg_buf.fee_rate_to = xmr_offer.b_fee_rate @@ -1198,12 +1198,19 @@ class BasicSwap(BaseApp): return self.ci(coin_type).get_fee_rate() + def estimateWithdrawFee(self, coin_type, fee_rate): + if coin_type == Coins.XMR: + self.log.error('TODO: estimateWithdrawFee XMR') + return None + tx_vsize = self.getContractSpendTxVSize(coin_type) + est_fee = (fee_rate * tx_vsize) / 1000 + return est_fee + 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 '') - params = [addr_to, value, '', '', subfee, True, self.coin_clients[coin_type]['conf_target']] - if coin_type == Coins.PART: - params.insert(5, '') # narration - return self.callcoinrpc(coin_type, 'sendtoaddress', params) + + ci = self.ci(coin_type) + return ci.withdrawCoin(value, addr_to, subfee) def cacheNewAddressForCoin(self, coin_type): self.log.debug('cacheNewAddressForCoin %s', coin_type) @@ -2765,7 +2772,15 @@ class BasicSwap(BaseApp): def addWatchedOutput(self, coin_type, bid_id, txid_hex, vout, tx_type, swap_type=None): self.log.debug('Adding watched output %s bid %s tx %s type %s', coin_type, bid_id.hex(), txid_hex, tx_type) - self.coin_clients[coin_type]['watched_outputs'].append(WatchedOutput(bid_id, txid_hex, vout, tx_type, swap_type)) + + watched = self.coin_clients[coin_type]['watched_outputs'] + + for wo in watched: + if wo.bid_id == bid_id and wo.txid_hex == txid_hex and wo.vout == vout: + self.log.debug('Output already being watched.') + return + + watched.append(WatchedOutput(bid_id, txid_hex, vout, tx_type, swap_type)) def removeWatchedOutput(self, coin_type, bid_id, txid_hex): # Remove all for bid if txid is None @@ -2862,6 +2877,8 @@ class BasicSwap(BaseApp): spending_txid = bytes.fromhex(spend_txid_hex) if spending_txid == xmr_swap.a_lock_spend_tx_id: + self.log.debug('[rm] state %d', state) + self.log.debug('[rm] BidStates.XMR_SWAP_SECRET_SHARED %d', BidStates.XMR_SWAP_SECRET_SHARED) if state == BidStates.XMR_SWAP_SECRET_SHARED: xmr_swap.a_lock_spend_tx = bytes.fromhex(spend_txn['hex']) bid.setState(BidStates.XMR_SWAP_SCRIPT_TX_REDEEMED) # TODO: Wait for confirmation? @@ -4232,24 +4249,28 @@ class BasicSwap(BaseApp): if bid.state != data['bid_state']: bid.setState(data['bid_state']) self.log.debug('Set state to %s', strBidState(bid.state)) + self.log.debug('[rm] Set bid.state %d', bid.state) has_changed = True if has_changed: session = scoped_session(self.session_factory) try: - activate_bid = False if offer.swap_type == SwapTypes.SELLER_FIRST: if bid.state and bid.state > BidStates.BID_RECEIVED and bid.state < BidStates.SWAP_COMPLETED: activate_bid = True else: - raise ValueError('TODO') + self.log.debug('TODO - determine in-progress for manualBidUpdate') + if offer.swap_type == SwapTypes.XMR_SWAP: + if bid.state and bid.state == BidStates.XMR_SWAP_SECRET_SHARED: + activate_bid = True if activate_bid: self.activateBid(session, bid) else: self.deactivateBid(session, offer, bid) + self.log.debug('[rm] bid.state %d', bid.state) self.saveBidInSession(bid_id, bid, session) session.commit() finally: diff --git a/basicswap/http_server.py b/basicswap/http_server.py index 2cf9d61..ddfe416 100644 --- a/basicswap/http_server.py +++ b/basicswap/http_server.py @@ -242,14 +242,13 @@ class HttpHandler(BaseHTTPRequestHandler): ci = swap_client.ci(k) fee_rate = swap_client.getFeeRateForCoin(k) - tx_vsize = swap_client.getContractSpendTxVSize(k) - est_fee = (fee_rate * tx_vsize) / 1000 + est_fee = swap_client.estimateWithdrawFee(k, fee_rate) wallets_formatted.append({ 'name': w['name'], 'version': w['version'], 'cid': str(int(k)), 'fee_rate': ci.format_amount(int(fee_rate * ci.COIN())), - 'est_fee': ci.format_amount(int(est_fee * ci.COIN())), + 'est_fee': 'Unknown' if est_fee is None else ci.format_amount(int(est_fee * ci.COIN())), 'balance': w['balance'], 'blocks': w['blocks'], 'synced': w['synced'], diff --git a/basicswap/interface_btc.py b/basicswap/interface_btc.py index 20301ad..b7554a8 100644 --- a/basicswap/interface_btc.py +++ b/basicswap/interface_btc.py @@ -123,6 +123,7 @@ class BTCInterface(CoinInterface): self.txoType = CTxOut self._network = network self.blocks_confirmed = coin_settings['blocks_confirmed'] + self._conf_target = coin_settings['conf_target'] def testDaemonRPC(self): self.rpc_callback('getwalletinfo', []) @@ -881,6 +882,10 @@ class BTCInterface(CoinInterface): 'vout': utxo['vout']}) return rv + def withdrawCoin(self, value, addr_to, subfee): + params = [addr_to, value, '', '', subfee, True, self._conf_target] + return self.rpc_callback('sendtoaddress', params) + def testBTCInterface(): print('testBTCInterface') diff --git a/basicswap/interface_part.py b/basicswap/interface_part.py index b725e64..b3e7f78 100644 --- a/basicswap/interface_part.py +++ b/basicswap/interface_part.py @@ -32,6 +32,7 @@ class PARTInterface(BTCInterface): self.txoType = CTxOutPart self._network = network self.blocks_confirmed = coin_settings['blocks_confirmed'] + self._conf_target = coin_settings['conf_target'] def knownWalletSeed(self): # TODO: Double check @@ -47,3 +48,7 @@ class PARTInterface(BTCInterface): def initialiseWallet(self, key): raise ValueError('TODO') + + def withdrawCoin(self, value, addr_to, subfee): + params = [addr_to, value, '', '', subfee, '', True, self._conf_target] + return self.rpc_callback('sendtoaddress', params) diff --git a/basicswap/interface_xmr.py b/basicswap/interface_xmr.py index f1e0c74..980bfe9 100644 --- a/basicswap/interface_xmr.py +++ b/basicswap/interface_xmr.py @@ -21,6 +21,7 @@ from coincurve.dleag import ( from .util import ( dumpj, + make_int, format_amount) from .rpc_xmr import ( make_xmr_rpc_func, @@ -55,14 +56,14 @@ class XMRInterface(CoinInterface): def __init__(self, coin_settings, network): super().__init__() - rpc_cb = make_xmr_rpc_func(coin_settings['rpcport'], host=coin_settings['rpchost']) + rpc_cb = make_xmr_rpc_func(coin_settings['rpcport'], host=coin_settings.get('rpchost', 'localhost')) rpc_wallet_cb = make_xmr_wallet_rpc_func(coin_settings['walletrpcport'], coin_settings['walletrpcauth']) self.rpc_cb = rpc_cb self.rpc_wallet_cb = rpc_wallet_cb self._network = network self.blocks_confirmed = coin_settings['blocks_confirmed'] - self._restore_height = coin_settings['restore_height'] + self._restore_height = coin_settings.get('restore_height', 0) def setWalletFilename(self, wallet_filename): self._wallet_filename = wallet_filename @@ -368,14 +369,26 @@ class XMRInterface(CoinInterface): break time.sleep(1 + i) + if rv['balance'] < cb_swap_value: + logging.error('wallet {} balance {}, expected {}'.format(wallet_filename, rv['balance'], cb_swap_value)) + raise ValueError('Invalid balance') + params = {'address': address_to} + rv = self.rpc_wallet_cb('sweep_all', params) + print('sweep_all', rv) + + return bytes.fromhex(rv['tx_hash_list'][0]) + + """ # TODO: need a subfee from output option - b_fee = b_fee_rate * 10 # Guess + # b_fee = b_fee_rate * 10 # Guess + b_fee = b_fee_rate num_tries = 20 for i in range(1 + num_tries): try: params = {'destinations': [{'amount': cb_swap_value - b_fee, 'address': address_to}]} + logging.debug('params', dumpj(params)) rv = self.rpc_wallet_cb('transfer', params) print('transfer', rv) break @@ -387,3 +400,12 @@ class XMRInterface(CoinInterface): logging.info('Raising fee to %d', b_fee) return bytes.fromhex(rv['tx_hash']) + """ + + def withdrawCoin(self, value, addr_to, subfee): + self.rpc_wallet_cb('open_wallet', {'filename': self._wallet_filename}) + + value_sats = make_int(value, self.exp()) + params = {'destinations': [{'amount': value_sats, 'address': addr_to}]} + rv = self.rpc_wallet_cb('transfer', params) + return rv['tx_hash'] diff --git a/basicswap/util.py b/basicswap/util.py index 283e80b..b8316b1 100644 --- a/basicswap/util.py +++ b/basicswap/util.py @@ -14,6 +14,10 @@ OP_16 = 0x60 COIN = 100000000 +decimal_ctx = decimal.Context() +decimal_ctx.prec = 20 + + def assert_cond(v, err='Bad opcode'): if not v: raise ValueError(err) @@ -224,9 +228,15 @@ def getCompactSizeLen(v): raise ValueError('Value too large') +def float_to_str(f): + # stackoverflow.com/questions/38847690 + d1 = decimal_ctx.create_decimal(repr(f)) + return format(d1, 'f') + + def make_int(v, scale=8, r=0): # r = 0, no rounding, fail, r > 0 round up, r < 0 floor if type(v) == float: - v = str(v) + v = float_to_str(v) elif type(v) == int: return v * 10 ** scale @@ -239,7 +249,8 @@ def make_int(v, scale=8, r=0): # r = 0, no rounding, fail, r > 0 round up, r < have_dp = True continue if not c.isdigit(): - raise ValueError('Invalid char') + + raise ValueError('Invalid char: ' + c) if have_dp: ep //= 10 if ep <= 0: @@ -260,7 +271,7 @@ def make_int(v, scale=8, r=0): # r = 0, no rounding, fail, r > 0 round up, r < def validate_amount(amount, scale=8): - str_amount = str(amount) + str_amount = float_to_str(amount) if type(amount) == float else str(amount) has_decimal = False for c in str_amount: if c == '.' and not has_decimal: diff --git a/bin/basicswap_prepare.py b/bin/basicswap_prepare.py index fa37626..eebd41a 100755 --- a/bin/basicswap_prepare.py +++ b/bin/basicswap_prepare.py @@ -358,7 +358,6 @@ def printHelp(): logger.info('--htmlhost= Interface to host on, default:localhost.') logger.info('--xmrrestoreheight=n Block height to restore Monero wallet from, default:{}.'.format(DEFAULT_XMR_RESTORE_HEIGHT)) - logger.info('\n' + 'Known coins: %s', ', '.join(known_coins.keys())) diff --git a/bin/basicswap_run.py b/bin/basicswap_run.py old mode 100644 new mode 100755 diff --git a/doc/install.md b/doc/install.md index 834f8e0..c5502cd 100644 --- a/doc/install.md +++ b/doc/install.md @@ -1,7 +1,6 @@ -## Prerequisites +## Source code - $ sudo apt-get install git python3-pip protobuf-compiler $ git clone https://github.com/tecnovert/basicswap.git @@ -10,46 +9,71 @@ Docker must be installed and started: $ sudo systemctl status docker | grep Active -Should return a line containing: -`active (running)` +Should return a line containing `active (running)` + + +Create the images: $ cd basicswap/docker $ docker-compose build - $ docker-compose up -You may need to run docker-compose with sudo, unless you've setup docker -to be able to run from user accounts. +Prepare the datadir: +Set XMR_RPC_HOST and BASE_XMR_RPC_PORT to a public XMR node or exclude to run a local node. + + $ export SWAP_DATADIR=/var/data/coinswaps + $ docker run -e XMR_RPC_HOST="node.xmr.to" -e BASE_XMR_RPC_PORT=18081 -t --name swap_prepare -v $SWAP_DATADIR:/coindata i_swapclient \ + basicswap-prepare --datadir=/coindata --withcoins=monero --withoutcoins=litecoin --htmlhost="0.0.0.0" --xmrrestoreheight=2245107 +Record the mnemonic from the output of the above command. -By default the data dir will be basicswap/docker/coindata +Remove swap_prepare container (and logs): -To run with a different data directory run: + $ docker rm swap_prepare + + +Start the container + + $ export SWAP_DATADIR=/var/data/coinswaps + $ docker-compose up - $ export COINDATA_PATH=/tmp/part_swap_test/coindata +Open in browser: `http://localhost:12700` -And copy the initial config there: - $ cp -r docker/coindata /tmp/part_swap_test/coindata +## Run Without Docker: -Before running docker-compose build + $ apt-get install -y wget python3-pip gnupg unzip protobuf-compiler automake libtool pkg-config + $ export SWAP_DATADIR=/var/data/coinswaps + $ mkdirs -p "$SWAP_DATADIR/venv" + $ python3 -m venv "$SWAP_DATADIR/venv" + $ . $SWAP_DATADIR/venv/bin/activate && python -V + $ wget -O coincurve-anonswap.zip https://github.com/tecnovert/coincurve/archive/anonswap.zip + $ unzip coincurve-anonswap.zip + $ cd coincurve-anonswap + $ python3 setup.py install --force -## Install as Python Module with PIP + $ cd $SWAP_DATADIR + $ git clone https://github.com/tecnovert/basicswap.git $ cd basicswap $ protoc -I=basicswap --python_out=basicswap basicswap/messages.proto $ pip3 install . - $ basicswap-prepare - $ basicswap-run +Prepare the datadir: + + XMR_RPC_HOST="node.xmr.to" BASE_XMR_RPC_PORT=18081 basicswap-prepare --datadir=$SWAP_DATADIR --withcoins=monero --withoutcoins=litecoin --xmrrestoreheight=2245107 + +Record the mnemonic from the output of the above command. + +Start the app + + $ basicswap-run --datadir=$SWAP_DATADIR + +Open in browser: `http://localhost:12700` -By default the data dir will be `~/.basicswap` -To run in a different directory and on testnet: -``` - $ basicswap-prepare -datadir=~/part_swap_test -testnet - $ basicswap-run -datadir=~/part_swap_test -testnet -``` +Old notes +============= ## Run Without Installing diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..5834b9a --- /dev/null +++ b/requirements.txt @@ -0,0 +1,7 @@ +wheel +pyzmq +protobuf +sqlalchemy +python-gnupg +Jinja2 +requests diff --git a/tests/basicswap/__init__.py b/tests/basicswap/__init__.py index 30104e0..128b685 100644 --- a/tests/basicswap/__init__.py +++ b/tests/basicswap/__init__.py @@ -4,7 +4,6 @@ import tests.basicswap.test_other as test_other import tests.basicswap.test_prepare as test_prepare import tests.basicswap.test_run as test_run import tests.basicswap.test_reload as test_reload -import tests.basicswap.test_xmr as test_xmr def test_suite(): @@ -13,6 +12,6 @@ def test_suite(): suite.addTests(loader.loadTestsFromModule(test_prepare)) suite.addTests(loader.loadTestsFromModule(test_run)) suite.addTests(loader.loadTestsFromModule(test_reload)) - suite.addTests(loader.loadTestsFromModule(test_xmr)) + # TODO: Add to ci scripts suite.addTests(loader.loadTestsFromModule(test_xmr)) return suite diff --git a/tests/basicswap/test_other.py b/tests/basicswap/test_other.py index 84b4a12..b179723 100644 --- a/tests/basicswap/test_other.py +++ b/tests/basicswap/test_other.py @@ -161,7 +161,7 @@ class Test(unittest.TestCase): assert(pubkey == pubkey_test) def test_ecdsa_otves(self): - coin_settings = {'rpcport': 0, 'rpcauth': 'none', 'blocks_confirmed': 1} + coin_settings = {'rpcport': 0, 'rpcauth': 'none', 'blocks_confirmed': 1, 'conf_target': 1} ci = BTCInterface(coin_settings, 'regtest') vk_sign = i2b(ci.getNewSecretKey()) vk_encrypt = i2b(ci.getNewSecretKey()) @@ -183,7 +183,7 @@ class Test(unittest.TestCase): assert(vk_encrypt == recovered_key) def test_dleag(self): - coin_settings = {'rpcport': 0, 'walletrpcport': 0, 'walletrpcauth': 'none', 'blocks_confirmed': 1} + coin_settings = {'rpcport': 0, 'walletrpcport': 0, 'walletrpcauth': 'none', 'blocks_confirmed': 1, 'conf_target': 1} ci = XMRInterface(coin_settings, 'regtest') key = i2b(ci.getNewSecretKey()) diff --git a/tests/basicswap/test_xmr.py b/tests/basicswap/test_xmr.py index bd55b88..824b71c 100644 --- a/tests/basicswap/test_xmr.py +++ b/tests/basicswap/test_xmr.py @@ -547,9 +547,9 @@ class Test(unittest.TestCase): logging.info('---------- Test PART to XMR') swap_clients = self.swap_clients - js_0 = json.loads(urlopen('http://localhost:1801/json/wallets').read()) - 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) + js_1 = json.loads(urlopen('http://localhost:1801/json/wallets').read()) + assert(make_int(js_1[str(int(Coins.XMR))]['balance'], scale=12) > 0) + assert(make_int(js_1[str(int(Coins.XMR))]['unconfirmed'], scale=12) > 0) 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) @@ -725,6 +725,14 @@ class Test(unittest.TestCase): self.wait_for_no_offer(swap_clients[1], offer_id) + def test_08_withdraw(self): + logging.info('---------- Test xmr withdrawals') + swap_clients = self.swap_clients + js_0 = json.loads(urlopen('http://localhost:1800/json/wallets').read()) + address_to = js_0[str(int(Coins.XMR))]['deposit_address'] + + swap_clients[1].withdrawCoin(Coins.XMR, 1.1, address_to, False) + if __name__ == '__main__': unittest.main()