from io import BytesIO from base64 import b64encode from qrcode import make as qrcode_make from datetime import datetime from flask import session, redirect, url_for, request, Blueprint, flash, render_template from monero.address import address from app.models import Swap from app.factory import db from app.routes.api import perform_conversion from app.library.crypto import wow_wallet, xmr_wallet from app.library.crypto import wownero, monero from app.library.cache import cache from app.library.mattermost import post_webhook from app import config bp = Blueprint('swap', 'swap') @bp.route('/swap') def create_swap(): send_amount = request.args.get('send_amount') wow_to_xmr = request.args.get('wow_to_xmr', 'true') wow_address = request.args.get('wow_address') xmr_address = request.args.get('xmr_address') # Check send_amount try: send_amount = float(send_amount) except: flash('Invalid send amount provided') return redirect('/#swap') # Check send_amount greater than 0 if not send_amount > 0: flash('Invalid send amount provided') return redirect('/#swap') # todo - simplify if possible, normalize var conventions if wow_to_xmr == 'true': wow_amount = send_amount xmr_amount = 0 worth = 'wow_worth' wow_to_xmr = True gen_subaddress = wow_wallet.new_address receive_wallet = wownero send_wallet = monero fee_as_other = 'wow_to_xmr_fee_as_xmr' amount_as_other = 'wow_as_xmr' coin = 'WOW' elif wow_to_xmr == 'false': wow_amount = 0 xmr_amount = send_amount worth = 'xmr_worth' wow_to_xmr = False gen_subaddress = xmr_wallet.new_address receive_wallet = monero send_wallet = wownero fee_as_other = 'xmr_to_wow_fee_as_wow' amount_as_other = 'xmr_as_wow' coin = 'XMR' else: flash('There was a problem processing') return redirect('/#swap') # Check addresses if not Swap().validate_wow_address(wow_address): flash('Invalid WOW address provided.') return redirect('/#swap') if not Swap().validate_xmr_address(xmr_address): flash('Invalid XMR address provided.') return redirect('/#swap') # Get price and conversion data conversion = perform_conversion(wow_amount, xmr_amount) # Check swap worth sw = Swap().validate_swap_worth(conversion[worth]) if not sw[0]: flash(f'Invalid swap worth: {sw[1]}') return redirect('/#swap') # Create new subaddress swap_address = gen_subaddress() # Validate subaddress does not exist already checks = 0 address_exists = Swap.query.filter( Swap.wow_to_xmr==wow_to_xmr, Swap.swap_address_index==swap_address[0] ).first() while address_exists: print(f'Found existing address index {swap_address[0]} for {coin}. Generating another.') if checks >= 10: flash('Something went wrong. Contact the administrator for help.') return redirect('/#swap') swap_address = gen_subaddress() address_exists = Swap.query.filter( Swap.wow_to_xmr==wow_to_xmr, Swap.swap_address_index==swap_address[0] ).first() checks += 1 # Create swap in database send_full_atomic = send_wallet.to_atomic(conversion[amount_as_other]) send_fee_atomic = send_wallet.to_atomic(conversion[fee_as_other]) s = Swap( date=datetime.utcnow(), wow_to_xmr=wow_to_xmr, wow_price_ausd=Swap().to_ausd(conversion['wow_price']), xmr_price_ausd=Swap().to_ausd(conversion['xmr_price']), swap_address=swap_address[1], swap_address_index=swap_address[0], return_wow_address=wow_address, return_xmr_address=xmr_address, receive_amount_atomic=receive_wallet.to_atomic(send_amount), fee_amount_atomic=send_wallet.to_atomic(conversion[fee_as_other]), send_amount_atomic=send_full_atomic - send_fee_atomic ) db.session.add(s) db.session.commit() url = url_for('swap.get_swap', swap_id=s.id, _external=True) details = s.show_details() post_webhook(f'New swap [{s.id}]({url}); swap wallets to receive {details["receive"]} and send {details["send"]} ({details["fee"]} fee)') return redirect(url) # todo - simplify, use model logic @bp.route('/swap/') def get_swap(swap_id): s = Swap.query.get(swap_id) _address_qr = BytesIO() if s: if s.hours_elapsed(since_completed=True) > 12: flash('That swap is completed and no longer available to view') return redirect('/') if s.wow_to_xmr: coin = 'wow' full = 'wownero' qr_uri = s.swap_address else: coin = 'xmr' full = 'monero' qr_uri = f'{full}:{s.swap_address}&tx_description=neroswap_{s.id}' address_qr = qrcode_make(qr_uri).save(_address_qr) qrcode = b64encode(_address_qr.getvalue()).decode() txes = cache.get_transfer_data(coin, s.swap_address_index) return render_template('swap.html', swap=s, txes=txes, qrcode=qrcode) else: flash('That swap ID does not exist.') return redirect('/#search') @bp.route('/search') def search_swap(): swap_id = request.args.get('swap_id') if not swap_id: flash('No swap ID provided') return redirect('/#search') return redirect(url_for('swap.get_swap', swap_id=swap_id))