ui: Split wallet cached data into balance and blockchain state.
Add XMR synced indicator.
This commit is contained in:
		
							parent
							
								
									0580f9ebac
								
							
						
					
					
						commit
						91e285bf4a
					
				@ -5258,60 +5258,82 @@ class BasicSwap(BaseApp):
 | 
			
		||||
        }
 | 
			
		||||
        return rv
 | 
			
		||||
 | 
			
		||||
    def getWalletInfo(self, coin):
 | 
			
		||||
 | 
			
		||||
    def getBlockchainInfo(self, coin):
 | 
			
		||||
        ci = self.ci(coin)
 | 
			
		||||
        blockchaininfo = ci.getBlockchainInfo()
 | 
			
		||||
        walletinfo = ci.getWalletInfo()
 | 
			
		||||
 | 
			
		||||
        scale = chainparams[coin]['decimal_places']
 | 
			
		||||
        rv = {
 | 
			
		||||
            'version': self.coin_clients[coin]['core_version'],
 | 
			
		||||
            'deposit_address': self.getCachedAddressForCoin(coin),
 | 
			
		||||
            'name': ci.coin_name(),
 | 
			
		||||
            'blocks': blockchaininfo['blocks'],
 | 
			
		||||
            'balance': format_amount(make_int(walletinfo['balance'], scale), scale),
 | 
			
		||||
            'unconfirmed': format_amount(make_int(walletinfo.get('unconfirmed_balance'), scale), scale),
 | 
			
		||||
            'synced': '{0:.2f}'.format(round(blockchaininfo['verificationprogress'], 2)),
 | 
			
		||||
            'expected_seed': ci.knownWalletSeed(),
 | 
			
		||||
        }
 | 
			
		||||
        try:
 | 
			
		||||
            blockchaininfo = ci.getBlockchainInfo()
 | 
			
		||||
 | 
			
		||||
        if coin == Coins.PART:
 | 
			
		||||
            rv['stealth_address'] = self.getCachedStealthAddressForCoin(Coins.PART)
 | 
			
		||||
            rv['anon_balance'] = walletinfo['anon_balance']
 | 
			
		||||
            rv['anon_pending'] = walletinfo['unconfirmed_anon'] + walletinfo['immature_anon_balance']
 | 
			
		||||
            rv['blind_balance'] = walletinfo['blind_balance']
 | 
			
		||||
            rv['blind_unconfirmed'] = walletinfo['unconfirmed_blind']
 | 
			
		||||
        elif coin == Coins.XMR:
 | 
			
		||||
            rv['main_address'] = self.getCachedMainWalletAddress(ci)
 | 
			
		||||
            rv = {
 | 
			
		||||
                'version': self.coin_clients[coin]['core_version'],
 | 
			
		||||
                'name': ci.coin_name(),
 | 
			
		||||
                'blocks': blockchaininfo['blocks'],
 | 
			
		||||
                'synced': '{0:.2f}'.format(round(blockchaininfo['verificationprogress'], 2)),
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        return rv
 | 
			
		||||
            return rv
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            self.log.warning('getWalletInfo failed with: %s', str(e))
 | 
			
		||||
 | 
			
		||||
    def updateWalletInfo(self, coin):
 | 
			
		||||
        wi = self.getWalletInfo(coin)
 | 
			
		||||
    def getWalletInfo(self, coin):
 | 
			
		||||
        ci = self.ci(coin)
 | 
			
		||||
 | 
			
		||||
        # Store wallet info to db so it's available after startup
 | 
			
		||||
        try:
 | 
			
		||||
            walletinfo = ci.getWalletInfo()
 | 
			
		||||
            scale = chainparams[coin]['decimal_places']
 | 
			
		||||
            rv = {
 | 
			
		||||
                'deposit_address': self.getCachedAddressForCoin(coin),
 | 
			
		||||
                'balance': format_amount(make_int(walletinfo['balance'], scale), scale),
 | 
			
		||||
                'unconfirmed': format_amount(make_int(walletinfo.get('unconfirmed_balance'), scale), scale),
 | 
			
		||||
                'expected_seed': ci.knownWalletSeed(),
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if coin == Coins.PART:
 | 
			
		||||
                rv['stealth_address'] = self.getCachedStealthAddressForCoin(Coins.PART)
 | 
			
		||||
                rv['anon_balance'] = walletinfo['anon_balance']
 | 
			
		||||
                rv['anon_pending'] = walletinfo['unconfirmed_anon'] + walletinfo['immature_anon_balance']
 | 
			
		||||
                rv['blind_balance'] = walletinfo['blind_balance']
 | 
			
		||||
                rv['blind_unconfirmed'] = walletinfo['unconfirmed_blind']
 | 
			
		||||
            elif coin == Coins.XMR:
 | 
			
		||||
                rv['main_address'] = self.getCachedMainWalletAddress(ci)
 | 
			
		||||
 | 
			
		||||
            return rv
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            self.log.warning('getWalletInfo failed with: %s', str(e))
 | 
			
		||||
 | 
			
		||||
    def addWalletInfoRecord(self, coin, info_type, wi):
 | 
			
		||||
        coin_id = int(coin)
 | 
			
		||||
        self.mxDB.acquire()
 | 
			
		||||
        try:
 | 
			
		||||
            rv = []
 | 
			
		||||
            now = int(time.time())
 | 
			
		||||
            session = scoped_session(self.session_factory)
 | 
			
		||||
 | 
			
		||||
            session.add(Wallets(coin_id=coin, wallet_data=json.dumps(wi), created_at=now))
 | 
			
		||||
 | 
			
		||||
            coin_id = int(coin)
 | 
			
		||||
            query_str = f'DELETE FROM wallets WHERE coin_id = {coin_id} AND record_id NOT IN (SELECT record_id FROM wallets WHERE coin_id = {coin_id} ORDER BY created_at DESC LIMIT 3 )'
 | 
			
		||||
            session.add(Wallets(coin_id=coin, balance_type=info_type, wallet_data=json.dumps(wi), created_at=now))
 | 
			
		||||
            query_str = f'DELETE FROM wallets WHERE (coin_id = {coin_id} AND balance_type = {info_type}) AND record_id NOT IN (SELECT record_id FROM wallets WHERE coin_id = {coin_id} AND balance_type = {info_type} ORDER BY created_at DESC LIMIT 3 )'
 | 
			
		||||
            session.execute(query_str)
 | 
			
		||||
            session.commit()
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            self.log.error(f'updateWalletInfo {e}')
 | 
			
		||||
 | 
			
		||||
            self.log.error(f'addWalletInfoRecord {e}')
 | 
			
		||||
        finally:
 | 
			
		||||
            session.close()
 | 
			
		||||
            session.remove()
 | 
			
		||||
            self._updating_wallets_info[int(coin)] = False
 | 
			
		||||
            self.mxDB.release()
 | 
			
		||||
 | 
			
		||||
    def updateWalletInfo(self, coin):
 | 
			
		||||
        # Store wallet info to db so it's available after startup
 | 
			
		||||
        try:
 | 
			
		||||
            bi = self.getBlockchainInfo(coin)
 | 
			
		||||
            if bi:
 | 
			
		||||
                self.addWalletInfoRecord(coin, 0, bi)
 | 
			
		||||
 | 
			
		||||
            # monero-wallet-rpc is slow/unresponsive while syncing
 | 
			
		||||
            wi = self.getWalletInfo(coin)
 | 
			
		||||
            if wi:
 | 
			
		||||
                self.addWalletInfoRecord(coin, 1, wi)
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            self.log.error(f'updateWalletInfo {e}')
 | 
			
		||||
        finally:
 | 
			
		||||
            self._updating_wallets_info[int(coin)] = False
 | 
			
		||||
 | 
			
		||||
    def updateWalletsInfo(self, force_update=False, only_coin=None):
 | 
			
		||||
        now = int(time.time())
 | 
			
		||||
        if not force_update and now - self._last_updated_wallets_info < 30:
 | 
			
		||||
@ -5335,6 +5357,7 @@ class BasicSwap(BaseApp):
 | 
			
		||||
            if self.coin_clients[c]['connection_type'] == 'rpc':
 | 
			
		||||
                try:
 | 
			
		||||
                    rv[c] = self.getWalletInfo(c)
 | 
			
		||||
                    rv[c].update(self.getBlockchainInfo(c))
 | 
			
		||||
                except Exception as ex:
 | 
			
		||||
                    rv[c] = {'name': chainparams[c]['name'].capitalize(), 'error': str(ex)}
 | 
			
		||||
        return rv
 | 
			
		||||
@ -5347,8 +5370,8 @@ class BasicSwap(BaseApp):
 | 
			
		||||
            where_str = ''
 | 
			
		||||
            if opts is not None and 'coin_id' in opts:
 | 
			
		||||
                where_str = 'WHERE coin_id = {}'.format(opts['coin_id'])
 | 
			
		||||
            inner_str = f'SELECT coin_id, MAX(created_at) as max_created_at FROM wallets {where_str} GROUP BY coin_id'
 | 
			
		||||
            query_str = 'SELECT a.coin_id, wallet_data, created_at FROM wallets a, ({}) b WHERE a.coin_id = b.coin_id AND a.created_at = b.max_created_at'.format(inner_str)
 | 
			
		||||
            inner_str = f'SELECT coin_id, balance_type, MAX(created_at) as max_created_at FROM wallets {where_str} GROUP BY coin_id, balance_type'
 | 
			
		||||
            query_str = 'SELECT a.coin_id, a.balance_type, wallet_data, created_at FROM wallets a, ({}) b WHERE a.coin_id = b.coin_id AND a.balance_type = b.balance_type AND a.created_at = b.max_created_at'.format(inner_str)
 | 
			
		||||
 | 
			
		||||
            q = session.execute(query_str)
 | 
			
		||||
            for row in q:
 | 
			
		||||
@ -5358,16 +5381,20 @@ class BasicSwap(BaseApp):
 | 
			
		||||
                    # Skip cached info if coin was disabled
 | 
			
		||||
                    continue
 | 
			
		||||
 | 
			
		||||
                wallet_data = json.loads(row[1])
 | 
			
		||||
                wallet_data['lastupdated'] = row[2]
 | 
			
		||||
                wallet_data['updating'] = self._updating_wallets_info.get(coin_id, False)
 | 
			
		||||
                wallet_data = json.loads(row[2])
 | 
			
		||||
                if row[1] == 1:
 | 
			
		||||
                    wallet_data['lastupdated'] = row[3]
 | 
			
		||||
                    wallet_data['updating'] = self._updating_wallets_info.get(coin_id, False)
 | 
			
		||||
 | 
			
		||||
                # Ensure the latest deposit address is displayed
 | 
			
		||||
                q = session.execute('SELECT value FROM kv_string WHERE key = "receive_addr_{}"'.format(chainparams[coin_id]['name']))
 | 
			
		||||
                for row in q:
 | 
			
		||||
                    wallet_data['deposit_address'] = row[0]
 | 
			
		||||
                    # Ensure the latest deposit address is displayed
 | 
			
		||||
                    q = session.execute('SELECT value FROM kv_string WHERE key = "receive_addr_{}"'.format(chainparams[coin_id]['name']))
 | 
			
		||||
                    for row in q:
 | 
			
		||||
                        wallet_data['deposit_address'] = row[0]
 | 
			
		||||
 | 
			
		||||
                rv[coin_id] = wallet_data
 | 
			
		||||
                if coin_id in rv:
 | 
			
		||||
                    rv[coin_id].update(wallet_data)
 | 
			
		||||
                else:
 | 
			
		||||
                    rv[coin_id] = wallet_data
 | 
			
		||||
        finally:
 | 
			
		||||
            session.close()
 | 
			
		||||
            session.remove()
 | 
			
		||||
@ -5383,6 +5410,7 @@ class BasicSwap(BaseApp):
 | 
			
		||||
                if coin_id not in rv:
 | 
			
		||||
                    rv[coin_id] = {
 | 
			
		||||
                        'name': chainparams[c]['name'].capitalize(),
 | 
			
		||||
                        'no_data': True,
 | 
			
		||||
                        'updating': self._updating_wallets_info.get(coin_id, False),
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
@ -5602,7 +5630,6 @@ class BasicSwap(BaseApp):
 | 
			
		||||
    def getAutomationStrategy(self, strategy_id):
 | 
			
		||||
        self.mxDB.acquire()
 | 
			
		||||
        try:
 | 
			
		||||
            rv = []
 | 
			
		||||
            session = scoped_session(self.session_factory)
 | 
			
		||||
            return session.query(AutomationStrategy).filter_by(record_id=strategy_id).first()
 | 
			
		||||
        finally:
 | 
			
		||||
@ -5613,7 +5640,6 @@ class BasicSwap(BaseApp):
 | 
			
		||||
    def getLinkedStrategy(self, linked_type, linked_id):
 | 
			
		||||
        self.mxDB.acquire()
 | 
			
		||||
        try:
 | 
			
		||||
            rv = []
 | 
			
		||||
            session = scoped_session(self.session_factory)
 | 
			
		||||
            query_str = 'SELECT links.strategy_id, strats.label FROM automationlinks links' + \
 | 
			
		||||
                        ' LEFT JOIN automationstrategies strats ON strats.record_id = links.strategy_id' + \
 | 
			
		||||
 | 
			
		||||
@ -391,8 +391,6 @@ class Wallets(Base):
 | 
			
		||||
    wallet_name = sa.Column(sa.String)
 | 
			
		||||
    wallet_data = sa.Column(sa.String)
 | 
			
		||||
    balance_type = sa.Column(sa.Integer)
 | 
			
		||||
    amount = sa.Column(sa.BigInteger)
 | 
			
		||||
    updated_at = sa.Column(sa.BigInteger)
 | 
			
		||||
    created_at = sa.Column(sa.BigInteger)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -102,9 +102,8 @@ def upgradeDatabase(self, db_version):
 | 
			
		||||
                    record_id INTEGER NOT NULL,
 | 
			
		||||
                    coin_id INTEGER,
 | 
			
		||||
                    wallet_name VARCHAR,
 | 
			
		||||
                    wallet_data VARCHAR,
 | 
			
		||||
                    balance_type INTEGER,
 | 
			
		||||
                    amount BIGINT,
 | 
			
		||||
                    updated_at BIGINT,
 | 
			
		||||
                    created_at BIGINT,
 | 
			
		||||
                    PRIMARY KEY (record_id))''')
 | 
			
		||||
            db_version += 1
 | 
			
		||||
@ -216,6 +215,7 @@ def upgradeDatabase(self, db_version):
 | 
			
		||||
            db_version += 1
 | 
			
		||||
            session.execute('ALTER TABLE xmr_swaps ADD COLUMN coin_a_lock_release_msg_id BLOB')
 | 
			
		||||
            session.execute('ALTER TABLE xmr_swaps RENAME COLUMN coin_a_lock_refund_spend_tx_msg_id TO coin_a_lock_spend_tx_msg_id')
 | 
			
		||||
 | 
			
		||||
        if current_version != db_version:
 | 
			
		||||
            self.db_version = db_version
 | 
			
		||||
            self.setIntKVInSession('db_version', db_version, session)
 | 
			
		||||
 | 
			
		||||
@ -23,7 +23,6 @@ from .util import (
 | 
			
		||||
from .chainparams import (
 | 
			
		||||
    Coins,
 | 
			
		||||
    chainparams,
 | 
			
		||||
    getCoinIdFromTicker,
 | 
			
		||||
)
 | 
			
		||||
from .basicswap_util import (
 | 
			
		||||
    BidStates,
 | 
			
		||||
@ -61,6 +60,7 @@ from .ui.util import (
 | 
			
		||||
)
 | 
			
		||||
from .ui.page_tor import page_tor
 | 
			
		||||
from .ui.page_offers import page_offers, page_offer, page_newoffer
 | 
			
		||||
from .ui.page_wallet import page_wallets, page_wallet
 | 
			
		||||
from .ui.page_automation import (
 | 
			
		||||
    page_automation_strategies,
 | 
			
		||||
    page_automation_strategy,
 | 
			
		||||
@ -257,304 +257,6 @@ class HttpHandler(BaseHTTPRequestHandler):
 | 
			
		||||
            active_swaps=[(s[0].hex(), s[1], strBidState(s[2]), strTxState(s[3]), strTxState(s[4])) for s in active_swaps],
 | 
			
		||||
        ), 'UTF-8')
 | 
			
		||||
 | 
			
		||||
    def page_wallets(self, url_split, post_string):
 | 
			
		||||
        swap_client = self.server.swap_client
 | 
			
		||||
 | 
			
		||||
        page_data = {}
 | 
			
		||||
        messages = []
 | 
			
		||||
        form_data = self.checkForm(post_string, 'wallets', messages)
 | 
			
		||||
        if form_data:
 | 
			
		||||
            for c in Coins:
 | 
			
		||||
                if c not in chainparams:
 | 
			
		||||
                    continue
 | 
			
		||||
                cid = str(int(c))
 | 
			
		||||
 | 
			
		||||
                if bytes('newaddr_' + cid, 'utf-8') in form_data:
 | 
			
		||||
                    swap_client.cacheNewAddressForCoin(c)
 | 
			
		||||
                elif bytes('reseed_' + cid, 'utf-8') in form_data:
 | 
			
		||||
                    try:
 | 
			
		||||
                        swap_client.reseedWallet(c)
 | 
			
		||||
                        messages.append('Reseed complete ' + str(c))
 | 
			
		||||
                    except Exception as ex:
 | 
			
		||||
                        messages.append('Reseed failed ' + str(ex))
 | 
			
		||||
                    swap_client.updateWalletsInfo(True, c)
 | 
			
		||||
                elif bytes('withdraw_' + cid, 'utf-8') in form_data:
 | 
			
		||||
                    try:
 | 
			
		||||
                        value = form_data[bytes('amt_' + cid, 'utf-8')][0].decode('utf-8')
 | 
			
		||||
                        page_data['wd_value_' + cid] = value
 | 
			
		||||
                    except Exception as e:
 | 
			
		||||
                        messages.append('Error: Missing value')
 | 
			
		||||
                    try:
 | 
			
		||||
                        address = form_data[bytes('to_' + cid, 'utf-8')][0].decode('utf-8')
 | 
			
		||||
                        page_data['wd_address_' + cid] = address
 | 
			
		||||
                    except Exception as e:
 | 
			
		||||
                        messages.append('Error: Missing address')
 | 
			
		||||
 | 
			
		||||
                    subfee = True if bytes('subfee_' + cid, 'utf-8') in form_data else False
 | 
			
		||||
                    page_data['wd_subfee_' + cid] = subfee
 | 
			
		||||
 | 
			
		||||
                    if c == Coins.PART:
 | 
			
		||||
                        try:
 | 
			
		||||
                            type_from = form_data[bytes('withdraw_type_from_' + cid, 'utf-8')][0].decode('utf-8')
 | 
			
		||||
                            type_to = form_data[bytes('withdraw_type_to_' + cid, 'utf-8')][0].decode('utf-8')
 | 
			
		||||
                            page_data['wd_type_from_' + cid] = type_from
 | 
			
		||||
                            page_data['wd_type_to_' + cid] = type_to
 | 
			
		||||
                        except Exception as e:
 | 
			
		||||
                            messages.append('Error: Missing type')
 | 
			
		||||
 | 
			
		||||
                    if len(messages) == 0:
 | 
			
		||||
                        ci = swap_client.ci(c)
 | 
			
		||||
                        ticker = ci.ticker()
 | 
			
		||||
                        if c == Coins.PART:
 | 
			
		||||
                            try:
 | 
			
		||||
                                txid = swap_client.withdrawParticl(type_from, type_to, value, address, subfee)
 | 
			
		||||
                                messages.append('Withdrew {} {} ({} to {}) to address {}<br/>In txid: {}'.format(value, ticker, type_from, type_to, address, txid))
 | 
			
		||||
                            except Exception as e:
 | 
			
		||||
                                messages.append('Error: {}'.format(str(e)))
 | 
			
		||||
                        else:
 | 
			
		||||
                            try:
 | 
			
		||||
                                txid = swap_client.withdrawCoin(c, value, address, subfee)
 | 
			
		||||
                                messages.append('Withdrew {} {} to address {}<br/>In txid: {}'.format(value, ticker, address, txid))
 | 
			
		||||
                            except Exception as e:
 | 
			
		||||
                                messages.append('Error: {}'.format(str(e)))
 | 
			
		||||
                        swap_client.updateWalletsInfo(True, c)
 | 
			
		||||
 | 
			
		||||
        swap_client.updateWalletsInfo()
 | 
			
		||||
        wallets = swap_client.getCachedWalletsInfo()
 | 
			
		||||
 | 
			
		||||
        wallets_formatted = []
 | 
			
		||||
        sk = sorted(wallets.keys())
 | 
			
		||||
 | 
			
		||||
        for k in sk:
 | 
			
		||||
            w = wallets[k]
 | 
			
		||||
            if 'error' in w:
 | 
			
		||||
                wallets_formatted.append({
 | 
			
		||||
                    'cid': str(int(k)),
 | 
			
		||||
                    'error': w['error']
 | 
			
		||||
                })
 | 
			
		||||
                continue
 | 
			
		||||
 | 
			
		||||
            if 'balance' not in w:
 | 
			
		||||
                wallets_formatted.append({
 | 
			
		||||
                    'name': w['name'],
 | 
			
		||||
                    'havedata': False,
 | 
			
		||||
                    'updating': w['updating'],
 | 
			
		||||
                })
 | 
			
		||||
                continue
 | 
			
		||||
 | 
			
		||||
            ci = swap_client.ci(k)
 | 
			
		||||
            cid = str(int(k))
 | 
			
		||||
            wf = {
 | 
			
		||||
                'name': w['name'],
 | 
			
		||||
                'version': w['version'],
 | 
			
		||||
                'ticker': ci.ticker_mainnet(),
 | 
			
		||||
                'cid': cid,
 | 
			
		||||
                'balance': w['balance'],
 | 
			
		||||
                'blocks': w['blocks'],
 | 
			
		||||
                'synced': w['synced'],
 | 
			
		||||
                'deposit_address': w['deposit_address'],
 | 
			
		||||
                'expected_seed': w['expected_seed'],
 | 
			
		||||
                'balance_all': float(w['balance']) + float(w['unconfirmed']),
 | 
			
		||||
                'updating': w['updating'],
 | 
			
		||||
                'lastupdated': format_timestamp(w['lastupdated']),
 | 
			
		||||
                'havedata': True,
 | 
			
		||||
            }
 | 
			
		||||
            if float(w['unconfirmed']) > 0.0:
 | 
			
		||||
                wf['unconfirmed'] = w['unconfirmed']
 | 
			
		||||
 | 
			
		||||
            if k == Coins.PART:
 | 
			
		||||
                wf['stealth_address'] = w['stealth_address']
 | 
			
		||||
                wf['blind_balance'] = w['blind_balance']
 | 
			
		||||
                if float(w['blind_unconfirmed']) > 0.0:
 | 
			
		||||
                    wf['blind_unconfirmed'] = w['blind_unconfirmed']
 | 
			
		||||
                wf['anon_balance'] = w['anon_balance']
 | 
			
		||||
                if float(w['anon_pending']) > 0.0:
 | 
			
		||||
                    wf['anon_pending'] = w['anon_pending']
 | 
			
		||||
 | 
			
		||||
            wallets_formatted.append(wf)
 | 
			
		||||
 | 
			
		||||
        template = env.get_template('wallets.html')
 | 
			
		||||
        return bytes(template.render(
 | 
			
		||||
            title=self.server.title,
 | 
			
		||||
            h2=self.server.title,
 | 
			
		||||
            messages=messages,
 | 
			
		||||
            wallets=wallets_formatted,
 | 
			
		||||
            form_id=os.urandom(8).hex(),
 | 
			
		||||
        ), 'UTF-8')
 | 
			
		||||
 | 
			
		||||
    def page_wallet(self, url_split, post_string):
 | 
			
		||||
        ensure(len(url_split) > 2, 'Wallet not specified')
 | 
			
		||||
        wallet_ticker = url_split[2]
 | 
			
		||||
        swap_client = self.server.swap_client
 | 
			
		||||
 | 
			
		||||
        coin_id = getCoinIdFromTicker(wallet_ticker)
 | 
			
		||||
 | 
			
		||||
        page_data = {}
 | 
			
		||||
        messages = []
 | 
			
		||||
        form_data = self.checkForm(post_string, 'settings', messages)
 | 
			
		||||
        show_utxo_groups = False
 | 
			
		||||
        if form_data:
 | 
			
		||||
            cid = str(int(coin_id))
 | 
			
		||||
 | 
			
		||||
            if bytes('newaddr_' + cid, 'utf-8') in form_data:
 | 
			
		||||
                swap_client.cacheNewAddressForCoin(coin_id)
 | 
			
		||||
            elif bytes('reseed_' + cid, 'utf-8') in form_data:
 | 
			
		||||
                try:
 | 
			
		||||
                    swap_client.reseedWallet(coin_id)
 | 
			
		||||
                    messages.append('Reseed complete ' + str(coin_id))
 | 
			
		||||
                except Exception as ex:
 | 
			
		||||
                    messages.append('Reseed failed ' + str(ex))
 | 
			
		||||
                swap_client.updateWalletsInfo(True, coin_id)
 | 
			
		||||
            elif bytes('withdraw_' + cid, 'utf-8') in form_data:
 | 
			
		||||
                try:
 | 
			
		||||
                    value = form_data[bytes('amt_' + cid, 'utf-8')][0].decode('utf-8')
 | 
			
		||||
                    page_data['wd_value_' + cid] = value
 | 
			
		||||
                except Exception as e:
 | 
			
		||||
                    messages.append('Error: Missing value')
 | 
			
		||||
                try:
 | 
			
		||||
                    address = form_data[bytes('to_' + cid, 'utf-8')][0].decode('utf-8')
 | 
			
		||||
                    page_data['wd_address_' + cid] = address
 | 
			
		||||
                except Exception as e:
 | 
			
		||||
                    messages.append('Error: Missing address')
 | 
			
		||||
 | 
			
		||||
                subfee = True if bytes('subfee_' + cid, 'utf-8') in form_data else False
 | 
			
		||||
                page_data['wd_subfee_' + cid] = subfee
 | 
			
		||||
 | 
			
		||||
                if coin_id == Coins.PART:
 | 
			
		||||
                    try:
 | 
			
		||||
                        type_from = form_data[bytes('withdraw_type_from_' + cid, 'utf-8')][0].decode('utf-8')
 | 
			
		||||
                        type_to = form_data[bytes('withdraw_type_to_' + cid, 'utf-8')][0].decode('utf-8')
 | 
			
		||||
                        page_data['wd_type_from_' + cid] = type_from
 | 
			
		||||
                        page_data['wd_type_to_' + cid] = type_to
 | 
			
		||||
                    except Exception as e:
 | 
			
		||||
                        messages.append('Error: Missing type')
 | 
			
		||||
 | 
			
		||||
                if len(messages) == 0:
 | 
			
		||||
                    ci = swap_client.ci(coin_id)
 | 
			
		||||
                    ticker = ci.ticker()
 | 
			
		||||
                    if coin_id == Coins.PART:
 | 
			
		||||
                        try:
 | 
			
		||||
                            txid = swap_client.withdrawParticl(type_from, type_to, value, address, subfee)
 | 
			
		||||
                            messages.append('Withdrew {} {} ({} to {}) to address {}<br/>In txid: {}'.format(value, ticker, type_from, type_to, address, txid))
 | 
			
		||||
                        except Exception as e:
 | 
			
		||||
                            messages.append('Error: {}'.format(str(e)))
 | 
			
		||||
                    else:
 | 
			
		||||
                        try:
 | 
			
		||||
                            txid = swap_client.withdrawCoin(coin_id, value, address, subfee)
 | 
			
		||||
                            messages.append('Withdrew {} {} to address {}<br/>In txid: {}'.format(value, ticker, address, txid))
 | 
			
		||||
                        except Exception as e:
 | 
			
		||||
                            messages.append('Error: {}'.format(str(e)))
 | 
			
		||||
                    swap_client.updateWalletsInfo(True, coin_id)
 | 
			
		||||
            elif have_data_entry(form_data, 'showutxogroups'):
 | 
			
		||||
                show_utxo_groups = True
 | 
			
		||||
            elif have_data_entry(form_data, 'create_utxo'):
 | 
			
		||||
                show_utxo_groups = True
 | 
			
		||||
                try:
 | 
			
		||||
                    value = get_data_entry(form_data, 'utxo_value')
 | 
			
		||||
                    page_data['utxo_value'] = value
 | 
			
		||||
 | 
			
		||||
                    ci = swap_client.ci(coin_id)
 | 
			
		||||
 | 
			
		||||
                    value_sats = ci.make_int(value)
 | 
			
		||||
 | 
			
		||||
                    txid, address = ci.createUTXO(value_sats)
 | 
			
		||||
                    messages.append('Created new utxo of value {} and address {}<br/>In txid: {}'.format(value, address, txid))
 | 
			
		||||
                except Exception as e:
 | 
			
		||||
                    messages.append('Error: {}'.format(str(e)))
 | 
			
		||||
                    if swap_client.debug is True:
 | 
			
		||||
                        swap_client.log.error(traceback.format_exc())
 | 
			
		||||
 | 
			
		||||
        swap_client.updateWalletsInfo()
 | 
			
		||||
        wallets = swap_client.getCachedWalletsInfo({'coin_id': coin_id})
 | 
			
		||||
        for k in wallets.keys():
 | 
			
		||||
            w = wallets[k]
 | 
			
		||||
            if 'error' in w:
 | 
			
		||||
                wallet_data = {
 | 
			
		||||
                    'cid': str(int(k)),
 | 
			
		||||
                    'error': w['error']
 | 
			
		||||
                }
 | 
			
		||||
                continue
 | 
			
		||||
 | 
			
		||||
            if 'balance' not in w:
 | 
			
		||||
                wallet_data = {
 | 
			
		||||
                    'name': w['name'],
 | 
			
		||||
                    'havedata': False,
 | 
			
		||||
                    'updating': w['updating'],
 | 
			
		||||
                }
 | 
			
		||||
                continue
 | 
			
		||||
 | 
			
		||||
            ci = swap_client.ci(k)
 | 
			
		||||
            fee_rate, fee_src = swap_client.getFeeRateForCoin(k)
 | 
			
		||||
            est_fee = swap_client.estimateWithdrawFee(k, fee_rate)
 | 
			
		||||
            cid = str(int(k))
 | 
			
		||||
            wallet_data = {
 | 
			
		||||
                'name': w['name'],
 | 
			
		||||
                'version': w['version'],
 | 
			
		||||
                'ticker': ci.ticker_mainnet(),
 | 
			
		||||
                'cid': cid,
 | 
			
		||||
                'fee_rate': ci.format_amount(int(fee_rate * ci.COIN())),
 | 
			
		||||
                'fee_rate_src': fee_src,
 | 
			
		||||
                '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'],
 | 
			
		||||
                'deposit_address': w['deposit_address'],
 | 
			
		||||
                'expected_seed': w['expected_seed'],
 | 
			
		||||
                'balance_all': float(w['balance']) + float(w['unconfirmed']),
 | 
			
		||||
                'updating': w['updating'],
 | 
			
		||||
                'lastupdated': format_timestamp(w['lastupdated']),
 | 
			
		||||
                'havedata': True,
 | 
			
		||||
            }
 | 
			
		||||
            if float(w['unconfirmed']) > 0.0:
 | 
			
		||||
                wallet_data['unconfirmed'] = w['unconfirmed']
 | 
			
		||||
 | 
			
		||||
            if k == Coins.PART:
 | 
			
		||||
                wallet_data['stealth_address'] = w['stealth_address']
 | 
			
		||||
                wallet_data['blind_balance'] = w['blind_balance']
 | 
			
		||||
                if float(w['blind_unconfirmed']) > 0.0:
 | 
			
		||||
                    wallet_data['blind_unconfirmed'] = w['blind_unconfirmed']
 | 
			
		||||
                wallet_data['anon_balance'] = w['anon_balance']
 | 
			
		||||
                if float(w['anon_pending']) > 0.0:
 | 
			
		||||
                    wallet_data['anon_pending'] = w['anon_pending']
 | 
			
		||||
 | 
			
		||||
            elif k == Coins.XMR:
 | 
			
		||||
                wallet_data['main_address'] = w.get('main_address', 'Refresh necessary')
 | 
			
		||||
 | 
			
		||||
            if 'wd_type_from_' + cid in page_data:
 | 
			
		||||
                wallet_data['wd_type_from'] = page_data['wd_type_from_' + cid]
 | 
			
		||||
            if 'wd_type_to_' + cid in page_data:
 | 
			
		||||
                wallet_data['wd_type_to'] = page_data['wd_type_to_' + cid]
 | 
			
		||||
 | 
			
		||||
            if 'wd_value_' + cid in page_data:
 | 
			
		||||
                wallet_data['wd_value'] = page_data['wd_value_' + cid]
 | 
			
		||||
            if 'wd_address_' + cid in page_data:
 | 
			
		||||
                wallet_data['wd_address'] = page_data['wd_address_' + cid]
 | 
			
		||||
            if 'wd_subfee_' + cid in page_data:
 | 
			
		||||
                wallet_data['wd_subfee'] = page_data['wd_subfee_' + cid]
 | 
			
		||||
            if 'utxo_value' in page_data:
 | 
			
		||||
                wallet_data['utxo_value'] = page_data['utxo_value']
 | 
			
		||||
 | 
			
		||||
            if show_utxo_groups:
 | 
			
		||||
                utxo_groups = ''
 | 
			
		||||
 | 
			
		||||
                unspent_by_addr = swap_client.getUnspentsByAddr(k)
 | 
			
		||||
 | 
			
		||||
                sorted_unspent_by_addr = sorted(unspent_by_addr.items(), key=lambda x: x[1], reverse=True)
 | 
			
		||||
                for kv in sorted_unspent_by_addr:
 | 
			
		||||
                    utxo_groups += kv[0] + ' ' + ci.format_amount(kv[1]) + '\n'
 | 
			
		||||
 | 
			
		||||
                wallet_data['show_utxo_groups'] = True
 | 
			
		||||
                wallet_data['utxo_groups'] = utxo_groups
 | 
			
		||||
 | 
			
		||||
        template = env.get_template('wallet.html')
 | 
			
		||||
        return bytes(template.render(
 | 
			
		||||
            title=self.server.title,
 | 
			
		||||
            h2=self.server.title,
 | 
			
		||||
            messages=messages,
 | 
			
		||||
            w=wallet_data,
 | 
			
		||||
            form_id=os.urandom(8).hex(),
 | 
			
		||||
        ), 'UTF-8')
 | 
			
		||||
 | 
			
		||||
    def page_settings(self, url_split, post_string):
 | 
			
		||||
        swap_client = self.server.swap_client
 | 
			
		||||
 | 
			
		||||
@ -1000,9 +702,9 @@ class HttpHandler(BaseHTTPRequestHandler):
 | 
			
		||||
                if url_split[1] == 'active':
 | 
			
		||||
                    return self.page_active(url_split, post_string)
 | 
			
		||||
                if url_split[1] == 'wallets':
 | 
			
		||||
                    return self.page_wallets(url_split, post_string)
 | 
			
		||||
                    return page_wallets(self, url_split, post_string)
 | 
			
		||||
                if url_split[1] == 'wallet':
 | 
			
		||||
                    return self.page_wallet(url_split, post_string)
 | 
			
		||||
                    return page_wallet(self, url_split, post_string)
 | 
			
		||||
                if url_split[1] == 'settings':
 | 
			
		||||
                    return self.page_settings(url_split, post_string)
 | 
			
		||||
                if url_split[1] == 'rpc':
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
#!/usr/bin/env python
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
 | 
			
		||||
# Copyright (c) 2020-2021 tecnovert
 | 
			
		||||
# Copyright (c) 2020-2022 tecnovert
 | 
			
		||||
# Distributed under the MIT software license, see the accompanying
 | 
			
		||||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
 | 
			
		||||
 | 
			
		||||
@ -117,22 +117,34 @@ class XMRInterface(CoinInterface):
 | 
			
		||||
        return self.rpc_wallet_cb('get_version')['version']
 | 
			
		||||
 | 
			
		||||
    def getBlockchainInfo(self):
 | 
			
		||||
        rv = {}
 | 
			
		||||
        get_height = self.rpc_cb2('get_height', timeout=30)
 | 
			
		||||
        rv = {
 | 
			
		||||
            'blocks': get_height['height'],
 | 
			
		||||
            'verificationprogress': 0.0,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        # get_block_count returns "Internal error" if bootstrap-daemon is active
 | 
			
		||||
        # rv['blocks'] = self.rpc_cb('get_block_count')['count']
 | 
			
		||||
        rv['blocks'] = self.rpc_cb2('get_height', timeout=30)['height']
 | 
			
		||||
        try:
 | 
			
		||||
            # get_block_count.block_count is how many blocks are in the longest chain known to the node.
 | 
			
		||||
            # get_block_count returns "Internal error" if bootstrap-daemon is active
 | 
			
		||||
            if get_height['untrusted'] is True:
 | 
			
		||||
                rv['untrusted'] = True
 | 
			
		||||
                get_info = self.rpc_cb2('get_info', timeout=30)
 | 
			
		||||
                if 'height_without_bootstrap' in get_info:
 | 
			
		||||
                    rv['blocks'] = get_info['height_without_bootstrap']
 | 
			
		||||
 | 
			
		||||
        # sync_info = self.rpc_cb('sync_info', timeout=30)
 | 
			
		||||
        # rv['verificationprogress'] = 0.0 if 'spans' in sync_info else 1.0
 | 
			
		||||
        rv['verificationprogress'] = 0.0
 | 
			
		||||
                rv['block_count'] = get_info['height']
 | 
			
		||||
                if rv['block_count'] > rv['blocks']:
 | 
			
		||||
                    rv['verificationprogress'] = rv['blocks'] / rv['block_count']
 | 
			
		||||
            else:
 | 
			
		||||
                rv['block_count'] = self.rpc_cb('get_block_count', timeout=30)['count']
 | 
			
		||||
                rv['verificationprogress'] = rv['blocks'] / rv['block_count']
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            self._log.warning('XMR get_block_count failed with: %s', str(e))
 | 
			
		||||
            rv['verificationprogress'] = 0.0
 | 
			
		||||
 | 
			
		||||
        return rv
 | 
			
		||||
 | 
			
		||||
    def getChainHeight(self):
 | 
			
		||||
        # get_block_count returns "Internal error" if bootstrap-daemon is active
 | 
			
		||||
        # return self.rpc_cb('get_info')['height']
 | 
			
		||||
        # return self.rpc_cb('get_block_count')['count']
 | 
			
		||||
        return self.rpc_cb2('get_height', timeout=30)['height']
 | 
			
		||||
 | 
			
		||||
    def getWalletInfo(self):
 | 
			
		||||
 | 
			
		||||
@ -62,6 +62,7 @@ def withdraw_coin(swap_client, coin_type, post_string, is_json):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def js_wallets(self, url_split, post_string, is_json):
 | 
			
		||||
    swap_client = self.server.swap_client
 | 
			
		||||
    if len(url_split) > 3:
 | 
			
		||||
        ticker_str = url_split[3]
 | 
			
		||||
        coin_type = tickerToCoinId(ticker_str)
 | 
			
		||||
@ -69,9 +70,11 @@ def js_wallets(self, url_split, post_string, is_json):
 | 
			
		||||
        if len(url_split) > 4:
 | 
			
		||||
            cmd = url_split[4]
 | 
			
		||||
            if cmd == 'withdraw':
 | 
			
		||||
                return bytes(json.dumps(withdraw_coin(self.server.swap_client, coin_type, post_string, is_json)), 'UTF-8')
 | 
			
		||||
                return bytes(json.dumps(withdraw_coin(swap_client, coin_type, post_string, is_json)), 'UTF-8')
 | 
			
		||||
            raise ValueError('Unknown command')
 | 
			
		||||
        return bytes(json.dumps(self.server.swap_client.getWalletInfo(coin_type)), 'UTF-8')
 | 
			
		||||
 | 
			
		||||
        rv = swap_client.getWalletInfo(coin_type).update(swap_client.getBlockchainInfo(coin_type))
 | 
			
		||||
        return bytes(json.dumps(rv), 'UTF-8')
 | 
			
		||||
    return bytes(json.dumps(self.server.swap_client.getWalletsInfo()), 'UTF-8')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										327
									
								
								basicswap/ui/page_wallet.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										327
									
								
								basicswap/ui/page_wallet.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,327 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
 | 
			
		||||
# Copyright (c) 2022 tecnovert
 | 
			
		||||
# Distributed under the MIT software license, see the accompanying
 | 
			
		||||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
 | 
			
		||||
 | 
			
		||||
import os
 | 
			
		||||
import traceback
 | 
			
		||||
 | 
			
		||||
from .util import (
 | 
			
		||||
    get_data_entry,
 | 
			
		||||
    have_data_entry,
 | 
			
		||||
)
 | 
			
		||||
from basicswap.util import (
 | 
			
		||||
    ensure,
 | 
			
		||||
    format_timestamp,
 | 
			
		||||
)
 | 
			
		||||
from basicswap.chainparams import (
 | 
			
		||||
    Coins,
 | 
			
		||||
    chainparams,
 | 
			
		||||
    getCoinIdFromTicker,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def page_wallets(self, url_split, post_string):
 | 
			
		||||
    server = self.server
 | 
			
		||||
    swap_client = server.swap_client
 | 
			
		||||
 | 
			
		||||
    page_data = {}
 | 
			
		||||
    messages = []
 | 
			
		||||
    form_data = self.checkForm(post_string, 'wallets', messages)
 | 
			
		||||
    if form_data:
 | 
			
		||||
        for c in Coins:
 | 
			
		||||
            if c not in chainparams:
 | 
			
		||||
                continue
 | 
			
		||||
            cid = str(int(c))
 | 
			
		||||
 | 
			
		||||
            if bytes('newaddr_' + cid, 'utf-8') in form_data:
 | 
			
		||||
                swap_client.cacheNewAddressForCoin(c)
 | 
			
		||||
            elif bytes('reseed_' + cid, 'utf-8') in form_data:
 | 
			
		||||
                try:
 | 
			
		||||
                    swap_client.reseedWallet(c)
 | 
			
		||||
                    messages.append('Reseed complete ' + str(c))
 | 
			
		||||
                except Exception as ex:
 | 
			
		||||
                    messages.append('Reseed failed ' + str(ex))
 | 
			
		||||
                swap_client.updateWalletsInfo(True, c)
 | 
			
		||||
            elif bytes('withdraw_' + cid, 'utf-8') in form_data:
 | 
			
		||||
                try:
 | 
			
		||||
                    value = form_data[bytes('amt_' + cid, 'utf-8')][0].decode('utf-8')
 | 
			
		||||
                    page_data['wd_value_' + cid] = value
 | 
			
		||||
                except Exception as e:
 | 
			
		||||
                    messages.append('Error: Missing value')
 | 
			
		||||
                try:
 | 
			
		||||
                    address = form_data[bytes('to_' + cid, 'utf-8')][0].decode('utf-8')
 | 
			
		||||
                    page_data['wd_address_' + cid] = address
 | 
			
		||||
                except Exception as e:
 | 
			
		||||
                    messages.append('Error: Missing address')
 | 
			
		||||
 | 
			
		||||
                subfee = True if bytes('subfee_' + cid, 'utf-8') in form_data else False
 | 
			
		||||
                page_data['wd_subfee_' + cid] = subfee
 | 
			
		||||
 | 
			
		||||
                if c == Coins.PART:
 | 
			
		||||
                    try:
 | 
			
		||||
                        type_from = form_data[bytes('withdraw_type_from_' + cid, 'utf-8')][0].decode('utf-8')
 | 
			
		||||
                        type_to = form_data[bytes('withdraw_type_to_' + cid, 'utf-8')][0].decode('utf-8')
 | 
			
		||||
                        page_data['wd_type_from_' + cid] = type_from
 | 
			
		||||
                        page_data['wd_type_to_' + cid] = type_to
 | 
			
		||||
                    except Exception as e:
 | 
			
		||||
                        messages.append('Error: Missing type')
 | 
			
		||||
 | 
			
		||||
                if len(messages) == 0:
 | 
			
		||||
                    ci = swap_client.ci(c)
 | 
			
		||||
                    ticker = ci.ticker()
 | 
			
		||||
                    if c == Coins.PART:
 | 
			
		||||
                        try:
 | 
			
		||||
                            txid = swap_client.withdrawParticl(type_from, type_to, value, address, subfee)
 | 
			
		||||
                            messages.append('Withdrew {} {} ({} to {}) to address {}<br/>In txid: {}'.format(value, ticker, type_from, type_to, address, txid))
 | 
			
		||||
                        except Exception as e:
 | 
			
		||||
                            messages.append('Error: {}'.format(str(e)))
 | 
			
		||||
                    else:
 | 
			
		||||
                        try:
 | 
			
		||||
                            txid = swap_client.withdrawCoin(c, value, address, subfee)
 | 
			
		||||
                            messages.append('Withdrew {} {} to address {}<br/>In txid: {}'.format(value, ticker, address, txid))
 | 
			
		||||
                        except Exception as e:
 | 
			
		||||
                            messages.append('Error: {}'.format(str(e)))
 | 
			
		||||
                    swap_client.updateWalletsInfo(True, c)
 | 
			
		||||
 | 
			
		||||
    swap_client.updateWalletsInfo()
 | 
			
		||||
    wallets = swap_client.getCachedWalletsInfo()
 | 
			
		||||
 | 
			
		||||
    wallets_formatted = []
 | 
			
		||||
    sk = sorted(wallets.keys())
 | 
			
		||||
 | 
			
		||||
    for k in sk:
 | 
			
		||||
        w = wallets[k]
 | 
			
		||||
        if 'error' in w:
 | 
			
		||||
            wallets_formatted.append({
 | 
			
		||||
                'cid': str(int(k)),
 | 
			
		||||
                'error': w['error']
 | 
			
		||||
            })
 | 
			
		||||
            continue
 | 
			
		||||
 | 
			
		||||
        if 'no_data' in w:
 | 
			
		||||
            wallets_formatted.append({
 | 
			
		||||
                'name': w['name'],
 | 
			
		||||
                'havedata': False,
 | 
			
		||||
                'updating': w['updating'],
 | 
			
		||||
            })
 | 
			
		||||
            continue
 | 
			
		||||
 | 
			
		||||
        ci = swap_client.ci(k)
 | 
			
		||||
        cid = str(int(k))
 | 
			
		||||
        wf = {
 | 
			
		||||
            'name': ci.coin_name(),
 | 
			
		||||
            'version': w.get('version', '?'),
 | 
			
		||||
            'ticker': ci.ticker_mainnet(),
 | 
			
		||||
            'cid': cid,
 | 
			
		||||
            'balance': w.get('balance', '?'),
 | 
			
		||||
            'blocks': w.get('blocks', '?'),
 | 
			
		||||
            'synced': w.get('synced', '?'),
 | 
			
		||||
            'deposit_address': w.get('deposit_address', '?'),
 | 
			
		||||
            'expected_seed': w.get('expected_seed', '?'),
 | 
			
		||||
            'updating': w.get('updating', '?'),
 | 
			
		||||
            'havedata': True,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if 'balance' in w and 'unconfirmed' in w:
 | 
			
		||||
            wf['balance_all'] = float(w['balance']) + float(w['unconfirmed'])
 | 
			
		||||
        if 'lastupdated' in w:
 | 
			
		||||
            wf['lastupdated'] = format_timestamp(w['lastupdated'])
 | 
			
		||||
        if 'unconfirmed' in w and float(w['unconfirmed']) > 0.0:
 | 
			
		||||
            wf['unconfirmed'] = w['unconfirmed']
 | 
			
		||||
 | 
			
		||||
        if k == Coins.PART:
 | 
			
		||||
            wf['stealth_address'] = w.get('stealth_address', '?')
 | 
			
		||||
            wf['blind_balance'] = w.get('blind_balance', '?')
 | 
			
		||||
            if 'blind_unconfirmed' in w and float(w['blind_unconfirmed']) > 0.0:
 | 
			
		||||
                wf['blind_unconfirmed'] = w['blind_unconfirmed']
 | 
			
		||||
            wf['anon_balance'] = w.get('anon_balance', '?')
 | 
			
		||||
            if 'anon_pending' in w and float(w['anon_pending']) > 0.0:
 | 
			
		||||
                wf['anon_pending'] = w['anon_pending']
 | 
			
		||||
 | 
			
		||||
        wallets_formatted.append(wf)
 | 
			
		||||
 | 
			
		||||
    template = server.env.get_template('wallets.html')
 | 
			
		||||
    return bytes(template.render(
 | 
			
		||||
        title=server.title,
 | 
			
		||||
        h2=server.title,
 | 
			
		||||
        messages=messages,
 | 
			
		||||
        wallets=wallets_formatted,
 | 
			
		||||
        form_id=os.urandom(8).hex(),
 | 
			
		||||
    ), 'UTF-8')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def page_wallet(self, url_split, post_string):
 | 
			
		||||
    ensure(len(url_split) > 2, 'Wallet not specified')
 | 
			
		||||
    wallet_ticker = url_split[2]
 | 
			
		||||
    server = self.server
 | 
			
		||||
    swap_client = server.swap_client
 | 
			
		||||
 | 
			
		||||
    coin_id = getCoinIdFromTicker(wallet_ticker)
 | 
			
		||||
 | 
			
		||||
    page_data = {}
 | 
			
		||||
    messages = []
 | 
			
		||||
    form_data = self.checkForm(post_string, 'settings', messages)
 | 
			
		||||
    show_utxo_groups = False
 | 
			
		||||
    if form_data:
 | 
			
		||||
        cid = str(int(coin_id))
 | 
			
		||||
 | 
			
		||||
        if bytes('newaddr_' + cid, 'utf-8') in form_data:
 | 
			
		||||
            swap_client.cacheNewAddressForCoin(coin_id)
 | 
			
		||||
        elif bytes('reseed_' + cid, 'utf-8') in form_data:
 | 
			
		||||
            try:
 | 
			
		||||
                swap_client.reseedWallet(coin_id)
 | 
			
		||||
                messages.append('Reseed complete ' + str(coin_id))
 | 
			
		||||
            except Exception as ex:
 | 
			
		||||
                messages.append('Reseed failed ' + str(ex))
 | 
			
		||||
            swap_client.updateWalletsInfo(True, coin_id)
 | 
			
		||||
        elif bytes('withdraw_' + cid, 'utf-8') in form_data:
 | 
			
		||||
            try:
 | 
			
		||||
                value = form_data[bytes('amt_' + cid, 'utf-8')][0].decode('utf-8')
 | 
			
		||||
                page_data['wd_value_' + cid] = value
 | 
			
		||||
            except Exception as e:
 | 
			
		||||
                messages.append('Error: Missing value')
 | 
			
		||||
            try:
 | 
			
		||||
                address = form_data[bytes('to_' + cid, 'utf-8')][0].decode('utf-8')
 | 
			
		||||
                page_data['wd_address_' + cid] = address
 | 
			
		||||
            except Exception as e:
 | 
			
		||||
                messages.append('Error: Missing address')
 | 
			
		||||
 | 
			
		||||
            subfee = True if bytes('subfee_' + cid, 'utf-8') in form_data else False
 | 
			
		||||
            page_data['wd_subfee_' + cid] = subfee
 | 
			
		||||
 | 
			
		||||
            if coin_id == Coins.PART:
 | 
			
		||||
                try:
 | 
			
		||||
                    type_from = form_data[bytes('withdraw_type_from_' + cid, 'utf-8')][0].decode('utf-8')
 | 
			
		||||
                    type_to = form_data[bytes('withdraw_type_to_' + cid, 'utf-8')][0].decode('utf-8')
 | 
			
		||||
                    page_data['wd_type_from_' + cid] = type_from
 | 
			
		||||
                    page_data['wd_type_to_' + cid] = type_to
 | 
			
		||||
                except Exception as e:
 | 
			
		||||
                    messages.append('Error: Missing type')
 | 
			
		||||
 | 
			
		||||
            if len(messages) == 0:
 | 
			
		||||
                ci = swap_client.ci(coin_id)
 | 
			
		||||
                ticker = ci.ticker()
 | 
			
		||||
                if coin_id == Coins.PART:
 | 
			
		||||
                    try:
 | 
			
		||||
                        txid = swap_client.withdrawParticl(type_from, type_to, value, address, subfee)
 | 
			
		||||
                        messages.append('Withdrew {} {} ({} to {}) to address {}<br/>In txid: {}'.format(value, ticker, type_from, type_to, address, txid))
 | 
			
		||||
                    except Exception as e:
 | 
			
		||||
                        messages.append('Error: {}'.format(str(e)))
 | 
			
		||||
                else:
 | 
			
		||||
                    try:
 | 
			
		||||
                        txid = swap_client.withdrawCoin(coin_id, value, address, subfee)
 | 
			
		||||
                        messages.append('Withdrew {} {} to address {}<br/>In txid: {}'.format(value, ticker, address, txid))
 | 
			
		||||
                    except Exception as e:
 | 
			
		||||
                        messages.append('Error: {}'.format(str(e)))
 | 
			
		||||
                swap_client.updateWalletsInfo(True, coin_id)
 | 
			
		||||
        elif have_data_entry(form_data, 'showutxogroups'):
 | 
			
		||||
            show_utxo_groups = True
 | 
			
		||||
        elif have_data_entry(form_data, 'create_utxo'):
 | 
			
		||||
            show_utxo_groups = True
 | 
			
		||||
            try:
 | 
			
		||||
                value = get_data_entry(form_data, 'utxo_value')
 | 
			
		||||
                page_data['utxo_value'] = value
 | 
			
		||||
 | 
			
		||||
                ci = swap_client.ci(coin_id)
 | 
			
		||||
 | 
			
		||||
                value_sats = ci.make_int(value)
 | 
			
		||||
 | 
			
		||||
                txid, address = ci.createUTXO(value_sats)
 | 
			
		||||
                messages.append('Created new utxo of value {} and address {}<br/>In txid: {}'.format(value, address, txid))
 | 
			
		||||
            except Exception as e:
 | 
			
		||||
                messages.append('Error: {}'.format(str(e)))
 | 
			
		||||
                if swap_client.debug is True:
 | 
			
		||||
                    swap_client.log.error(traceback.format_exc())
 | 
			
		||||
 | 
			
		||||
    swap_client.updateWalletsInfo()
 | 
			
		||||
    wallets = swap_client.getCachedWalletsInfo({'coin_id': coin_id})
 | 
			
		||||
    for k in wallets.keys():
 | 
			
		||||
        w = wallets[k]
 | 
			
		||||
        if 'error' in w:
 | 
			
		||||
            wallet_data = {
 | 
			
		||||
                'cid': str(int(k)),
 | 
			
		||||
                'error': w['error']
 | 
			
		||||
            }
 | 
			
		||||
            continue
 | 
			
		||||
 | 
			
		||||
        if 'balance' not in w:
 | 
			
		||||
            wallet_data = {
 | 
			
		||||
                'name': w['name'],
 | 
			
		||||
                'havedata': False,
 | 
			
		||||
                'updating': w['updating'],
 | 
			
		||||
            }
 | 
			
		||||
            continue
 | 
			
		||||
 | 
			
		||||
        ci = swap_client.ci(k)
 | 
			
		||||
        fee_rate, fee_src = swap_client.getFeeRateForCoin(k)
 | 
			
		||||
        est_fee = swap_client.estimateWithdrawFee(k, fee_rate)
 | 
			
		||||
        cid = str(int(k))
 | 
			
		||||
        wallet_data = {
 | 
			
		||||
            'name': w['name'],
 | 
			
		||||
            'version': w['version'],
 | 
			
		||||
            'ticker': ci.ticker_mainnet(),
 | 
			
		||||
            'cid': cid,
 | 
			
		||||
            'fee_rate': ci.format_amount(int(fee_rate * ci.COIN())),
 | 
			
		||||
            'fee_rate_src': fee_src,
 | 
			
		||||
            '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'],
 | 
			
		||||
            'deposit_address': w['deposit_address'],
 | 
			
		||||
            'expected_seed': w['expected_seed'],
 | 
			
		||||
            'balance_all': float(w['balance']) + float(w['unconfirmed']),
 | 
			
		||||
            'updating': w['updating'],
 | 
			
		||||
            'lastupdated': format_timestamp(w['lastupdated']),
 | 
			
		||||
            'havedata': True,
 | 
			
		||||
        }
 | 
			
		||||
        if float(w['unconfirmed']) > 0.0:
 | 
			
		||||
            wallet_data['unconfirmed'] = w['unconfirmed']
 | 
			
		||||
 | 
			
		||||
        if k == Coins.PART:
 | 
			
		||||
            wallet_data['stealth_address'] = w['stealth_address']
 | 
			
		||||
            wallet_data['blind_balance'] = w['blind_balance']
 | 
			
		||||
            if float(w['blind_unconfirmed']) > 0.0:
 | 
			
		||||
                wallet_data['blind_unconfirmed'] = w['blind_unconfirmed']
 | 
			
		||||
            wallet_data['anon_balance'] = w['anon_balance']
 | 
			
		||||
            if float(w['anon_pending']) > 0.0:
 | 
			
		||||
                wallet_data['anon_pending'] = w['anon_pending']
 | 
			
		||||
 | 
			
		||||
        elif k == Coins.XMR:
 | 
			
		||||
            wallet_data['main_address'] = w.get('main_address', 'Refresh necessary')
 | 
			
		||||
 | 
			
		||||
        if 'wd_type_from_' + cid in page_data:
 | 
			
		||||
            wallet_data['wd_type_from'] = page_data['wd_type_from_' + cid]
 | 
			
		||||
        if 'wd_type_to_' + cid in page_data:
 | 
			
		||||
            wallet_data['wd_type_to'] = page_data['wd_type_to_' + cid]
 | 
			
		||||
 | 
			
		||||
        if 'wd_value_' + cid in page_data:
 | 
			
		||||
            wallet_data['wd_value'] = page_data['wd_value_' + cid]
 | 
			
		||||
        if 'wd_address_' + cid in page_data:
 | 
			
		||||
            wallet_data['wd_address'] = page_data['wd_address_' + cid]
 | 
			
		||||
        if 'wd_subfee_' + cid in page_data:
 | 
			
		||||
            wallet_data['wd_subfee'] = page_data['wd_subfee_' + cid]
 | 
			
		||||
        if 'utxo_value' in page_data:
 | 
			
		||||
            wallet_data['utxo_value'] = page_data['utxo_value']
 | 
			
		||||
 | 
			
		||||
        if show_utxo_groups:
 | 
			
		||||
            utxo_groups = ''
 | 
			
		||||
 | 
			
		||||
            unspent_by_addr = swap_client.getUnspentsByAddr(k)
 | 
			
		||||
 | 
			
		||||
            sorted_unspent_by_addr = sorted(unspent_by_addr.items(), key=lambda x: x[1], reverse=True)
 | 
			
		||||
            for kv in sorted_unspent_by_addr:
 | 
			
		||||
                utxo_groups += kv[0] + ' ' + ci.format_amount(kv[1]) + '\n'
 | 
			
		||||
 | 
			
		||||
            wallet_data['show_utxo_groups'] = True
 | 
			
		||||
            wallet_data['utxo_groups'] = utxo_groups
 | 
			
		||||
 | 
			
		||||
    template = server.env.get_template('wallet.html')
 | 
			
		||||
    return bytes(template.render(
 | 
			
		||||
        title=server.title,
 | 
			
		||||
        h2=server.title,
 | 
			
		||||
        messages=messages,
 | 
			
		||||
        w=wallet_data,
 | 
			
		||||
        form_id=os.urandom(8).hex(),
 | 
			
		||||
    ), 'UTF-8')
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user