mirror of
https://github.com/basicswap/basicswap.git
synced 2025-01-30 22:35:53 +00:00
Add automation override option.
This commit is contained in:
parent
3241616d68
commit
ac16fc07a4
11 changed files with 233 additions and 87 deletions
|
@ -52,6 +52,7 @@ from .util import (
|
|||
format_amount,
|
||||
format_timestamp,
|
||||
DeserialiseNum,
|
||||
zeroIfNone,
|
||||
make_int,
|
||||
ensure,
|
||||
)
|
||||
|
@ -143,6 +144,8 @@ from .basicswap_util import (
|
|||
getLastBidState,
|
||||
isActiveBidState,
|
||||
NotificationTypes as NT,
|
||||
AutomationOverrideOptions,
|
||||
VisibilityOverrideOptions,
|
||||
)
|
||||
|
||||
|
||||
|
@ -157,12 +160,6 @@ def validOfferStateToReceiveBid(offer_state):
|
|||
return False
|
||||
|
||||
|
||||
def zeroIfNone(value):
|
||||
if value is None:
|
||||
return 0
|
||||
return value
|
||||
|
||||
|
||||
def threadPollXMRChainState(swap_client, coin_type):
|
||||
ci = swap_client.ci(coin_type)
|
||||
cc = swap_client.coin_clients[coin_type]
|
||||
|
@ -1189,17 +1186,57 @@ class BasicSwap(BaseApp):
|
|||
try:
|
||||
now = int(time.time())
|
||||
session = self.openSession()
|
||||
q = session.execute(f'SELECT COUNT(*) FROM knownidentities WHERE address = "{address}"').first()
|
||||
q = session.execute('SELECT COUNT(*) FROM knownidentities WHERE address = :address', {'address': address}).first()
|
||||
if q[0] < 1:
|
||||
q = session.execute(f'INSERT INTO knownidentities (active_ind, address, created_at) VALUES (1, "{address}", {now})')
|
||||
session.execute('INSERT INTO knownidentities (active_ind, address, created_at) VALUES (1, :address, :now)', {'address': address, 'now': now})
|
||||
|
||||
values = []
|
||||
pattern = ''
|
||||
if 'label' in data:
|
||||
pattern += (', ' if pattern != '' else '')
|
||||
pattern += 'label = "{}"'.format(data['label'])
|
||||
values.append(address)
|
||||
q = session.execute(f'UPDATE knownidentities SET {pattern} WHERE address = "{address}"')
|
||||
session.execute('UPDATE knownidentities SET label = :label WHERE address = :address', {'address': address, 'label': data['label']})
|
||||
|
||||
if 'automation_override' in data:
|
||||
new_value: int = 0
|
||||
data_value = data['automation_override']
|
||||
if isinstance(data_value, int):
|
||||
new_value = data_value
|
||||
elif isinstance(data_value, str):
|
||||
if data_value.isdigit():
|
||||
new_value = int(data_value)
|
||||
elif data_value == 'default':
|
||||
new_value = 0
|
||||
elif data_value == 'always_accept':
|
||||
new_value = int(AutomationOverrideOptions.ALWAYS_ACCEPT)
|
||||
elif data_value == 'never_accept':
|
||||
new_value = int(AutomationOverrideOptions.NEVER_ACCEPT)
|
||||
else:
|
||||
raise ValueError('Unknown automation_override value')
|
||||
else:
|
||||
raise ValueError('Unknown automation_override type')
|
||||
|
||||
session.execute('UPDATE knownidentities SET automation_override = :new_value WHERE address = :address', {'address': address, 'new_value': new_value})
|
||||
|
||||
if 'visibility_override' in data:
|
||||
new_value: int = 0
|
||||
data_value = data['visibility_override']
|
||||
if isinstance(data_value, int):
|
||||
new_value = data_value
|
||||
elif isinstance(data_value, str):
|
||||
if data_value.isdigit():
|
||||
new_value = int(data_value)
|
||||
elif data_value == 'default':
|
||||
new_value = 0
|
||||
elif data_value == 'hide':
|
||||
new_value = int(VisibilityOverrideOptions.HIDE)
|
||||
elif data_value == 'block':
|
||||
new_value = int(VisibilityOverrideOptions.BLOCK)
|
||||
else:
|
||||
raise ValueError('Unknown visibility_override value')
|
||||
else:
|
||||
raise ValueError('Unknown visibility_override type')
|
||||
|
||||
session.execute('UPDATE knownidentities SET visibility_override = :new_value WHERE address = :address', {'address': address, 'new_value': new_value})
|
||||
|
||||
if 'note' in data:
|
||||
session.execute('UPDATE knownidentities SET note = :note WHERE address = :address', {'address': address, 'note': data['note']})
|
||||
|
||||
finally:
|
||||
self.closeSession(session)
|
||||
|
@ -1209,7 +1246,8 @@ class BasicSwap(BaseApp):
|
|||
session = self.openSession()
|
||||
|
||||
query_str = 'SELECT address, label, num_sent_bids_successful, num_recv_bids_successful, ' + \
|
||||
' num_sent_bids_rejected, num_recv_bids_rejected, num_sent_bids_failed, num_recv_bids_failed ' + \
|
||||
' num_sent_bids_rejected, num_recv_bids_rejected, num_sent_bids_failed, num_recv_bids_failed, ' + \
|
||||
' automation_override, visibility_override, note ' + \
|
||||
' FROM knownidentities ' + \
|
||||
' WHERE active_ind = 1 '
|
||||
|
||||
|
@ -1240,6 +1278,9 @@ class BasicSwap(BaseApp):
|
|||
'num_recv_bids_rejected': zeroIfNone(row[5]),
|
||||
'num_sent_bids_failed': zeroIfNone(row[6]),
|
||||
'num_recv_bids_failed': zeroIfNone(row[7]),
|
||||
'automation_override': zeroIfNone(row[8]),
|
||||
'visibility_override': zeroIfNone(row[9]),
|
||||
'note': row[10],
|
||||
}
|
||||
rv.append(identity)
|
||||
return rv
|
||||
|
@ -2186,22 +2227,6 @@ class BasicSwap(BaseApp):
|
|||
session.remove()
|
||||
self.mxDB.release()
|
||||
|
||||
def updateIdentity(self, address, label):
|
||||
self.mxDB.acquire()
|
||||
try:
|
||||
session = scoped_session(self.session_factory)
|
||||
identity = session.query(KnownIdentity).filter_by(address=address).first()
|
||||
if identity is None:
|
||||
identity = KnownIdentity(active_ind=1, address=address)
|
||||
identity.label = label
|
||||
identity.updated_at = int(time.time())
|
||||
session.add(identity)
|
||||
session.commit()
|
||||
finally:
|
||||
session.close()
|
||||
session.remove()
|
||||
self.mxDB.release()
|
||||
|
||||
def list_bid_events(self, bid_id, session):
|
||||
query_str = 'SELECT created_at, event_type, event_msg FROM eventlog ' + \
|
||||
'WHERE active_ind = 1 AND linked_type = {} AND linked_id = x\'{}\' '.format(Concepts.BID, bid_id.hex())
|
||||
|
@ -4158,6 +4183,24 @@ class BasicSwap(BaseApp):
|
|||
total_value += amount
|
||||
return bids, total_value
|
||||
|
||||
def evaluateKnownIdentityForAutoAccept(self, strategy, identity_stats) -> bool:
|
||||
if identity_stats:
|
||||
if identity_stats.automation_override == AutomationOverrideOptions.NEVER_ACCEPT:
|
||||
raise AutomationConstraint('From address is marked never accept')
|
||||
if identity_stats.automation_override == AutomationOverrideOptions.ALWAYS_ACCEPT:
|
||||
return True
|
||||
|
||||
if strategy.only_known_identities:
|
||||
if not identity_stats:
|
||||
raise AutomationConstraint('Unknown bidder')
|
||||
|
||||
# TODO: More options
|
||||
if identity_stats.num_recv_bids_successful < 1:
|
||||
raise AutomationConstraint('Bidder has too few successful swaps')
|
||||
if identity_stats.num_recv_bids_successful <= identity_stats.num_recv_bids_failed:
|
||||
raise AutomationConstraint('Bidder has too many failed swaps')
|
||||
return True
|
||||
|
||||
def shouldAutoAcceptBid(self, offer, bid, session=None):
|
||||
try:
|
||||
use_session = self.openSession(session)
|
||||
|
@ -4195,16 +4238,8 @@ class BasicSwap(BaseApp):
|
|||
if num_not_completed >= max_concurrent_bids:
|
||||
raise AutomationConstraint('Already have {} bids to complete'.format(num_not_completed))
|
||||
|
||||
if strategy.only_known_identities:
|
||||
identity_stats = use_session.query(KnownIdentity).filter_by(address=bid.bid_addr).first()
|
||||
if not identity_stats:
|
||||
raise AutomationConstraint('Unknown bidder')
|
||||
|
||||
# TODO: More options
|
||||
if identity_stats.num_recv_bids_successful < 1:
|
||||
raise AutomationConstraint('Bidder has too few successful swaps')
|
||||
if identity_stats.num_recv_bids_successful <= identity_stats.num_recv_bids_failed:
|
||||
raise AutomationConstraint('Bidder has too many failed swaps')
|
||||
identity_stats = use_session.query(KnownIdentity).filter_by(address=bid.bid_addr).first()
|
||||
self.evaluateKnownIdentityForAutoAccept(strategy, identity_stats)
|
||||
|
||||
self.logEvent(Concepts.BID,
|
||||
bid.bid_id,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2021-2022 tecnovert
|
||||
# Copyright (c) 2021-2023 tecnovert
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
|
@ -192,6 +192,45 @@ class DebugTypes(IntEnum):
|
|||
B_LOCK_TX_MISSED_SEND = auto()
|
||||
|
||||
|
||||
class NotificationTypes(IntEnum):
|
||||
NONE = 0
|
||||
OFFER_RECEIVED = auto()
|
||||
BID_RECEIVED = auto()
|
||||
BID_ACCEPTED = auto()
|
||||
|
||||
|
||||
class AutomationOverrideOptions(IntEnum):
|
||||
DEFAULT = 0
|
||||
ALWAYS_ACCEPT = 1
|
||||
NEVER_ACCEPT = auto()
|
||||
|
||||
|
||||
def strAutomationOverrideOption(option):
|
||||
if option == AutomationOverrideOptions.DEFAULT:
|
||||
return 'Default'
|
||||
if option == AutomationOverrideOptions.ALWAYS_ACCEPT:
|
||||
return 'Always Accept'
|
||||
if option == AutomationOverrideOptions.NEVER_ACCEPT:
|
||||
return 'Never Accept'
|
||||
return 'Unknown'
|
||||
|
||||
|
||||
class VisibilityOverrideOptions(IntEnum):
|
||||
DEFAULT = 0
|
||||
HIDE = 1
|
||||
BLOCK = auto()
|
||||
|
||||
|
||||
def strVisibilityOverrideOption(option):
|
||||
if option == VisibilityOverrideOptions.DEFAULT:
|
||||
return 'Default'
|
||||
if option == VisibilityOverrideOptions.HIDE:
|
||||
return 'Hide'
|
||||
if option == VisibilityOverrideOptions.BLOCK:
|
||||
return 'Block'
|
||||
return 'Unknown'
|
||||
|
||||
|
||||
def strOfferState(state):
|
||||
if state == OfferStates.OFFER_SENT:
|
||||
return 'Sent'
|
||||
|
@ -202,13 +241,6 @@ def strOfferState(state):
|
|||
return 'Unknown'
|
||||
|
||||
|
||||
class NotificationTypes(IntEnum):
|
||||
NONE = 0
|
||||
OFFER_RECEIVED = auto()
|
||||
BID_RECEIVED = auto()
|
||||
BID_ACCEPTED = auto()
|
||||
|
||||
|
||||
def strBidState(state):
|
||||
if state == BidStates.BID_SENT:
|
||||
return 'Sent'
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2019-2022 tecnovert
|
||||
# Copyright (c) 2019-2023 tecnovert
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
|
@ -12,7 +12,7 @@ from enum import IntEnum, auto
|
|||
from sqlalchemy.ext.declarative import declarative_base
|
||||
|
||||
|
||||
CURRENT_DB_VERSION = 17
|
||||
CURRENT_DB_VERSION = 18
|
||||
CURRENT_DB_DATA_VERSION = 2
|
||||
Base = declarative_base()
|
||||
|
||||
|
@ -421,6 +421,8 @@ class KnownIdentity(Base):
|
|||
num_recv_bids_rejected = sa.Column(sa.Integer)
|
||||
num_sent_bids_failed = sa.Column(sa.Integer)
|
||||
num_recv_bids_failed = sa.Column(sa.Integer)
|
||||
automation_override = sa.Column(sa.Integer) # AutomationOverrideOptions
|
||||
visibility_override = sa.Column(sa.Integer) # VisibilityOverrideOptions
|
||||
note = sa.Column(sa.String)
|
||||
updated_at = sa.Column(sa.BigInteger)
|
||||
created_at = sa.Column(sa.BigInteger)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2022 tecnovert
|
||||
# Copyright (c) 2022-2023 tecnovert
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
|
@ -238,6 +238,11 @@ def upgradeDatabase(self, db_version):
|
|||
tx_data BLOB,
|
||||
used_by BLOB,
|
||||
PRIMARY KEY (record_id))''')
|
||||
elif current_version == 16:
|
||||
db_version += 1
|
||||
session.execute('ALTER TABLE knownidentities ADD COLUMN automation_override INTEGER')
|
||||
session.execute('ALTER TABLE knownidentities ADD COLUMN visibility_override INTEGER')
|
||||
session.execute('UPDATE knownidentities SET active_ind = 1')
|
||||
|
||||
if current_version != db_version:
|
||||
self.db_version = db_version
|
||||
|
|
|
@ -17,6 +17,7 @@ from . import __version__
|
|||
from .util import (
|
||||
dumpj,
|
||||
ensure,
|
||||
zeroIfNone,
|
||||
LockedCoinError,
|
||||
format_timestamp,
|
||||
)
|
||||
|
@ -25,9 +26,11 @@ from .chainparams import (
|
|||
chainparams,
|
||||
)
|
||||
from .basicswap_util import (
|
||||
strBidState,
|
||||
strTxState,
|
||||
strBidState,
|
||||
strAddressType,
|
||||
AutomationOverrideOptions,
|
||||
strAutomationOverrideOption,
|
||||
)
|
||||
|
||||
from .js_server import (
|
||||
|
@ -37,6 +40,7 @@ from .js_server import (
|
|||
from .ui.util import (
|
||||
getCoinName,
|
||||
get_data_entry,
|
||||
get_data_entry_or,
|
||||
have_data_entry,
|
||||
listAvailableCoins,
|
||||
)
|
||||
|
@ -447,10 +451,13 @@ class HttpHandler(BaseHTTPRequestHandler):
|
|||
if have_data_entry(form_data, 'edit'):
|
||||
page_data['show_edit_form'] = True
|
||||
if have_data_entry(form_data, 'apply'):
|
||||
new_label = get_data_entry(form_data, 'label')
|
||||
|
||||
try:
|
||||
swap_client.updateIdentity(identity_address, new_label)
|
||||
data = {
|
||||
'label': get_data_entry_or(form_data, 'label', ''),
|
||||
'note': get_data_entry_or(form_data, 'note', ''),
|
||||
'automation_override': get_data_entry(form_data, 'automation_override'),
|
||||
}
|
||||
swap_client.setIdentityData({'address': identity_address}, data)
|
||||
messages.append('Updated')
|
||||
except Exception as e:
|
||||
err_messages.append(str(e))
|
||||
|
@ -466,14 +473,19 @@ class HttpHandler(BaseHTTPRequestHandler):
|
|||
page_data['num_recv_bids_rejected'] = identity.num_recv_bids_rejected
|
||||
page_data['num_sent_bids_failed'] = identity.num_sent_bids_failed
|
||||
page_data['num_recv_bids_failed'] = identity.num_recv_bids_failed
|
||||
automation_override = zeroIfNone(identity.automation_override)
|
||||
page_data['automation_override'] = automation_override
|
||||
page_data['str_automation_override'] = strAutomationOverrideOption(automation_override)
|
||||
page_data['note'] = identity.note
|
||||
except Exception as e:
|
||||
messages.append(e)
|
||||
err_messages.append(e)
|
||||
|
||||
template = env.get_template('identity.html')
|
||||
return self.render_template(template, {
|
||||
'messages': messages,
|
||||
'err_messages': err_messages,
|
||||
'data': page_data,
|
||||
'automation_override_options': [(int(opt), strAutomationOverrideOption(opt)) for opt in AutomationOverrideOptions if opt > 0],
|
||||
'summary': summary,
|
||||
})
|
||||
|
||||
|
|
|
@ -517,6 +517,12 @@ def js_identities(self, url_split, post_string: str, is_json: bool) -> bytes:
|
|||
set_data = {}
|
||||
if have_data_entry(post_data, 'set_label'):
|
||||
set_data['label'] = get_data_entry(post_data, 'set_label')
|
||||
if have_data_entry(post_data, 'set_automation_override'):
|
||||
set_data['automation_override'] = get_data_entry(post_data, 'set_automation_override')
|
||||
if have_data_entry(post_data, 'set_visibility_override'):
|
||||
set_data['visibility_override'] = get_data_entry(post_data, 'set_visibility_override')
|
||||
if have_data_entry(post_data, 'set_note'):
|
||||
set_data['note'] = get_data_entry(post_data, 'set_note')
|
||||
|
||||
if set_data:
|
||||
ensure('address' in filters, 'Must provide an address to modify data')
|
||||
|
@ -631,7 +637,7 @@ pages = {
|
|||
'rateslist': js_rates_list,
|
||||
'generatenotification': js_generatenotification,
|
||||
'notifications': js_notifications,
|
||||
'identities': js_identities,
|
||||
'identities': js_identities,
|
||||
'vacuumdb': js_vacuumdb,
|
||||
'getcoinseed': js_getcoinseed,
|
||||
'setpassword': js_setpassword,
|
||||
|
|
|
@ -63,11 +63,38 @@
|
|||
<input class="appearance-none bg-gray-50 border w-full border-gray-300 text-gray-900 text-sm rounded-lg outline-none focus:ring-blue-500 focus:border-blue-500 block p-2.5" type="text" id="label" name="label" value="{{ data.label }}">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="py-4 px-6 bold">Automation Override</td>
|
||||
<td class="py-4 pr-5">
|
||||
<select name="automation_override">
|
||||
<option{% if data.automation_override=="0" %} selected{% endif %} value="0">-- Default --</option>
|
||||
{% for a in automation_override_options %}
|
||||
<option{% if data.automation_override==a[0] %} selected{% endif %} value="{{ a[0] }}">{{ a[1] }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="py-4 px-6 bold">Notes</td>
|
||||
<td class="py-4 pr-5">
|
||||
<textarea rows="5" class="w-full" id="note" name="note">{{ data.note }}</textarea>
|
||||
</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr>
|
||||
<td class="py-4 px-6 bold">Label</td>
|
||||
<td class="py-4">{{ data.label }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="py-4 px-6 bold">Automation Override</td>
|
||||
<td class="py-4">{{ data.str_automation_override }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="py-4 px-6 bold">Notes</td>
|
||||
<td class="py-4">
|
||||
<textarea rows="5" class="w-full" readonly>{{ data.note }}</textarea></td>
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
<tr class="bg-white border-t hover:bg-gray-50">
|
||||
<td class="py-4 px-6 bold w-96">Successful Sent Bids</td>
|
||||
|
@ -123,4 +150,4 @@
|
|||
</div>
|
||||
{% include 'footer.html' %} </div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2018-2022 tecnovert
|
||||
# Copyright (c) 2018-2023 tecnovert
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
|
@ -177,7 +177,7 @@ def format_amount(i, display_scale, scale=None):
|
|||
return rv
|
||||
|
||||
|
||||
def format_timestamp(value, with_seconds=False):
|
||||
def format_timestamp(value: int, with_seconds=False) -> str:
|
||||
str_format = '%Y-%m-%d %H:%M'
|
||||
if with_seconds:
|
||||
str_format += ':%S'
|
||||
|
@ -205,5 +205,11 @@ def h2b(h: str) -> bytes:
|
|||
return bytes.fromhex(h)
|
||||
|
||||
|
||||
def i2h(x):
|
||||
def i2h(x: int) -> str:
|
||||
return b2h(i2b(x))
|
||||
|
||||
|
||||
def zeroIfNone(value) -> int:
|
||||
if value is None:
|
||||
return 0
|
||||
return value
|
||||
|
|
|
@ -76,27 +76,27 @@ def readConfig(args, known_coins):
|
|||
with open(config_path) as fs:
|
||||
config = json.load(fs)
|
||||
|
||||
if not 'offers' in config:
|
||||
if 'offers' not in config:
|
||||
config['offers'] = []
|
||||
if not 'bids' in config:
|
||||
if 'bids' not in config:
|
||||
config['bids'] = []
|
||||
if not 'stealthex' in config:
|
||||
if 'stealthex' not in config:
|
||||
config['stealthex'] = []
|
||||
|
||||
if not 'min_seconds_between_offers' in config:
|
||||
if 'min_seconds_between_offers' not in config:
|
||||
config['min_seconds_between_offers'] = 60
|
||||
print('Set min_seconds_between_offers', config['min_seconds_between_offers'])
|
||||
num_changes += 1
|
||||
if not 'max_seconds_between_offers' in config:
|
||||
if 'max_seconds_between_offers' not in config:
|
||||
config['max_seconds_between_offers'] = config['min_seconds_between_offers'] * 4
|
||||
print('Set max_seconds_between_offers', config['max_seconds_between_offers'])
|
||||
num_changes += 1
|
||||
|
||||
if not 'min_seconds_between_bids' in config:
|
||||
if 'min_seconds_between_bids' not in config:
|
||||
config['min_seconds_between_bids'] = 60
|
||||
print('Set min_seconds_between_bids', config['min_seconds_between_bids'])
|
||||
num_changes += 1
|
||||
if not 'max_seconds_between_bids' in config:
|
||||
if 'max_seconds_between_bids' not in config:
|
||||
config['max_seconds_between_bids'] = config['min_seconds_between_bids'] * 4
|
||||
print('Set max_seconds_between_bids', config['max_seconds_between_bids'])
|
||||
num_changes += 1
|
||||
|
@ -152,7 +152,7 @@ def readConfig(args, known_coins):
|
|||
bid_template['coin_to'] = findCoin(bid_template['coin_to'], known_coins)
|
||||
|
||||
if bid_template['name'] in bid_templates_map:
|
||||
print('renaming bid template', offer_templates_map_template['name'])
|
||||
print('renaming bid template', bid_template['name'])
|
||||
original_name = bid_template['name']
|
||||
offset = 2
|
||||
while f'{original_name}_{offset}' in bid_templates_map:
|
||||
|
@ -167,7 +167,6 @@ def readConfig(args, known_coins):
|
|||
for i, swap in enumerate(stealthex_swaps):
|
||||
num_enabled += 1 if swap.get('enabled', True) else 0
|
||||
swap['coin_from'] = findCoin(swap['coin_from'], known_coins)
|
||||
#bid_template['coin_to'] = findCoin(bid_template['coin_to'], known_coins)
|
||||
config['num_enabled_swaps'] = num_enabled
|
||||
|
||||
if num_changes > 0:
|
||||
|
@ -303,10 +302,10 @@ def main():
|
|||
new_offer = read_json_api('offers/new', offer_data)
|
||||
print('New offer: {}'.format(new_offer['offer_id']))
|
||||
num_state_changes += 1
|
||||
if not 'offers' in script_state:
|
||||
if 'offers' not in script_state:
|
||||
script_state['offers'] = {}
|
||||
template_name = offer_template['name']
|
||||
if not template_name in script_state['offers']:
|
||||
if template_name not in script_state['offers']:
|
||||
script_state['offers'][template_name] = []
|
||||
script_state['offers'][template_name].append({'offer_id': new_offer['offer_id'], 'time': int(time.time())})
|
||||
max_seconds_between_offers = config['max_seconds_between_offers']
|
||||
|
@ -328,10 +327,10 @@ def main():
|
|||
|
||||
# Check bids in progress
|
||||
max_concurrent = bid_template.get('max_concurrent', 1)
|
||||
if not 'bids' in script_state:
|
||||
if 'bids' not in script_state:
|
||||
script_state['bids'] = {}
|
||||
template_name = bid_template['name']
|
||||
if not template_name in script_state['bids']:
|
||||
if template_name not in script_state['bids']:
|
||||
script_state['bids'][template_name] = []
|
||||
previous_bids = script_state['bids'][template_name]
|
||||
|
||||
|
@ -405,12 +404,22 @@ def main():
|
|||
|
||||
offer_identity = read_json_api('identities/{}'.format(offer['addr_from']))
|
||||
if len(offer_identity) > 0:
|
||||
successful_sent_bids = offer_identity[0]['num_sent_bids_successful']
|
||||
failed_sent_bids = offer_identity[0]['num_sent_bids_failed']
|
||||
if failed_sent_bids > 3 and failed_sent_bids > successful_sent_bids:
|
||||
id_offer_from = offer_identity[0]
|
||||
automation_override = id_offer_from['automation_override']
|
||||
if automation_override == 2:
|
||||
if args.debug:
|
||||
print(f'Not bidding on offer {offer_id}, too many failed bids ({failed_sent_bids}).')
|
||||
print(f'Not bidding on offer {offer_id}, automation_override ({automation_override}).')
|
||||
continue
|
||||
if automation_override == 1:
|
||||
if args.debug:
|
||||
print('Offer address from {}, set to always accept.'.format(offer['addr_from']))
|
||||
else:
|
||||
successful_sent_bids = id_offer_from['num_sent_bids_successful']
|
||||
failed_sent_bids = id_offer_from['num_sent_bids_failed']
|
||||
if failed_sent_bids > 3 and failed_sent_bids > successful_sent_bids:
|
||||
if args.debug:
|
||||
print(f'Not bidding on offer {offer_id}, too many failed bids ({failed_sent_bids}).')
|
||||
continue
|
||||
|
||||
max_coin_from_balance = bid_template.get('max_coin_from_balance', -1)
|
||||
if max_coin_from_balance > 0:
|
||||
|
@ -533,10 +542,10 @@ def main():
|
|||
'address_to': address_to,
|
||||
'amount_from': swap_amount,
|
||||
'fixed': True,
|
||||
#'extra_id_to':
|
||||
#'referral':
|
||||
# 'extra_id_to':
|
||||
# 'referral':
|
||||
'refund_address': address_refund,
|
||||
#'refund_extra_id':
|
||||
# 'refund_extra_id':
|
||||
'rate_id': estimate_response['rate_id'],
|
||||
}
|
||||
|
||||
|
|
|
@ -197,7 +197,6 @@ class Test(unittest.TestCase):
|
|||
cls.node1_statefile = os.path.join(datadir, 'node1_state.json')
|
||||
cls.node1_args = [script_path, '--port', str(UI_PORT + 1), '--configfile', cls.node1_configfile, '--statefile', cls.node1_statefile, '--oneshot', '--debug']
|
||||
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
logging.info('Stopping test')
|
||||
|
@ -333,7 +332,7 @@ class Test(unittest.TestCase):
|
|||
assert (count_lines_with(rv_stdout, 'Bid rate too low for offer') == 3)
|
||||
assert (count_lines_with(rv_stdout, 'Already bidding on offer') == 1)
|
||||
|
||||
logging.info(f'Modifying node1 config')
|
||||
logging.info('Modifying node1 config')
|
||||
node1_test1_config['bids'][0]['maxrate'] = 0.07
|
||||
node1_test1_config['bids'][0]['max_coin_from_balance'] = 100
|
||||
node1_test1_config['bids'][0]['min_coin_to_balance'] = 100
|
||||
|
@ -418,7 +417,7 @@ class Test(unittest.TestCase):
|
|||
assert (len(possible_bids) == 1)
|
||||
assert (float(possible_bids[0]['amount_from'] < 20.0))
|
||||
|
||||
logging.info(f'Adding mock data to node1 db for tests')
|
||||
logging.info('Adding mock data to node1 db for tests')
|
||||
rows = []
|
||||
offers = read_json_api(UI_PORT, 'offers')
|
||||
|
||||
|
@ -523,7 +522,6 @@ class Test(unittest.TestCase):
|
|||
offer_ids = []
|
||||
logging.info('Create three offers')
|
||||
|
||||
|
||||
for i in range(3):
|
||||
if i > 0:
|
||||
with open(self.node0_statefile) as fs:
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2019-2022 tecnovert
|
||||
# Copyright (c) 2019-2023 tecnovert
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
|
@ -145,6 +145,20 @@ class Test(BaseTest):
|
|||
rv = read_json_api(1800, 'identities/pPCsRro5po7Yu6kyu5XjSyr3A1PPdk9j1F', {'set_label': 'test 3'})
|
||||
assert (rv['error'] == 'Invalid identity address')
|
||||
|
||||
rv = read_json_api(1800, 'identities/ppCsRro5po7Yu6kyu5XjSyr3A1PPdk9j1F', {'set_note': 'note 1'})
|
||||
assert (len(rv) == 1)
|
||||
assert (rv[0]['address'] == 'ppCsRro5po7Yu6kyu5XjSyr3A1PPdk9j1F')
|
||||
assert (rv[0]['label'] == 'test 2')
|
||||
assert (rv[0]['note'] == 'note 1')
|
||||
|
||||
rv = read_json_api(1800, 'identities/ppCsRro5po7Yu6kyu5XjSyr3A1PPdk9j1F', {'set_automation_override': 1})
|
||||
assert (len(rv) == 1)
|
||||
assert (rv[0]['automation_override'] == 1)
|
||||
|
||||
rv = read_json_api(1800, 'identities/ppCsRro5po7Yu6kyu5XjSyr3A1PPdk9j1F', {'set_visibility_override': 'hide'})
|
||||
assert (len(rv) == 1)
|
||||
assert (rv[0]['visibility_override'] == 1)
|
||||
|
||||
def test_01_verifyrawtransaction(self):
|
||||
txn = '0200000001eb6e5c4ebba4efa32f40c7314cad456a64008e91ee30b2dd0235ab9bb67fbdbb01000000ee47304402200956933242dde94f6cf8f195a470f8d02aef21ec5c9b66c5d3871594bdb74c9d02201d7e1b440de8f4da672d689f9e37e98815fb63dbc1706353290887eb6e8f7235012103dc1b24feb32841bc2f4375da91fa97834e5983668c2a39a6b7eadb60e7033f9d205a803b28fe2f86c17db91fa99d7ed2598f79b5677ffe869de2e478c0d1c02cc7514c606382012088a8201fe90717abb84b481c2a59112414ae56ec8acc72273642ca26cc7a5812fdc8f68876a914225fbfa4cb725b75e511810ac4d6f74069bdded26703520140b27576a914207eb66b2fd6ed9924d6217efc7fa7b38dfabe666888acffffffff01e0167118020000001976a9140044e188928710cecba8311f1cf412135b98145c88ac00000000'
|
||||
prevout = {
|
||||
|
|
Loading…
Reference in a new issue