refactor: Add automation tables.
This commit is contained in:
		
							parent
							
								
									f4649d34b2
								
							
						
					
					
						commit
						8daa76f937
					
				@ -94,7 +94,10 @@ from .db import (
 | 
			
		||||
    XmrSplitData,
 | 
			
		||||
    Wallets,
 | 
			
		||||
    KnownIdentity,
 | 
			
		||||
    AutomationLink,
 | 
			
		||||
    AutomationStrategy,
 | 
			
		||||
)
 | 
			
		||||
from .db_upgrades import upgradeDatabase, upgradeDatabaseData
 | 
			
		||||
from .base import BaseApp
 | 
			
		||||
from .explorers import (
 | 
			
		||||
    ExplorerInsight,
 | 
			
		||||
@ -130,6 +133,7 @@ from .protocols.xmr_swap_1 import (
 | 
			
		||||
    addLockRefundSigs,
 | 
			
		||||
    recoverNoScriptTxnWithKey)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
non_script_type_coins = (Coins.XMR, Coins.PART_ANON)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -266,6 +270,10 @@ class BasicSwap(BaseApp):
 | 
			
		||||
                value=self.db_version
 | 
			
		||||
            ))
 | 
			
		||||
            session.commit()
 | 
			
		||||
        try:
 | 
			
		||||
            self.db_data_version = session.query(DBKVInt).filter_by(key='db_data_version').first().value
 | 
			
		||||
        except Exception:
 | 
			
		||||
            self.db_data_version = 0
 | 
			
		||||
        try:
 | 
			
		||||
            self._contract_count = session.query(DBKVInt).filter_by(key='contract_count').first().value
 | 
			
		||||
        except Exception:
 | 
			
		||||
@ -518,7 +526,8 @@ class BasicSwap(BaseApp):
 | 
			
		||||
        self.log.info('sqlalchemy version %s', sa.__version__)
 | 
			
		||||
        self.log.info('timezone offset: %d (%s)', time.timezone, time.tzname[0])
 | 
			
		||||
 | 
			
		||||
        self.upgradeDatabase(self.db_version)
 | 
			
		||||
        upgradeDatabase(self, self.db_version)
 | 
			
		||||
        upgradeDatabaseData(self, self.db_data_version)
 | 
			
		||||
 | 
			
		||||
        for c in Coins:
 | 
			
		||||
            if c not in chainparams:
 | 
			
		||||
@ -599,93 +608,6 @@ class BasicSwap(BaseApp):
 | 
			
		||||
            if self.coin_clients[c]['connection_type'] == 'rpc' and chain_client_settings['manage_daemon'] is True:
 | 
			
		||||
                self.stopDaemon(c)
 | 
			
		||||
 | 
			
		||||
    def upgradeDatabase(self, db_version):
 | 
			
		||||
        if db_version >= CURRENT_DB_VERSION:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        self.log.info('Upgrading database from version %d to %d.', db_version, CURRENT_DB_VERSION)
 | 
			
		||||
 | 
			
		||||
        while True:
 | 
			
		||||
            session = scoped_session(self.session_factory)
 | 
			
		||||
 | 
			
		||||
            current_version = db_version
 | 
			
		||||
            if current_version == 6:
 | 
			
		||||
                session.execute('ALTER TABLE bids ADD COLUMN security_token BLOB')
 | 
			
		||||
                session.execute('ALTER TABLE offers ADD COLUMN security_token BLOB')
 | 
			
		||||
                db_version += 1
 | 
			
		||||
            elif current_version == 7:
 | 
			
		||||
                session.execute('ALTER TABLE transactions ADD COLUMN block_hash BLOB')
 | 
			
		||||
                session.execute('ALTER TABLE transactions ADD COLUMN block_height INTEGER')
 | 
			
		||||
                session.execute('ALTER TABLE transactions ADD COLUMN block_time INTEGER')
 | 
			
		||||
                db_version += 1
 | 
			
		||||
            elif current_version == 8:
 | 
			
		||||
                session.execute('''
 | 
			
		||||
                    CREATE TABLE wallets (
 | 
			
		||||
                        record_id INTEGER NOT NULL,
 | 
			
		||||
                        coin_id INTEGER,
 | 
			
		||||
                        wallet_name VARCHAR,
 | 
			
		||||
                        balance_type INTEGER,
 | 
			
		||||
                        amount BIGINT,
 | 
			
		||||
                        updated_at BIGINT,
 | 
			
		||||
                        created_at BIGINT,
 | 
			
		||||
                        PRIMARY KEY (record_id))''')
 | 
			
		||||
                db_version += 1
 | 
			
		||||
            elif current_version == 9:
 | 
			
		||||
                session.execute('ALTER TABLE wallets ADD COLUMN wallet_data VARCHAR')
 | 
			
		||||
                db_version += 1
 | 
			
		||||
            elif current_version == 10:
 | 
			
		||||
                session.execute('ALTER TABLE smsgaddresses ADD COLUMN active_ind INTEGER')
 | 
			
		||||
                session.execute('ALTER TABLE smsgaddresses ADD COLUMN created_at INTEGER')
 | 
			
		||||
                session.execute('ALTER TABLE smsgaddresses ADD COLUMN note VARCHAR')
 | 
			
		||||
                session.execute('ALTER TABLE smsgaddresses ADD COLUMN pubkey VARCHAR')
 | 
			
		||||
                session.execute('UPDATE smsgaddresses SET active_ind = 1, created_at = 1')
 | 
			
		||||
 | 
			
		||||
                session.execute('ALTER TABLE offers ADD COLUMN addr_to VARCHAR')
 | 
			
		||||
                session.execute(f'UPDATE offers SET addr_to = "{self.network_addr}"')
 | 
			
		||||
                db_version += 1
 | 
			
		||||
            elif current_version == 11:
 | 
			
		||||
                session.execute('ALTER TABLE bids ADD COLUMN chain_a_height_start INTEGER')
 | 
			
		||||
                session.execute('ALTER TABLE bids ADD COLUMN chain_b_height_start INTEGER')
 | 
			
		||||
                session.execute('ALTER TABLE bids ADD COLUMN protocol_version INTEGER')
 | 
			
		||||
                session.execute('ALTER TABLE offers ADD COLUMN protocol_version INTEGER')
 | 
			
		||||
                session.execute('ALTER TABLE transactions ADD COLUMN tx_data BLOB')
 | 
			
		||||
                db_version += 1
 | 
			
		||||
            elif current_version == 12:
 | 
			
		||||
                session.execute('''
 | 
			
		||||
                    CREATE TABLE knownidentities (
 | 
			
		||||
                        record_id INTEGER NOT NULL,
 | 
			
		||||
                        address VARCHAR,
 | 
			
		||||
                        label VARCHAR,
 | 
			
		||||
                        publickey BLOB,
 | 
			
		||||
                        num_sent_bids_successful INTEGER,
 | 
			
		||||
                        num_recv_bids_successful INTEGER,
 | 
			
		||||
                        num_sent_bids_rejected INTEGER,
 | 
			
		||||
                        num_recv_bids_rejected INTEGER,
 | 
			
		||||
                        num_sent_bids_failed INTEGER,
 | 
			
		||||
                        num_recv_bids_failed INTEGER,
 | 
			
		||||
                        note VARCHAR,
 | 
			
		||||
                        updated_at BIGINT,
 | 
			
		||||
                        created_at BIGINT,
 | 
			
		||||
                        PRIMARY KEY (record_id))''')
 | 
			
		||||
                session.execute('ALTER TABLE bids ADD COLUMN reject_code INTEGER')
 | 
			
		||||
                session.execute('ALTER TABLE bids ADD COLUMN rate INTEGER')
 | 
			
		||||
                session.execute('ALTER TABLE offers ADD COLUMN amount_negotiable INTEGER')
 | 
			
		||||
                session.execute('ALTER TABLE offers ADD COLUMN rate_negotiable INTEGER')
 | 
			
		||||
                db_version += 1
 | 
			
		||||
 | 
			
		||||
            if current_version != db_version:
 | 
			
		||||
                self.db_version = db_version
 | 
			
		||||
                self.setIntKVInSession('db_version', db_version, session)
 | 
			
		||||
                session.commit()
 | 
			
		||||
                session.close()
 | 
			
		||||
                session.remove()
 | 
			
		||||
                self.log.info('Upgraded database to version {}'.format(self.db_version))
 | 
			
		||||
                continue
 | 
			
		||||
            break
 | 
			
		||||
 | 
			
		||||
        if db_version != CURRENT_DB_VERSION:
 | 
			
		||||
            raise ValueError('Unable to upgrade database.')
 | 
			
		||||
 | 
			
		||||
    def waitForDaemonRPC(self, coin_type):
 | 
			
		||||
        for i in range(self.startup_tries):
 | 
			
		||||
            if not self.is_running:
 | 
			
		||||
@ -1154,7 +1076,6 @@ class BasicSwap(BaseApp):
 | 
			
		||||
                created_at=offer_created_at,
 | 
			
		||||
                expire_at=offer_created_at + msg_buf.time_valid,
 | 
			
		||||
                was_sent=True,
 | 
			
		||||
                auto_accept_bids=auto_accept_bids,
 | 
			
		||||
                security_token=security_token)
 | 
			
		||||
            offer.setState(OfferStates.OFFER_SENT)
 | 
			
		||||
 | 
			
		||||
@ -1162,6 +1083,18 @@ class BasicSwap(BaseApp):
 | 
			
		||||
                xmr_offer.offer_id = offer_id
 | 
			
		||||
                session.add(xmr_offer)
 | 
			
		||||
 | 
			
		||||
            if auto_accept_bids:
 | 
			
		||||
                # Use default strategy
 | 
			
		||||
                auto_link = AutomationLink(
 | 
			
		||||
                    active_ind=1,
 | 
			
		||||
                    linked_type=TableTypes.OFFER,
 | 
			
		||||
                    linked_id=offer_id,
 | 
			
		||||
                    strategy_id=1,
 | 
			
		||||
                    created_at=offer_created_at,
 | 
			
		||||
                    repeat_limit=1,
 | 
			
		||||
                    repeat_count=0)
 | 
			
		||||
                session.add(auto_link)
 | 
			
		||||
 | 
			
		||||
            session.add(offer)
 | 
			
		||||
            session.add(SentOffer(offer_id=offer_id))
 | 
			
		||||
            session.commit()
 | 
			
		||||
@ -3833,6 +3766,54 @@ class BasicSwap(BaseApp):
 | 
			
		||||
                session.remove()
 | 
			
		||||
            self.mxDB.release()
 | 
			
		||||
 | 
			
		||||
    def shouldAutoAcceptBid(self, offer, bid, session=None):
 | 
			
		||||
        use_session = None
 | 
			
		||||
        try:
 | 
			
		||||
            if session:
 | 
			
		||||
                use_session = session
 | 
			
		||||
            else:
 | 
			
		||||
                self.mxDB.acquire()
 | 
			
		||||
                use_session = scoped_session(self.session_factory)
 | 
			
		||||
 | 
			
		||||
            link = session.query(AutomationLink).filter_by(active_ind=1, linked_type=TableTypes.OFFER, linked_id=offer.offer_id).first()
 | 
			
		||||
 | 
			
		||||
            if not link:
 | 
			
		||||
                return False
 | 
			
		||||
 | 
			
		||||
            strategy = session.query(AutomationStrategy).filter_by(active_ind=1, record_id=link.strategy_id).first()
 | 
			
		||||
            opts = json.loads(strategy.data.decode('utf-8'))
 | 
			
		||||
 | 
			
		||||
            self.log.debug('Evaluating against strategy {}'.format(strategy.record_id))
 | 
			
		||||
 | 
			
		||||
            if opts.get('full_amount_only', False) is True:
 | 
			
		||||
                if bid.amount != offer.amount_from:
 | 
			
		||||
                    self.log.info('Not auto accepting bid %s, want exact amount match', bid.bid_id.hex())
 | 
			
		||||
                    return False
 | 
			
		||||
 | 
			
		||||
            max_bids = opts.get('max_bids', 1)
 | 
			
		||||
            # Auto accept bid if set and no other non-abandoned bid for this order exists
 | 
			
		||||
            if self.countAcceptedBids(offer.offer_id) >= max_bids:
 | 
			
		||||
                self.log.info('Not auto accepting bid %s, already have', bid.bid_id.hex())
 | 
			
		||||
                return False
 | 
			
		||||
 | 
			
		||||
            if strategy.only_known_identities:
 | 
			
		||||
                identity_stats = session.query(KnownIdentity).filter_by(address=bid.bid_addr).first()
 | 
			
		||||
                if not identity_stats:
 | 
			
		||||
                    return False
 | 
			
		||||
 | 
			
		||||
                # TODO: More options
 | 
			
		||||
                if identity_stats.num_recv_bids_successful < 1:
 | 
			
		||||
                    return False
 | 
			
		||||
                if identity_stats.num_recv_bids_successful <= identity_stats.num_recv_bids_failed:
 | 
			
		||||
                    return False
 | 
			
		||||
 | 
			
		||||
            return True
 | 
			
		||||
        finally:
 | 
			
		||||
            if session is None:
 | 
			
		||||
                use_session.close()
 | 
			
		||||
                use_session.remove()
 | 
			
		||||
                self.mxDB.release()
 | 
			
		||||
 | 
			
		||||
    def processBid(self, msg):
 | 
			
		||||
        self.log.debug('Processing bid msg %s', msg['msgid'])
 | 
			
		||||
        now = int(time.time())
 | 
			
		||||
@ -3920,16 +3901,10 @@ class BasicSwap(BaseApp):
 | 
			
		||||
        self.log.info('Received valid bid %s for offer %s', bid_id.hex(), bid_data.offer_msg_id.hex())
 | 
			
		||||
        self.saveBid(bid_id, bid)
 | 
			
		||||
 | 
			
		||||
        # Auto accept bid if set and no other non-abandoned bid for this order exists
 | 
			
		||||
        if offer.auto_accept_bids:
 | 
			
		||||
            if self.countAcceptedBids(offer_id) > 0:
 | 
			
		||||
                self.log.info('Not auto accepting bid %s, already have', bid_id.hex())
 | 
			
		||||
            elif bid_data.amount != offer.amount_from:
 | 
			
		||||
                self.log.info('Not auto accepting bid %s, want exact amount match', bid_id.hex())
 | 
			
		||||
            else:
 | 
			
		||||
                delay = random.randrange(self.min_delay_event, self.max_delay_event)
 | 
			
		||||
                self.log.info('Auto accepting bid %s in %d seconds', bid_id.hex(), delay)
 | 
			
		||||
                self.createEvent(delay, EventTypes.ACCEPT_BID, bid_id)
 | 
			
		||||
        if self.shouldAutoAcceptBid(offer, bid):
 | 
			
		||||
            delay = random.randrange(self.min_delay_event, self.max_delay_event)
 | 
			
		||||
            self.log.info('Auto accepting bid %s in %d seconds', bid_id.hex(), delay)
 | 
			
		||||
            self.createEvent(delay, EventTypes.ACCEPT_BID, bid_id)
 | 
			
		||||
 | 
			
		||||
    def processBidAccept(self, msg):
 | 
			
		||||
        self.log.debug('Processing bid accepted msg %s', msg['msgid'])
 | 
			
		||||
@ -4046,17 +4021,11 @@ class BasicSwap(BaseApp):
 | 
			
		||||
 | 
			
		||||
        bid.setState(BidStates.BID_RECEIVED)
 | 
			
		||||
 | 
			
		||||
        # Auto accept bid if set and no other non-abandoned bid for this order exists
 | 
			
		||||
        if offer.auto_accept_bids:
 | 
			
		||||
            if self.countAcceptedBids(bid.offer_id) > 0:
 | 
			
		||||
                self.log.info('Not auto accepting bid %s, already have', bid.bid_id.hex())
 | 
			
		||||
            elif bid.amount != offer.amount_from:
 | 
			
		||||
                self.log.info('Not auto accepting bid %s, want exact amount match', bid.bid_id.hex())
 | 
			
		||||
            else:
 | 
			
		||||
                delay = random.randrange(self.min_delay_event, self.max_delay_event)
 | 
			
		||||
                self.log.info('Auto accepting xmr bid %s in %d seconds', bid.bid_id.hex(), delay)
 | 
			
		||||
                self.createEventInSession(delay, EventTypes.ACCEPT_XMR_BID, bid.bid_id, session)
 | 
			
		||||
                bid.setState(BidStates.SWAP_DELAYING)
 | 
			
		||||
        if self.shouldAutoAcceptBid(offer, bid, session):
 | 
			
		||||
            delay = random.randrange(self.min_delay_event, self.max_delay_event)
 | 
			
		||||
            self.log.info('Auto accepting xmr bid %s in %d seconds', bid.bid_id.hex(), delay)
 | 
			
		||||
            self.createEventInSession(delay, EventTypes.ACCEPT_XMR_BID, bid.bid_id, session)
 | 
			
		||||
            bid.setState(BidStates.SWAP_DELAYING)
 | 
			
		||||
 | 
			
		||||
        self.saveBidInSession(bid.bid_id, bid, session, xmr_swap)
 | 
			
		||||
 | 
			
		||||
@ -5492,6 +5461,46 @@ class BasicSwap(BaseApp):
 | 
			
		||||
            session.remove()
 | 
			
		||||
            self.mxDB.release()
 | 
			
		||||
 | 
			
		||||
    def listAutomationStrategies(self, filters={}):
 | 
			
		||||
        self.mxDB.acquire()
 | 
			
		||||
        try:
 | 
			
		||||
            rv = []
 | 
			
		||||
            session = scoped_session(self.session_factory)
 | 
			
		||||
 | 
			
		||||
            query_str = 'SELECT strats.record_id, strats.label, strats.type_ind FROM automationstrategies AS strats'
 | 
			
		||||
            query_str += ' WHERE strats.active_ind = 1 '
 | 
			
		||||
 | 
			
		||||
            sort_dir = filters.get('sort_dir', 'DESC').upper()
 | 
			
		||||
            sort_by = filters.get('sort_by', 'created_at')
 | 
			
		||||
            query_str += f' ORDER BY strats.{sort_by} {sort_dir}'
 | 
			
		||||
 | 
			
		||||
            limit = filters.get('limit', None)
 | 
			
		||||
            if limit is not None:
 | 
			
		||||
                query_str += f' LIMIT {limit}'
 | 
			
		||||
            offset = filters.get('offset', None)
 | 
			
		||||
            if offset is not None:
 | 
			
		||||
                query_str += f' OFFSET {offset}'
 | 
			
		||||
 | 
			
		||||
            q = session.execute(query_str)
 | 
			
		||||
            for row in q:
 | 
			
		||||
                rv.append(row)
 | 
			
		||||
            return rv
 | 
			
		||||
        finally:
 | 
			
		||||
            session.close()
 | 
			
		||||
            session.remove()
 | 
			
		||||
            self.mxDB.release()
 | 
			
		||||
 | 
			
		||||
    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:
 | 
			
		||||
            session.close()
 | 
			
		||||
            session.remove()
 | 
			
		||||
            self.mxDB.release()
 | 
			
		||||
 | 
			
		||||
    def newSMSGAddress(self, use_type=AddressTypes.RECV_OFFER, addressnote=None, session=None):
 | 
			
		||||
        now = int(time.time())
 | 
			
		||||
        use_session = None
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
 | 
			
		||||
# Copyright (c) 2019-2021 tecnovert
 | 
			
		||||
# Copyright (c) 2019-2022 tecnovert
 | 
			
		||||
# Distributed under the MIT software license, see the accompanying
 | 
			
		||||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
 | 
			
		||||
 | 
			
		||||
@ -12,7 +12,8 @@ from enum import IntEnum, auto
 | 
			
		||||
from sqlalchemy.ext.declarative import declarative_base
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
CURRENT_DB_VERSION = 13
 | 
			
		||||
CURRENT_DB_VERSION = 14
 | 
			
		||||
CURRENT_DB_DATA_VERSION = 1
 | 
			
		||||
Base = declarative_base()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -21,6 +22,14 @@ class TableTypes(IntEnum):
 | 
			
		||||
    BID = auto()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def strTableTypes(state):
 | 
			
		||||
    if state == TableTypes.OFFER:
 | 
			
		||||
        return 'Offer'
 | 
			
		||||
    if state == TableTypes.BID:
 | 
			
		||||
        return 'Bid'
 | 
			
		||||
    return 'Unknown'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DBKVInt(Base):
 | 
			
		||||
    __tablename__ = 'kv_int'
 | 
			
		||||
 | 
			
		||||
@ -372,6 +381,7 @@ class Wallets(Base):
 | 
			
		||||
    __tablename__ = 'wallets'
 | 
			
		||||
 | 
			
		||||
    record_id = sa.Column(sa.Integer, primary_key=True, autoincrement=True)
 | 
			
		||||
    active_ind = sa.Column(sa.Integer)
 | 
			
		||||
    coin_id = sa.Column(sa.Integer)
 | 
			
		||||
    wallet_name = sa.Column(sa.String)
 | 
			
		||||
    wallet_data = sa.Column(sa.String)
 | 
			
		||||
@ -385,6 +395,7 @@ class KnownIdentity(Base):
 | 
			
		||||
    __tablename__ = 'knownidentities'
 | 
			
		||||
 | 
			
		||||
    record_id = sa.Column(sa.Integer, primary_key=True, autoincrement=True)
 | 
			
		||||
    active_ind = sa.Column(sa.Integer)
 | 
			
		||||
    address = sa.Column(sa.String)
 | 
			
		||||
    label = sa.Column(sa.String)
 | 
			
		||||
    publickey = sa.Column(sa.LargeBinary)
 | 
			
		||||
@ -397,3 +408,51 @@ class KnownIdentity(Base):
 | 
			
		||||
    note = sa.Column(sa.String)
 | 
			
		||||
    updated_at = sa.Column(sa.BigInteger)
 | 
			
		||||
    created_at = sa.Column(sa.BigInteger)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AutomationStrategy(Base):
 | 
			
		||||
    __tablename__ = 'automationstrategies'
 | 
			
		||||
 | 
			
		||||
    record_id = sa.Column(sa.Integer, primary_key=True, autoincrement=True)
 | 
			
		||||
    active_ind = sa.Column(sa.Integer)
 | 
			
		||||
 | 
			
		||||
    label = sa.Column(sa.String)
 | 
			
		||||
    type_ind = sa.Column(sa.Integer)
 | 
			
		||||
    only_known_identities = sa.Column(sa.Integer)
 | 
			
		||||
    num_concurrent = sa.Column(sa.Integer)
 | 
			
		||||
    data = sa.Column(sa.LargeBinary)
 | 
			
		||||
 | 
			
		||||
    note = sa.Column(sa.String)
 | 
			
		||||
    created_at = sa.Column(sa.BigInteger)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AutomationLink(Base):
 | 
			
		||||
    __tablename__ = 'automationlinks'
 | 
			
		||||
    # Contains per order/bid options
 | 
			
		||||
 | 
			
		||||
    record_id = sa.Column(sa.Integer, primary_key=True, autoincrement=True)
 | 
			
		||||
    active_ind = sa.Column(sa.Integer)
 | 
			
		||||
 | 
			
		||||
    linked_type = sa.Column(sa.Integer)
 | 
			
		||||
    linked_id = sa.Column(sa.LargeBinary)
 | 
			
		||||
    strategy_id = sa.Column(sa.Integer)
 | 
			
		||||
 | 
			
		||||
    data = sa.Column(sa.LargeBinary)
 | 
			
		||||
    repeat_limit = sa.Column(sa.Integer)
 | 
			
		||||
    repeat_count = sa.Column(sa.Integer)
 | 
			
		||||
 | 
			
		||||
    note = sa.Column(sa.String)
 | 
			
		||||
    created_at = sa.Column(sa.BigInteger)
 | 
			
		||||
 | 
			
		||||
    __table_args__ = (sa.Index('linked_index', 'linked_type', 'linked_id'), )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class History(Base):
 | 
			
		||||
    __tablename__ = 'history'
 | 
			
		||||
 | 
			
		||||
    record_id = sa.Column(sa.Integer, primary_key=True, autoincrement=True)
 | 
			
		||||
    concept_type = sa.Column(sa.Integer)
 | 
			
		||||
    concept_id = sa.Column(sa.Integer)
 | 
			
		||||
 | 
			
		||||
    changed_data = sa.Column(sa.LargeBinary)
 | 
			
		||||
    created_at = sa.Column(sa.BigInteger)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										183
									
								
								basicswap/db_upgrades.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										183
									
								
								basicswap/db_upgrades.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,183 @@
 | 
			
		||||
# -*- 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 json
 | 
			
		||||
 | 
			
		||||
from sqlalchemy.orm import scoped_session
 | 
			
		||||
from .db import (
 | 
			
		||||
    TableTypes,
 | 
			
		||||
    AutomationStrategy,
 | 
			
		||||
    CURRENT_DB_VERSION,
 | 
			
		||||
    CURRENT_DB_DATA_VERSION)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def upgradeDatabaseData(self, data_version):
 | 
			
		||||
    if data_version >= CURRENT_DB_DATA_VERSION:
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    self.log.info('Upgrading database records from version %d to %d.', data_version, CURRENT_DB_DATA_VERSION)
 | 
			
		||||
    with self.mxDB:
 | 
			
		||||
        try:
 | 
			
		||||
            session = scoped_session(self.session_factory)
 | 
			
		||||
 | 
			
		||||
            if data_version < 1:
 | 
			
		||||
                session.add(AutomationStrategy(
 | 
			
		||||
                    active_ind=1,
 | 
			
		||||
                    label='Accept All',
 | 
			
		||||
                    type_ind=TableTypes.BID,
 | 
			
		||||
                    data=json.dumps({'full_amount_only': True,
 | 
			
		||||
                                     'max_bids': 1}).encode('utf-8'),
 | 
			
		||||
                    only_known_identities=False))
 | 
			
		||||
                session.add(AutomationStrategy(
 | 
			
		||||
                    active_ind=1,
 | 
			
		||||
                    label='Accept Known',
 | 
			
		||||
                    type_ind=TableTypes.BID,
 | 
			
		||||
                    data=json.dumps({'full_amount_only': True,
 | 
			
		||||
                                     'max_bids': 1}).encode('utf-8'),
 | 
			
		||||
                    only_known_identities=True,
 | 
			
		||||
                    note='Accept bids from identities with previously successful swaps only'))
 | 
			
		||||
 | 
			
		||||
            self.db_data_version = CURRENT_DB_DATA_VERSION
 | 
			
		||||
            self.setIntKVInSession('db_data_version', self.db_data_version, session)
 | 
			
		||||
            session.commit()
 | 
			
		||||
            self.log.info('Upgraded database records to version {}'.format(self.db_data_version))
 | 
			
		||||
        finally:
 | 
			
		||||
            session.close()
 | 
			
		||||
            session.remove()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def upgradeDatabase(self, db_version):
 | 
			
		||||
    if db_version >= CURRENT_DB_VERSION:
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    self.log.info('Upgrading database from version %d to %d.', db_version, CURRENT_DB_VERSION)
 | 
			
		||||
 | 
			
		||||
    while True:
 | 
			
		||||
        session = scoped_session(self.session_factory)
 | 
			
		||||
 | 
			
		||||
        current_version = db_version
 | 
			
		||||
        if current_version == 6:
 | 
			
		||||
            session.execute('ALTER TABLE bids ADD COLUMN security_token BLOB')
 | 
			
		||||
            session.execute('ALTER TABLE offers ADD COLUMN security_token BLOB')
 | 
			
		||||
            db_version += 1
 | 
			
		||||
        elif current_version == 7:
 | 
			
		||||
            session.execute('ALTER TABLE transactions ADD COLUMN block_hash BLOB')
 | 
			
		||||
            session.execute('ALTER TABLE transactions ADD COLUMN block_height INTEGER')
 | 
			
		||||
            session.execute('ALTER TABLE transactions ADD COLUMN block_time INTEGER')
 | 
			
		||||
            db_version += 1
 | 
			
		||||
        elif current_version == 8:
 | 
			
		||||
            session.execute('''
 | 
			
		||||
                CREATE TABLE wallets (
 | 
			
		||||
                    record_id INTEGER NOT NULL,
 | 
			
		||||
                    coin_id INTEGER,
 | 
			
		||||
                    wallet_name VARCHAR,
 | 
			
		||||
                    balance_type INTEGER,
 | 
			
		||||
                    amount BIGINT,
 | 
			
		||||
                    updated_at BIGINT,
 | 
			
		||||
                    created_at BIGINT,
 | 
			
		||||
                    PRIMARY KEY (record_id))''')
 | 
			
		||||
            db_version += 1
 | 
			
		||||
        elif current_version == 9:
 | 
			
		||||
            session.execute('ALTER TABLE wallets ADD COLUMN wallet_data VARCHAR')
 | 
			
		||||
            db_version += 1
 | 
			
		||||
        elif current_version == 10:
 | 
			
		||||
            session.execute('ALTER TABLE smsgaddresses ADD COLUMN active_ind INTEGER')
 | 
			
		||||
            session.execute('ALTER TABLE smsgaddresses ADD COLUMN created_at INTEGER')
 | 
			
		||||
            session.execute('ALTER TABLE smsgaddresses ADD COLUMN note VARCHAR')
 | 
			
		||||
            session.execute('ALTER TABLE smsgaddresses ADD COLUMN pubkey VARCHAR')
 | 
			
		||||
            session.execute('UPDATE smsgaddresses SET active_ind = 1, created_at = 1')
 | 
			
		||||
 | 
			
		||||
            session.execute('ALTER TABLE offers ADD COLUMN addr_to VARCHAR')
 | 
			
		||||
            session.execute(f'UPDATE offers SET addr_to = "{self.network_addr}"')
 | 
			
		||||
            db_version += 1
 | 
			
		||||
        elif current_version == 11:
 | 
			
		||||
            session.execute('ALTER TABLE bids ADD COLUMN chain_a_height_start INTEGER')
 | 
			
		||||
            session.execute('ALTER TABLE bids ADD COLUMN chain_b_height_start INTEGER')
 | 
			
		||||
            session.execute('ALTER TABLE bids ADD COLUMN protocol_version INTEGER')
 | 
			
		||||
            session.execute('ALTER TABLE offers ADD COLUMN protocol_version INTEGER')
 | 
			
		||||
            session.execute('ALTER TABLE transactions ADD COLUMN tx_data BLOB')
 | 
			
		||||
            db_version += 1
 | 
			
		||||
        elif current_version == 12:
 | 
			
		||||
            session.execute('''
 | 
			
		||||
                CREATE TABLE knownidentities (
 | 
			
		||||
                    record_id INTEGER NOT NULL,
 | 
			
		||||
                    address VARCHAR,
 | 
			
		||||
                    label VARCHAR,
 | 
			
		||||
                    publickey BLOB,
 | 
			
		||||
                    num_sent_bids_successful INTEGER,
 | 
			
		||||
                    num_recv_bids_successful INTEGER,
 | 
			
		||||
                    num_sent_bids_rejected INTEGER,
 | 
			
		||||
                    num_recv_bids_rejected INTEGER,
 | 
			
		||||
                    num_sent_bids_failed INTEGER,
 | 
			
		||||
                    num_recv_bids_failed INTEGER,
 | 
			
		||||
                    note VARCHAR,
 | 
			
		||||
                    updated_at BIGINT,
 | 
			
		||||
                    created_at BIGINT,
 | 
			
		||||
                    PRIMARY KEY (record_id))''')
 | 
			
		||||
            session.execute('ALTER TABLE bids ADD COLUMN reject_code INTEGER')
 | 
			
		||||
            session.execute('ALTER TABLE bids ADD COLUMN rate INTEGER')
 | 
			
		||||
            session.execute('ALTER TABLE offers ADD COLUMN amount_negotiable INTEGER')
 | 
			
		||||
            session.execute('ALTER TABLE offers ADD COLUMN rate_negotiable INTEGER')
 | 
			
		||||
            db_version += 1
 | 
			
		||||
        elif current_version == 13:
 | 
			
		||||
            db_version += 1
 | 
			
		||||
            session.execute('''
 | 
			
		||||
                CREATE TABLE automationstrategies (
 | 
			
		||||
                    record_id INTEGER NOT NULL,
 | 
			
		||||
                    active_ind INTEGER,
 | 
			
		||||
                    label VARCHAR,
 | 
			
		||||
                    type_ind INTEGER,
 | 
			
		||||
                    only_known_identities INTEGER,
 | 
			
		||||
                    num_concurrent INTEGER,
 | 
			
		||||
                    data BLOB,
 | 
			
		||||
 | 
			
		||||
                    note VARCHAR,
 | 
			
		||||
                    created_at BIGINT,
 | 
			
		||||
                    PRIMARY KEY (record_id))''')
 | 
			
		||||
 | 
			
		||||
            session.execute('''
 | 
			
		||||
                CREATE TABLE automationlinks (
 | 
			
		||||
                    record_id INTEGER NOT NULL,
 | 
			
		||||
                    active_ind INTEGER,
 | 
			
		||||
 | 
			
		||||
                    linked_type INTEGER,
 | 
			
		||||
                    linked_id BLOB,
 | 
			
		||||
                    strategy_id INTEGER,
 | 
			
		||||
 | 
			
		||||
                    data BLOB,
 | 
			
		||||
                    repeat_limit INTEGER,
 | 
			
		||||
                    repeat_count INTEGER,
 | 
			
		||||
 | 
			
		||||
                    note VARCHAR,
 | 
			
		||||
                    created_at BIGINT,
 | 
			
		||||
                    PRIMARY KEY (record_id))''')
 | 
			
		||||
 | 
			
		||||
            session.execute('''
 | 
			
		||||
                CREATE TABLE history (
 | 
			
		||||
                    record_id INTEGER NOT NULL,
 | 
			
		||||
                    concept_type INTEGER,
 | 
			
		||||
                    concept_id INTEGER,
 | 
			
		||||
                    changed_data BLOB,
 | 
			
		||||
 | 
			
		||||
                    note VARCHAR,
 | 
			
		||||
                    created_at BIGINT,
 | 
			
		||||
                    PRIMARY KEY (record_id))''')
 | 
			
		||||
 | 
			
		||||
            session.execute('ALTER TABLE wallets ADD COLUMN active_ind INTEGER')
 | 
			
		||||
            session.execute('ALTER TABLE knownidentities ADD COLUMN active_ind INTEGER')
 | 
			
		||||
 | 
			
		||||
        if current_version != db_version:
 | 
			
		||||
            self.db_version = db_version
 | 
			
		||||
            self.setIntKVInSession('db_version', db_version, session)
 | 
			
		||||
            session.commit()
 | 
			
		||||
            session.close()
 | 
			
		||||
            session.remove()
 | 
			
		||||
            self.log.info('Upgraded database to version {}'.format(self.db_version))
 | 
			
		||||
            continue
 | 
			
		||||
        break
 | 
			
		||||
 | 
			
		||||
    if db_version != CURRENT_DB_VERSION:
 | 
			
		||||
        raise ValueError('Unable to upgrade database.')
 | 
			
		||||
@ -59,9 +59,15 @@ from .ui.util import (
 | 
			
		||||
    have_data_entry,
 | 
			
		||||
    get_data_entry_or,
 | 
			
		||||
    listAvailableCoins,
 | 
			
		||||
    set_pagination_filters,
 | 
			
		||||
)
 | 
			
		||||
from .ui.page_tor import page_tor
 | 
			
		||||
from .ui.page_offers import page_offers
 | 
			
		||||
from .ui.page_automation import (
 | 
			
		||||
    page_automation_strategies,
 | 
			
		||||
    page_automation_strategy,
 | 
			
		||||
    page_automation_strategy_new
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
env = Environment(loader=PackageLoader('basicswap', 'templates'))
 | 
			
		||||
@ -1155,15 +1161,7 @@ class HttpHandler(BaseHTTPRequestHandler):
 | 
			
		||||
                ensure(sort_dir in ['asc', 'desc'], 'Invalid sort dir')
 | 
			
		||||
                filters['sort_dir'] = sort_dir
 | 
			
		||||
 | 
			
		||||
        if form_data and have_data_entry(form_data, 'pageback'):
 | 
			
		||||
            filters['page_no'] = int(form_data[b'pageno'][0]) - 1
 | 
			
		||||
            if filters['page_no'] < 1:
 | 
			
		||||
                filters['page_no'] = 1
 | 
			
		||||
        elif form_data and have_data_entry(form_data, 'pageforwards'):
 | 
			
		||||
            filters['page_no'] = int(form_data[b'pageno'][0]) + 1
 | 
			
		||||
 | 
			
		||||
        if filters['page_no'] > 1:
 | 
			
		||||
            filters['offset'] = (filters['page_no'] - 1) * PAGE_LIMIT
 | 
			
		||||
        set_pagination_filters(form_data, filters)
 | 
			
		||||
 | 
			
		||||
        bids = swap_client.listBids(sent=sent, filters=filters)
 | 
			
		||||
 | 
			
		||||
@ -1437,6 +1435,12 @@ class HttpHandler(BaseHTTPRequestHandler):
 | 
			
		||||
                    return self.page_identity(url_split, post_string)
 | 
			
		||||
                if url_split[1] == 'tor':
 | 
			
		||||
                    return page_tor(self, url_split, post_string)
 | 
			
		||||
                if url_split[1] == 'automation':
 | 
			
		||||
                    return page_automation_strategies(self, url_split, post_string)
 | 
			
		||||
                if url_split[1] == 'automationstrategy':
 | 
			
		||||
                    return page_automation_strategy(self, url_split, post_string)
 | 
			
		||||
                if url_split[1] == 'newautomationstrategy':
 | 
			
		||||
                    return page_automation_strategy_new(self, url_split, post_string)
 | 
			
		||||
                if url_split[1] == 'shutdown':
 | 
			
		||||
                    return self.page_shutdown(url_split, post_string)
 | 
			
		||||
            return self.page_index(url_split)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										38
									
								
								basicswap/templates/automation_strategies.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								basicswap/templates/automation_strategies.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,38 @@
 | 
			
		||||
{% include 'header.html' %}
 | 
			
		||||
 | 
			
		||||
<h3>Automation Strategies</h3>
 | 
			
		||||
{% for m in messages %}
 | 
			
		||||
<p>{{ m }}</p>
 | 
			
		||||
{% endfor %}
 | 
			
		||||
 | 
			
		||||
<form method="post">
 | 
			
		||||
<table>
 | 
			
		||||
 | 
			
		||||
<tr><td>Sort By</td><td>
 | 
			
		||||
<select name="sort_by">
 | 
			
		||||
<option value="created_at"{% if filters.sort_by=='created_at' %} selected{% endif %}>Created At</option>
 | 
			
		||||
</select>
 | 
			
		||||
<select name="sort_dir">
 | 
			
		||||
<option value="asc"{% if filters.sort_dir=='asc' %} selected{% endif %}>Ascending</option>
 | 
			
		||||
<option value="desc"{% if filters.sort_dir=='desc' %} selected{% endif %}>Descending</option>
 | 
			
		||||
</select>
 | 
			
		||||
</td></tr>
 | 
			
		||||
 | 
			
		||||
<tr><td><input type="submit" name='applyfilters' value="Apply Filters"></td><td><input type="submit" name='clearfilters' value="Clear Filters"></td></tr>
 | 
			
		||||
<tr><td><input type="submit" name='pageback' value="Page Back"></td><td>Page: {{ filters.page_no }}</td><td><input type="submit" name='pageforwards' value="Page Forwards"></td></tr>
 | 
			
		||||
</table>
 | 
			
		||||
<input type="hidden" name="formid" value="{{ form_id }}">
 | 
			
		||||
<input type="hidden" name="pageno" value="{{ filters.page_no }}">
 | 
			
		||||
</form>
 | 
			
		||||
 | 
			
		||||
<p><a href="/newautomationstrategy">Create New Strategy</a></p>
 | 
			
		||||
 | 
			
		||||
<table>
 | 
			
		||||
<tr><th>Name</th><th>Type</th></tr>
 | 
			
		||||
{% for s in strategies %}
 | 
			
		||||
<tr><td><a class="monospace" href=/automationstrategy/{{ s[0] }}>{{ s[1] }}</td><td>{{ s[2] }}</td></tr>
 | 
			
		||||
{% endfor %}
 | 
			
		||||
</table>
 | 
			
		||||
 | 
			
		||||
<p><a href="/">home</a></p>
 | 
			
		||||
</body></html>
 | 
			
		||||
							
								
								
									
										27
									
								
								basicswap/templates/automation_strategy.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								basicswap/templates/automation_strategy.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
			
		||||
{% include 'header.html' %}
 | 
			
		||||
 | 
			
		||||
<h3>Automation Strategy {{ strategy_id }}</h3>
 | 
			
		||||
 | 
			
		||||
{% for m in messages %}
 | 
			
		||||
<p>{{ m }}</p>
 | 
			
		||||
{% endfor %}
 | 
			
		||||
 | 
			
		||||
<table>
 | 
			
		||||
<tr><td>Label</td><td>{{ strategy.label }}</td></tr>
 | 
			
		||||
<tr><td>Type</td><td>{{ strategy.type }}</td></tr>
 | 
			
		||||
<tr><td>Only known identities</td><td>{{ strategy.only_known_identities }}</td></tr>
 | 
			
		||||
 | 
			
		||||
<tr><td>Data</td><td>
 | 
			
		||||
<textarea class="monospace" rows="10" cols="150" readonly>
 | 
			
		||||
{{ strategy.data }}
 | 
			
		||||
</textarea>
 | 
			
		||||
<tr><td>Notes</td><td>
 | 
			
		||||
<textarea rows="10" cols="150" readonly>
 | 
			
		||||
{{ strategy.note }}
 | 
			
		||||
</textarea>
 | 
			
		||||
</td></tr>
 | 
			
		||||
</table>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<p><a href="/">home</a></p>
 | 
			
		||||
</body></html>
 | 
			
		||||
							
								
								
									
										11
									
								
								basicswap/templates/automation_strategy_new.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								basicswap/templates/automation_strategy_new.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
			
		||||
{% include 'header.html' %}
 | 
			
		||||
 | 
			
		||||
<h3>New Automation Strategy</h3>
 | 
			
		||||
{% for m in messages %}
 | 
			
		||||
<p>{{ m }}</p>
 | 
			
		||||
{% endfor %}
 | 
			
		||||
 | 
			
		||||
<p>TODO</p>
 | 
			
		||||
 | 
			
		||||
<p><a href="/">home</a></p>
 | 
			
		||||
</body></html>
 | 
			
		||||
@ -19,6 +19,7 @@ Version: {{ version }}
 | 
			
		||||
<a href="/bids">Received Bids: {{ summary.num_recv_bids }}</a><br/>
 | 
			
		||||
<a href="/sentbids">Sent Bids: {{ summary.num_sent_bids }}</a><br/>
 | 
			
		||||
<a href="/watched">Watched Outputs: {{ summary.num_watched_outputs }}</a><br/>
 | 
			
		||||
<a href="/automation">Automation Strategies</a><br/>
 | 
			
		||||
{% if use_tor_proxy %} <a href="/tor">TOR Information</a><br/> {% endif %}
 | 
			
		||||
</p>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										110
									
								
								basicswap/ui/page_automation.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								basicswap/ui/page_automation.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,110 @@
 | 
			
		||||
# -*- 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
 | 
			
		||||
 | 
			
		||||
from .util import (
 | 
			
		||||
    PAGE_LIMIT,
 | 
			
		||||
    get_data_entry,
 | 
			
		||||
    have_data_entry,
 | 
			
		||||
    set_pagination_filters,
 | 
			
		||||
)
 | 
			
		||||
from basicswap.util import (
 | 
			
		||||
    ensure,
 | 
			
		||||
)
 | 
			
		||||
from basicswap.db import (
 | 
			
		||||
    strTableTypes,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def page_automation_strategies(self, url_split, post_string):
 | 
			
		||||
    server = self.server
 | 
			
		||||
    swap_client = server.swap_client
 | 
			
		||||
 | 
			
		||||
    filters = {
 | 
			
		||||
        'page_no': 1,
 | 
			
		||||
        'limit': PAGE_LIMIT,
 | 
			
		||||
        'sort_by': 'created_at',
 | 
			
		||||
        'sort_dir': 'desc',
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    messages = []
 | 
			
		||||
    form_data = self.checkForm(post_string, 'automationstrategies', messages)
 | 
			
		||||
 | 
			
		||||
    if form_data and have_data_entry(form_data, 'applyfilters'):
 | 
			
		||||
        if have_data_entry(form_data, 'sort_by'):
 | 
			
		||||
            sort_by = get_data_entry(form_data, 'sort_by')
 | 
			
		||||
            ensure(sort_by in ['created_at', 'rate'], 'Invalid sort by')
 | 
			
		||||
            filters['sort_by'] = sort_by
 | 
			
		||||
        if have_data_entry(form_data, 'sort_dir'):
 | 
			
		||||
            sort_dir = get_data_entry(form_data, 'sort_dir')
 | 
			
		||||
            ensure(sort_dir in ['asc', 'desc'], 'Invalid sort dir')
 | 
			
		||||
            filters['sort_dir'] = sort_dir
 | 
			
		||||
 | 
			
		||||
    set_pagination_filters(form_data, filters)
 | 
			
		||||
 | 
			
		||||
    formatted_strategies = []
 | 
			
		||||
    for s in swap_client.listAutomationStrategies(filters):
 | 
			
		||||
        formatted_strategies.append((s[0], s[1], strTableTypes(s[2])))
 | 
			
		||||
 | 
			
		||||
    template = server.env.get_template('automation_strategies.html')
 | 
			
		||||
    return bytes(template.render(
 | 
			
		||||
        title=server.title,
 | 
			
		||||
        h2=server.title,
 | 
			
		||||
        messages=messages,
 | 
			
		||||
        filters=filters,
 | 
			
		||||
        strategies=formatted_strategies,
 | 
			
		||||
        form_id=os.urandom(8).hex(),
 | 
			
		||||
    ), 'UTF-8')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def page_automation_strategy_new(self, url_split, post_string):
 | 
			
		||||
    server = self.server
 | 
			
		||||
    swap_client = self.server.swap_client
 | 
			
		||||
 | 
			
		||||
    messages = []
 | 
			
		||||
    form_data = self.checkForm(post_string, 'automationstrategynew', messages)
 | 
			
		||||
 | 
			
		||||
    template = server.env.get_template('automation_strategy_new.html')
 | 
			
		||||
    return bytes(template.render(
 | 
			
		||||
        title=server.title,
 | 
			
		||||
        h2=server.title,
 | 
			
		||||
        messages=messages,
 | 
			
		||||
        form_id=os.urandom(8).hex(),
 | 
			
		||||
    ), 'UTF-8')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def page_automation_strategy(self, url_split, post_string):
 | 
			
		||||
    ensure(len(url_split) > 2, 'Strategy ID not specified')
 | 
			
		||||
    try:
 | 
			
		||||
        strategy_id = int(url_split[2])
 | 
			
		||||
    except Exception:
 | 
			
		||||
        raise ValueError('Bad strategy ID')
 | 
			
		||||
 | 
			
		||||
    server = self.server
 | 
			
		||||
    swap_client = self.server.swap_client
 | 
			
		||||
 | 
			
		||||
    messages = []
 | 
			
		||||
 | 
			
		||||
    strategy = swap_client.getAutomationStrategy(strategy_id)
 | 
			
		||||
 | 
			
		||||
    formatted_strategy = {
 | 
			
		||||
        'label': strategy.label,
 | 
			
		||||
        'type': strTableTypes(strategy.type_ind),
 | 
			
		||||
        'only_known_identities': 'True' if strategy.only_known_identities is True else 'False',
 | 
			
		||||
        'data': strategy.data,
 | 
			
		||||
        'note': strategy.note,
 | 
			
		||||
        'created_at': strategy.created_at,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template = server.env.get_template('automation_strategy.html')
 | 
			
		||||
    return bytes(template.render(
 | 
			
		||||
        title=server.title,
 | 
			
		||||
        h2=server.title,
 | 
			
		||||
        messages=messages,
 | 
			
		||||
        strategy=formatted_strategy,
 | 
			
		||||
        form_id=os.urandom(8).hex(),
 | 
			
		||||
    ), 'UTF-8')
 | 
			
		||||
@ -12,6 +12,7 @@ from .util import (
 | 
			
		||||
    get_data_entry,
 | 
			
		||||
    have_data_entry,
 | 
			
		||||
    listAvailableCoins,
 | 
			
		||||
    set_pagination_filters,
 | 
			
		||||
)
 | 
			
		||||
from basicswap.util import (
 | 
			
		||||
    ensure,
 | 
			
		||||
@ -23,7 +24,8 @@ from basicswap.chainparams import (
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def page_offers(self, url_split, post_string, sent=False):
 | 
			
		||||
    swap_client = self.server.swap_client
 | 
			
		||||
    server = self.server
 | 
			
		||||
    swap_client = server.swap_client
 | 
			
		||||
 | 
			
		||||
    filters = {
 | 
			
		||||
        'coin_from': -1,
 | 
			
		||||
@ -53,15 +55,7 @@ def page_offers(self, url_split, post_string, sent=False):
 | 
			
		||||
            ensure(sent_from in ['any', 'only'], 'Invalid sent filter')
 | 
			
		||||
            filters['sent_from'] = sent_from
 | 
			
		||||
 | 
			
		||||
    if form_data and have_data_entry(form_data, 'pageback'):
 | 
			
		||||
        filters['page_no'] = int(form_data[b'pageno'][0]) - 1
 | 
			
		||||
        if filters['page_no'] < 1:
 | 
			
		||||
            filters['page_no'] = 1
 | 
			
		||||
    elif form_data and have_data_entry(form_data, 'pageforwards'):
 | 
			
		||||
        filters['page_no'] = int(form_data[b'pageno'][0]) + 1
 | 
			
		||||
 | 
			
		||||
    if filters['page_no'] > 1:
 | 
			
		||||
        filters['offset'] = (filters['page_no'] - 1) * PAGE_LIMIT
 | 
			
		||||
    set_pagination_filters(form_data, filters)
 | 
			
		||||
 | 
			
		||||
    if filters['sent_from'] == 'only':
 | 
			
		||||
        sent = True
 | 
			
		||||
@ -84,10 +78,10 @@ def page_offers(self, url_split, post_string, sent=False):
 | 
			
		||||
            o.addr_from,
 | 
			
		||||
            o.was_sent))
 | 
			
		||||
 | 
			
		||||
    template = self.server.env.get_template('offers.html')
 | 
			
		||||
    template = server.env.get_template('offers.html')
 | 
			
		||||
    return bytes(template.render(
 | 
			
		||||
        title=self.server.title,
 | 
			
		||||
        h2=self.server.title,
 | 
			
		||||
        title=server.title,
 | 
			
		||||
        h2=server.title,
 | 
			
		||||
        coins=listAvailableCoins(swap_client),
 | 
			
		||||
        messages=messages,
 | 
			
		||||
        filters=filters,
 | 
			
		||||
 | 
			
		||||
@ -96,6 +96,17 @@ def setCoinFilter(form_data, field_name):
 | 
			
		||||
        raise ValueError('Unknown Coin Type {}'.format(str(field_name)))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def set_pagination_filters(form_data, filters):
 | 
			
		||||
    if form_data and have_data_entry(form_data, 'pageback'):
 | 
			
		||||
        filters['page_no'] = int(form_data[b'pageno'][0]) - 1
 | 
			
		||||
        if filters['page_no'] < 1:
 | 
			
		||||
            filters['page_no'] = 1
 | 
			
		||||
    elif form_data and have_data_entry(form_data, 'pageforwards'):
 | 
			
		||||
        filters['page_no'] = int(form_data[b'pageno'][0]) + 1
 | 
			
		||||
    if filters['page_no'] > 1:
 | 
			
		||||
        filters['offset'] = (filters['page_no'] - 1) * PAGE_LIMIT
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def getTxIdHex(bid, tx_type, suffix):
 | 
			
		||||
    if tx_type == TxTypes.ITX:
 | 
			
		||||
        obj = bid.initiate_tx
 | 
			
		||||
 | 
			
		||||
@ -13,6 +13,11 @@ Docker must be installed and started:
 | 
			
		||||
Should return a line containing `Docker version`...
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
It's recommended to setup docker to work without sudo:
 | 
			
		||||
 | 
			
		||||
    https://docs.docker.com/engine/install/linux-postinstall/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#### Create the images:
 | 
			
		||||
 | 
			
		||||
    $ cd basicswap/docker
 | 
			
		||||
 | 
			
		||||
@ -9,7 +9,7 @@
 | 
			
		||||
export RESET_TEST=true
 | 
			
		||||
export TEST_PATH=/tmp/test_persistent
 | 
			
		||||
mkdir -p ${TEST_PATH}/bin/{particl,monero,bitcoin}
 | 
			
		||||
cp ~/tmp/particl-0.21.2.8-x86_64-linux-gnu.tar.gz ${TEST_PATH}/bin/particl
 | 
			
		||||
cp ~/tmp/particl-0.21.2.9-x86_64-linux-gnu.tar.gz ${TEST_PATH}/bin/particl
 | 
			
		||||
cp ~/tmp/bitcoin-0.21.1-x86_64-linux-gnu.tar.gz ${TEST_PATH}/bin/bitcoin
 | 
			
		||||
cp ~/tmp/monero-linux-x64-v0.17.3.0.tar.bz2 ${TEST_PATH}/bin/monero/monero-0.17.3.0-x86_64-linux-gnu.tar.bz2
 | 
			
		||||
export PYTHONPATH=$(pwd)
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user