api: getcoinseed shows seed id

This commit is contained in:
tecnovert 2023-02-18 01:47:44 +02:00
parent c2d6cdafdd
commit b6046fdbf3
No known key found for this signature in database
GPG key ID: 8ED6D8750C4E3F93
13 changed files with 109 additions and 54 deletions

View file

@ -1,3 +1,3 @@
name = "basicswap"
__version__ = "0.11.58"
__version__ = "0.11.59"

View file

@ -4273,7 +4273,7 @@ class BasicSwap(BaseApp):
except AutomationConstraint as e:
self.log.info('Not auto accepting bid {}, {}'.format(bid.bid_id.hex(), str(e)))
if self.debug:
self.logEvent(Concepts.AUTOMATION,
self.logEvent(Concepts.BID,
bid.bid_id,
EventLogTypes.AUTOMATION_CONSTRAINT,
str(e),
@ -5814,7 +5814,7 @@ class BasicSwap(BaseApp):
session.remove()
self.mxDB.release()
def updateWalletInfo(self, coin):
def updateWalletInfo(self, coin) -> None:
# Store wallet info to db so it's available after startup
try:
bi = self.getBlockchainInfo(coin)
@ -6141,15 +6141,22 @@ class BasicSwap(BaseApp):
session.remove()
self.mxDB.release()
def getAutomationStrategy(self, strategy_id):
self.mxDB.acquire()
def getAutomationStrategy(self, strategy_id: int):
try:
session = scoped_session(self.session_factory)
session = self.openSession()
return session.query(AutomationStrategy).filter_by(record_id=strategy_id).first()
finally:
session.close()
session.remove()
self.mxDB.release()
self.closeSession(session, commit=False)
def updateAutomationStrategy(self, strategy_id: int, data, note: str) -> None:
try:
session = self.openSession()
strategy = session.query(AutomationStrategy).filter_by(record_id=strategy_id).first()
strategy.data = json.dumps(data).encode('utf-8')
strategy.note = note
session.add(strategy)
finally:
self.closeSession(session)
def getLinkedStrategy(self, linked_type, linked_id):
self.mxDB.acquire()
@ -6211,7 +6218,7 @@ class BasicSwap(BaseApp):
if session is None:
self.closeSession(use_session)
def addSMSGAddress(self, pubkey_hex, addressnote=None):
def addSMSGAddress(self, pubkey_hex: str, addressnote: str = None) -> None:
self.mxDB.acquire()
try:
session = scoped_session(self.session_factory)
@ -6229,7 +6236,7 @@ class BasicSwap(BaseApp):
session.remove()
self.mxDB.release()
def editSMSGAddress(self, address, active_ind, addressnote):
def editSMSGAddress(self, address: str, active_ind: int, addressnote: str) -> None:
self.mxDB.acquire()
try:
session = scoped_session(self.session_factory)

View file

@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2020-2022 tecnovert
# Copyright (c) 2020-2023 tecnovert
# Distributed under the MIT software license, see the accompanying
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
@ -260,7 +260,7 @@ class BTCInterface(CoinInterface):
last_block_header = prev_block_header
raise ValueError(f'Block header not found at time: {time}')
def initialiseWallet(self, key_bytes: bytes):
def initialiseWallet(self, key_bytes: bytes) -> None:
key_wif = self.encodeKey(key_bytes)
self.rpc_callback('sethdseed', [True, key_wif])
@ -388,11 +388,11 @@ class BTCInterface(CoinInterface):
def getPubkey(self, privkey):
return PublicKey.from_secret(privkey).format()
def getAddressHashFromKey(self, key) -> bytes:
def getAddressHashFromKey(self, key: bytes) -> bytes:
pk = self.getPubkey(key)
return hash160(pk)
def getSeedHash(self, seed):
def getSeedHash(self, seed) -> bytes:
return self.getAddressHashFromKey(seed)[::-1]
def verifyKey(self, k: bytes) -> bool:

View file

@ -163,7 +163,7 @@ class FIROInterface(BTCInterface):
return CScript([OP_HASH160, script_hash_hash, OP_EQUAL])
def getSeedHash(self, seed):
def getSeedHash(self, seed) -> bytes:
return hash160(seed)[::-1]
def encodeScriptDest(self, script):

View file

@ -127,7 +127,7 @@ class XMRInterface(CoinInterface):
self.createWallet(params)
self.openWallet(self._wallet_filename)
def ensureWalletExists(self):
def ensureWalletExists(self) -> None:
with self._mx_wallet:
self.openWallet(self._wallet_filename)
@ -190,12 +190,12 @@ class XMRInterface(CoinInterface):
def walletRestoreHeight(self):
return self._restore_height
def getMainWalletAddress(self):
def getMainWalletAddress(self) -> str:
with self._mx_wallet:
self.openWallet(self._wallet_filename)
return self.rpc_wallet_cb('get_address')['address']
def getNewAddress(self, placeholder):
def getNewAddress(self, placeholder) -> str:
with self._mx_wallet:
self.openWallet(self._wallet_filename)
return self.rpc_wallet_cb('create_address', {'account_index': 0})['address']
@ -204,19 +204,19 @@ class XMRInterface(CoinInterface):
self._log.warning('TODO - estimate fee rate?')
return 0.0, 'unused'
def getNewSecretKey(self):
def getNewSecretKey(self) -> bytes:
return edu.get_secret()
def pubkey(self, key):
def pubkey(self, key: bytes) -> bytes:
return edf.scalarmult_B(key)
def encodeKey(self, vk):
def encodeKey(self, vk: bytes) -> str:
return vk[::-1].hex()
def decodeKey(self, k_hex):
def decodeKey(self, k_hex: str) -> bytes:
return bytes.fromhex(k_hex)[::-1]
def encodePubkey(self, pk):
def encodePubkey(self, pk: bytes) -> str:
return edu.encodepoint(pk)
def decodePubkey(self, pke):
@ -225,12 +225,12 @@ class XMRInterface(CoinInterface):
def getPubkey(self, privkey):
return ed25519_get_pubkey(privkey)
def getAddressFromKeys(self, key_view, key_spend):
def getAddressFromKeys(self, key_view: bytes, key_spend: bytes) -> str:
pk_view = self.getPubkey(key_view)
pk_spend = self.getPubkey(key_spend)
return xmr_util.encode_address(pk_view, pk_spend)
def verifyKey(self, k):
def verifyKey(self, k: int) -> bool:
i = b2i(k)
return (i < edf.l and i > 8)
@ -239,23 +239,23 @@ class XMRInterface(CoinInterface):
# Checks for small order
return verify_ed25519_point(pubkey_bytes)
def proveDLEAG(self, key):
def proveDLEAG(self, key: bytes) -> bytes:
privkey = PrivateKey(key)
return dleag_prove(privkey)
def verifyDLEAG(self, dleag_bytes):
def verifyDLEAG(self, dleag_bytes: bytes) -> bool:
return dleag_verify(dleag_bytes)
def lengthDLEAG(self):
def lengthDLEAG(self) -> int:
return dleag_proof_len()
def sumKeys(self, ka, kb):
def sumKeys(self, ka: bytes, kb: bytes) -> bytes:
return ed25519_scalar_add(ka, kb)
def sumPubkeys(self, Ka, Kb):
def sumPubkeys(self, Ka: bytes, Kb: bytes) -> bytes:
return ed25519_add(Ka, Kb)
def encodeSharedAddress(self, Kbv, Kbs):
def encodeSharedAddress(self, Kbv: bytes, Kbs: bytes) -> str:
return xmr_util.encode_address(Kbv, Kbs)
def publishBLockTx(self, kbv, Kbs, output_amount, feerate, delay_for: int = 10, unlock_time: int = 0) -> bytes:
@ -494,14 +494,14 @@ class XMRInterface(CoinInterface):
self._wallet_password = orig_password
raise e
def unlockWallet(self, password):
def unlockWallet(self, password: str) -> None:
self._log.info('unlockWallet - {}'.format(self.ticker()))
self._wallet_password = password
if not self._have_checked_seed:
self._sc.checkWalletSeed(self.coin_type())
def lockWallet(self):
def lockWallet(self) -> None:
self._log.info('lockWallet - {}'.format(self.ticker()))
self._wallet_password = None

View file

@ -551,10 +551,17 @@ def js_getcoinseed(self, url_split, post_string, is_json) -> bytes:
raise ValueError('Particl wallet seed is set from the Basicswap mnemonic.')
ci = swap_client.ci(coin)
seed = swap_client.getWalletKey(coin, 1)
if coin == Coins.XMR:
key_view = swap_client.getWalletKey(coin, 1, for_ed25519=True)
key_spend = swap_client.getWalletKey(coin, 2, for_ed25519=True)
address = ci.getAddressFromKeys(key_view, key_spend)
return bytes(json.dumps({'coin': ci.ticker(), 'key_view': ci.encodeKey(key_view), 'key_spend': ci.encodeKey(key_spend), 'address': address}), 'UTF-8')
seed_key = swap_client.getWalletKey(coin, 1)
if coin == Coins.DASH:
return bytes(json.dumps({'coin': ci.ticker(), 'seed': seed.hex(), 'mnemonic': ci.seedToMnemonic(seed)}), 'UTF-8')
return bytes(json.dumps({'coin': ci.ticker(), 'seed': seed.hex()}), 'UTF-8')
return bytes(json.dumps({'coin': ci.ticker(), 'seed': seed_key.hex(), 'mnemonic': ci.seedToMnemonic(seed_key)}), 'UTF-8')
seed_id = ci.getSeedHash(seed_key)
return bytes(json.dumps({'coin': ci.ticker(), 'seed': seed_key.hex(), 'seed_id': seed_id.hex()}), 'UTF-8')
def js_setpassword(self, url_split, post_string, is_json) -> bytes:

View file

@ -44,6 +44,7 @@
<div class="pb-6 border-coolGray-100">
<div class="flex flex-wrap items-center justify-between -m-2">
<div class="w-full pt-2 text-center ">
<form method="post" autocomplete="off">
<div class="container px-0 mx-auto mt-5">
<div class="overflow-x-auto relative border sm:rounded-lg">
<table class="w-full text-sm text-left text-gray-500 outline-none border-gray-300">
@ -69,11 +70,11 @@
<tr class="bg-white border-t hover:bg-gray-50">
<td class="py-4 px-6 bold w-96">Data</td>
<td class="py-4 pr-5">
<textarea class="outline-none block p-2.5 text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500 w-full monospace" rows="5" readonly>{{ strategy.data }}</textarea>
<textarea name="data" class="outline-none block p-2.5 text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500 w-full monospace" rows="5" {% if not show_edit_form %}readonly{% endif %}>{{ strategy.data }}</textarea>
<tr class="bg-white border-t hover:bg-gray-50">
<td class="py-4 px-6 bold w-96">Notes</td>
<td class="py-4 pr-5">
<textarea class="outline-none block p-2.5 text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500 w-full monospace" rows="5" readonly>{{ strategy.note }}</textarea>
<textarea name="note" class="outline-none block p-2.5 text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500 w-full monospace" rows="5" {% if not show_edit_form %}readonly{% endif %}>{{ strategy.note }}</textarea>
</td>
</tr>
</table>
@ -82,12 +83,27 @@
<div class="p-6 pt-10 bg-white bg-opacity-60 rounded-b-md">
<div class="w-full md:w-0/12">
<div class="flex flex-wrap justify-end -m-1.5">
{% if show_edit_form %}
<div class="w-full md:w-auto p-1.5 ml-2">
<button name="apply" value="Apply" type="submit" class="flex flex-wrap justify-center w-full px-4 py-2.5 bg-blue-500 hover:bg-blue-600 font-medium text-sm text-white border border-blue-500 rounded-md shadow-button focus:ring-0 focus:outline-none"><svg class="text-gray-500 w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><g stroke-linecap="round" stroke-width="2" fill="none" stroke="#ffffff" stroke-linejoin="round" ><polyline points=" 6,12 10,16 18,8 " stroke="#ffffff"></polyline> <circle cx="12" cy="12" r="11"></circle></g></svg>Apply</button>
</div>
<div class="w-full md:w-auto p-1.5 ml-2">
<button name="cancel" value="Cancel" type="submit"class="flex flex-wrap justify-center w-full px-4 py-2.5 font-medium text-sm text-red-500 hover:text-red-600 border border-red-400 hover:border-red-500 bg-white rounded-md shadow-button focus:ring-0 focus:outline-none"><svg class="text-gray-500 w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><g stroke-linecap="round" stroke-width="2" fill="none" stroke="#ef5844" stroke-linejoin="round" ><line x1="16" y1="8" x2="8" y2="16" stroke="#ef5844"></line> <line x1="16" y1="16" x2="8" y2="8" stroke="#ef5844"></line> <circle cx="12" cy="12" r="11"></circle></g></svg>Cancel</button>
</div>
{% else %}
<div class="w-full md:w-auto p-1.5">
<button name="edit" value="edit" type="submit" class="flex flex-wrap justify-center w-full px-4 py-2.5 bg-blue-500 hover:bg-blue-600 font-medium text-sm text-white border border-blue-500 rounded-md shadow-button focus:ring-0 focus:outline-none">
<svg class="text-gray-500 w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><g stroke-linecap="round" stroke-width="2" fill="none" stroke="#ffffff" stroke-linejoin="round" ><line x1="2" y1="23" x2="22" y2="23" stroke="#ffffff"></line> <line data-cap="butt" x1="13" y1="5" x2="17" y2="9"></line> <polygon points="8 18 3 19 4 14 16 2 20 6 8 18"></polygon></g></svg>Edit</button>
</div>
<div class="w-full md:w-auto p-1.5 ml-2">
<a href="/automation" type="submit" class="flex flex-wrap justify-center w-full px-4 py-2.5 font-medium text-sm text-coolGray-500 hover:text-coolGray-600 border border-coolGray-200 hover:border-coolGray-300 bg-white rounded-md shadow-button focus:ring-0 focus:outline-non"><svg class="text-gray-500 w-5 h-5 mr-2" height="24" width="24" viewBox="0 0 24 24"><g stroke-linecap="square" stroke-width="2" fill="none" stroke="#556987" stroke-linejoin="miter" class="nc-icon-wrapper" stroke-miterlimit="10"><line data-cap="butt" x1="18" y1="12" x2="7" y2="12" stroke-linecap="butt" stroke="#556987"></line> <polyline points=" 11,16 7,12 11,8 " stroke="#5569878"></polyline> <circle cx="12" cy="12" r="11"></circle></g></svg> <span>Back</span> </a>
</div>
{% endif %}
</div>
</div>
</div>
<input type="hidden" name="formid" value="{{ form_id }}">
</form>
</div>
</div>
</div>

View file

@ -241,7 +241,7 @@
</tr>
</thead>
<tr class="bg-white border-t hover:bg-gray-50">
<td class="py-4 px-6 bold w-96 bold">Debug Node</td>
<td class="py-4 px-6 bold w-96 bold">Debug Mode</td>
<td class="py-4 pr-5">
<div class="w-52 md:flex-1">
<div class="relative">

View file

@ -1,12 +1,15 @@
# -*- 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.
import json
from .util import (
PAGE_LIMIT,
get_data_entry,
get_data_entry_or,
have_data_entry,
set_pagination_filters,
)
@ -89,14 +92,29 @@ def page_automation_strategy(self, url_split, post_string):
messages = []
err_messages = []
form_data = self.checkForm(post_string, 'automation_strategy', err_messages)
show_edit_form = False
if form_data:
if have_data_entry(form_data, 'edit'):
show_edit_form = True
if have_data_entry(form_data, 'apply'):
try:
data = json.loads(get_data_entry_or(form_data, 'data', ''))
note = get_data_entry_or(form_data, 'note', '')
swap_client.updateAutomationStrategy(strategy_id, data, note)
messages.append('Updated')
except Exception as e:
err_messages.append(str(e))
show_edit_form = True
strategy = swap_client.getAutomationStrategy(strategy_id)
formatted_strategy = {
'label': strategy.label,
'type': strConcepts(strategy.type_ind),
'only_known_identities': 'True' if strategy.only_known_identities is True else 'False',
'data': strategy.data,
'note': strategy.note,
'data': strategy.data.decode('utf-8'),
'note': '' if not strategy.note else strategy.note,
'created_at': strategy.created_at,
}
@ -105,5 +123,6 @@ def page_automation_strategy(self, url_split, post_string):
'messages': messages,
'err_messages': err_messages,
'strategy': formatted_strategy,
'show_edit_form': show_edit_form,
'summary': summary,
})

View file

@ -17,7 +17,9 @@
- api: Can abandon bids.
- If wallets are encrypted the system will only load in-progress bids when unlocked rather than at startup.
- Can set overrides for automation strategies per identity.
- ui: bids on expired offers won't show as available
- ui: Bids on expired offers won't show as available.
- api: getcoinseed shows seed id.
- ui: Can edit automation strategy data.
0.0.54

View file

@ -1,7 +1,7 @@
#!/usr/bin/env python3
# -*- 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.
@ -260,6 +260,9 @@ class BasicSwapTest(BaseTest):
self.callnoderpc('getnewaddress')
assert self.swap_clients[0].checkWalletSeed(Coins.BTC) is True
rv = read_json_api(1800, 'getcoinseed', {'coin': 'XMR'})
assert (rv['address'] == '47H7UDLzYEsR28BWttxp59SP1UVSxs4VKDJYSfmz7Wd4Fue5VWuoV9x9eejunwzVSmHWN37gBkaAPNf9VD4bTvwQKsBVWyK')
def do_test_01_full_swap(self, coin_from, coin_to):
logging.info('---------- Test {} to {}'.format(coin_from.name, coin_to.name))

View file

@ -132,6 +132,7 @@ class Test(BaseTest):
rv = read_json_api(1800, 'getcoinseed', {'coin': 'BTC'})
assert (rv['seed'] == '8e54a313e6df8918df6d758fafdbf127a115175fdd2238d0e908dd8093c9ac3b')
assert (rv['seed_id'] == '3da5c0af91879e8ce97d9a843874601c08688078')
rv = read_json_api(1800, 'identities/ppCsRro5po7Yu6kyu5XjSyr3A1PPdk9j1F', {'set_label': 'test 1'})
assert (len(rv) == 1)