mirror of
https://github.com/basicswap/basicswap.git
synced 2025-11-06 02:38:11 +01:00
Decred: Add to test_xmr_persistent
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
name = "basicswap"
|
||||
|
||||
__version__ = "0.13.0"
|
||||
__version__ = "0.13.1"
|
||||
|
||||
@@ -774,9 +774,7 @@ class BasicSwap(BaseApp):
|
||||
|
||||
if self.coin_clients[c]['connection_type'] == 'rpc':
|
||||
ci = self.ci(c)
|
||||
self.waitForDaemonRPC(c, with_wallet=False)
|
||||
if c not in (Coins.XMR,) and ci.checkWallets() >= 1:
|
||||
self.waitForDaemonRPC(c)
|
||||
self.waitForDaemonRPC(c)
|
||||
|
||||
core_version = ci.getDaemonVersion()
|
||||
self.log.info('%s Core version %d', ci.coin_name(), core_version)
|
||||
@@ -857,7 +855,7 @@ class BasicSwap(BaseApp):
|
||||
self.log.info('Scanned %d unread messages.', nm)
|
||||
|
||||
def stopDaemon(self, coin) -> None:
|
||||
if coin == Coins.XMR:
|
||||
if coin in (Coins.XMR, Coins.DCR):
|
||||
return
|
||||
num_tries = 10
|
||||
authcookiepath = os.path.join(self.getChainDatadirPath(coin), '.cookie')
|
||||
@@ -893,6 +891,17 @@ class BasicSwap(BaseApp):
|
||||
self.stopDaemon(c)
|
||||
|
||||
def waitForDaemonRPC(self, coin_type, with_wallet: bool = True) -> None:
|
||||
|
||||
if with_wallet:
|
||||
self.waitForDaemonRPC(coin_type, with_wallet=False)
|
||||
if coin_type in (Coins.XMR,):
|
||||
return
|
||||
ci = self.ci(coin_type)
|
||||
# checkWallets can adjust the wallet name.
|
||||
if ci.checkWallets() < 1:
|
||||
self.log.error('No wallets found for coin {}.'.format(ci.coin_name()))
|
||||
self.stopRunning(1) # systemd will try to restart the process if fail_code != 0
|
||||
|
||||
startup_tries = self.startup_tries
|
||||
chain_client_settings = self.getChainClientSettings(coin_type)
|
||||
if 'startup_tries' in chain_client_settings:
|
||||
@@ -1938,9 +1947,6 @@ class BasicSwap(BaseApp):
|
||||
self.log.debug('Generated new receive address %s for %s', new_addr, Coins(coin_type).name)
|
||||
return new_addr
|
||||
|
||||
def getRelayFeeRateForCoin(self, coin_type):
|
||||
return self.callcoinrpc(coin_type, 'getnetworkinfo')['relayfee']
|
||||
|
||||
def getFeeRateForCoin(self, coin_type, conf_target: int = 2):
|
||||
return self.ci(coin_type).get_fee_rate(conf_target)
|
||||
|
||||
@@ -3376,11 +3382,11 @@ class BasicSwap(BaseApp):
|
||||
txn_script]
|
||||
redeem_txn = ci.setTxSignature(bytes.fromhex(redeem_txn), witness_stack).hex()
|
||||
else:
|
||||
script = (len(redeem_sig) // 2).to_bytes(1) + bytes.fromhex(redeem_sig)
|
||||
script += (33).to_bytes(1) + pubkey
|
||||
script += (32).to_bytes(1) + secret
|
||||
script += (OpCodes.OP_1).to_bytes(1)
|
||||
script += (OpCodes.OP_PUSHDATA1).to_bytes(1) + (len(txn_script)).to_bytes(1) + txn_script
|
||||
script = (len(redeem_sig) // 2).to_bytes(1, 'big') + bytes.fromhex(redeem_sig)
|
||||
script += (33).to_bytes(1, 'big') + pubkey
|
||||
script += (32).to_bytes(1, 'big') + secret
|
||||
script += (OpCodes.OP_1).to_bytes(1, 'big')
|
||||
script += (OpCodes.OP_PUSHDATA1).to_bytes(1, 'big') + (len(txn_script)).to_bytes(1, 'big') + txn_script
|
||||
redeem_txn = ci.setTxScriptSig(bytes.fromhex(redeem_txn), 0, script).hex()
|
||||
|
||||
if coin_type in (Coins.NAV, Coins.DCR):
|
||||
@@ -3488,10 +3494,10 @@ class BasicSwap(BaseApp):
|
||||
txn_script]
|
||||
refund_txn = ci.setTxSignature(bytes.fromhex(refund_txn), witness_stack).hex()
|
||||
else:
|
||||
script = (len(refund_sig) // 2).to_bytes(1) + bytes.fromhex(refund_sig)
|
||||
script += (33).to_bytes(1) + pubkey
|
||||
script += (OpCodes.OP_0).to_bytes(1)
|
||||
script += (OpCodes.OP_PUSHDATA1).to_bytes(1) + (len(txn_script)).to_bytes(1) + txn_script
|
||||
script = (len(refund_sig) // 2).to_bytes(1, 'big') + bytes.fromhex(refund_sig)
|
||||
script += (33).to_bytes(1, 'big') + pubkey
|
||||
script += (OpCodes.OP_0).to_bytes(1, 'big')
|
||||
script += (OpCodes.OP_PUSHDATA1).to_bytes(1, 'big') + (len(txn_script)).to_bytes(1, 'big') + txn_script
|
||||
refund_txn = ci.setTxScriptSig(bytes.fromhex(refund_txn), 0, script)
|
||||
|
||||
if coin_type in (Coins.NAV, Coins.DCR):
|
||||
@@ -4517,8 +4523,8 @@ class BasicSwap(BaseApp):
|
||||
except Exception as e:
|
||||
if 'Block not available (pruned data)' in str(e):
|
||||
# TODO: Better solution?
|
||||
bci = self.callcoinrpc(coin_type, 'getblockchaininfo')
|
||||
self.log.error('Coin %s last_height_checked %d set to pruneheight %d', self.ci(coin_type).coin_name(), last_height_checked, bci['pruneheight'])
|
||||
bci = ci.getBlockchainInfo()
|
||||
self.log.error('Coin %s last_height_checked %d set to pruneheight %d', ci.coin_name(), last_height_checked, bci['pruneheight'])
|
||||
last_height_checked = bci['pruneheight']
|
||||
continue
|
||||
else:
|
||||
|
||||
@@ -153,16 +153,19 @@ class CoinInterface:
|
||||
def use_tx_vsize(self) -> bool:
|
||||
return self._use_segwit
|
||||
|
||||
def getLockTxSwapOutputValue(self, bid, xmr_swap):
|
||||
def getLockTxSwapOutputValue(self, bid, xmr_swap) -> int:
|
||||
return bid.amount
|
||||
|
||||
def getLockRefundTxSwapOutputValue(self, bid, xmr_swap):
|
||||
def getLockRefundTxSwapOutputValue(self, bid, xmr_swap) -> int:
|
||||
return xmr_swap.a_swap_refund_value
|
||||
|
||||
def getLockRefundTxSwapOutput(self, xmr_swap):
|
||||
def getLockRefundTxSwapOutput(self, xmr_swap) -> int:
|
||||
# Only one prevout exists
|
||||
return 0
|
||||
|
||||
def checkWallets(self) -> int:
|
||||
return 1
|
||||
|
||||
|
||||
class AdaptorSigInterface():
|
||||
def getScriptLockTxDummyWitness(self, script: bytes):
|
||||
|
||||
@@ -109,7 +109,7 @@ def DCRSignatureHash(sign_script: bytes, hash_type: SigHashType, tx: CTransactio
|
||||
for txi_n, txi in enumerate(sign_vins):
|
||||
hash_buffer += txi.prevout.hash.to_bytes(32, 'little')
|
||||
hash_buffer += txi.prevout.n.to_bytes(4, 'little')
|
||||
hash_buffer += txi.prevout.tree.to_bytes(1)
|
||||
hash_buffer += txi.prevout.tree.to_bytes(1, 'little')
|
||||
|
||||
# In the case of SigHashNone and SigHashSingle, commit to 0 for everything that is not the input being signed instead.
|
||||
if (masked_hash_type == SigHashType.SigHashNone
|
||||
@@ -308,14 +308,19 @@ class DCRInterface(Secp256k1Interface):
|
||||
def getChainHeight(self) -> int:
|
||||
return self.rpc('getblockcount')
|
||||
|
||||
def checkWallets(self) -> int:
|
||||
# Only one wallet possible?
|
||||
return 1
|
||||
|
||||
def initialiseWallet(self, key: bytes) -> None:
|
||||
# Load with --create
|
||||
pass
|
||||
|
||||
def getWalletSeedID(self):
|
||||
masterpubkey = self.rpc_wallet('getmasterpubkey')
|
||||
masterpubkey_data = self.decode_address(masterpubkey)[4:]
|
||||
return hash160(masterpubkey_data).hex()
|
||||
|
||||
def checkExpectedSeed(self, expect_seedid) -> bool:
|
||||
self._expect_seedid_hex = expect_seedid
|
||||
return expect_seedid == self.getWalletSeedID()
|
||||
|
||||
def getDaemonVersion(self):
|
||||
return self.rpc('getnetworkinfo')['version']
|
||||
|
||||
@@ -368,7 +373,7 @@ class DCRInterface(Secp256k1Interface):
|
||||
def encodeKey(self, key_bytes: bytes) -> str:
|
||||
wif_prefix = self.chainparams_network()['key_prefix']
|
||||
key_type = 0 # STEcdsaSecp256k1
|
||||
b = wif_prefix.to_bytes(2, 'big') + key_type.to_bytes(1) + key_bytes
|
||||
b = wif_prefix.to_bytes(2, 'big') + key_type.to_bytes(1, 'big') + key_bytes
|
||||
b += blake256(b)[:4]
|
||||
return b58encode(b)
|
||||
|
||||
@@ -433,7 +438,7 @@ class DCRInterface(Secp256k1Interface):
|
||||
script_hash = self.pkh(script)
|
||||
assert len(script_hash) == 20
|
||||
|
||||
return OP_HASH160.to_bytes(1) + len(script_hash).to_bytes(1) + script_hash + OP_EQUAL.to_bytes(1)
|
||||
return bytes((OP_HASH160,)) + bytes((len(script_hash),)) + script_hash + bytes((OP_EQUAL,))
|
||||
|
||||
def encodeScriptDest(self, script_dest: bytes) -> str:
|
||||
script_hash = script_dest[2:-1] # Extract hash from script
|
||||
@@ -442,7 +447,7 @@ class DCRInterface(Secp256k1Interface):
|
||||
def getPubkeyHashDest(self, pkh: bytes) -> bytes:
|
||||
# P2PKH
|
||||
assert len(pkh) == 20
|
||||
return OP_DUP.to_bytes(1) + OP_HASH160.to_bytes(1) + len(pkh).to_bytes(1) + pkh + OP_EQUALVERIFY.to_bytes(1) + OP_CHECKSIG.to_bytes(1)
|
||||
return bytes((OP_DUP,)) + bytes((OP_HASH160,)) + bytes((len(pkh),)) + pkh + bytes((OP_EQUALVERIFY,)) + bytes((OP_CHECKSIG,))
|
||||
|
||||
def getPkDest(self, K: bytes) -> bytearray:
|
||||
return self.getPubkeyHashDest(self.pkh(K))
|
||||
@@ -532,7 +537,7 @@ class DCRInterface(Secp256k1Interface):
|
||||
prove_utxos.append(outpoint)
|
||||
hasher.update(outpoint[0])
|
||||
hasher.update(outpoint[1].to_bytes(2, 'big'))
|
||||
hasher.update(outpoint[2].to_bytes(1))
|
||||
hasher.update(outpoint[2].to_bytes(1, 'big'))
|
||||
if sum_value >= amount_for:
|
||||
break
|
||||
utxos_hash = hasher.digest()
|
||||
@@ -554,7 +559,7 @@ class DCRInterface(Secp256k1Interface):
|
||||
def encodeProofUtxos(self, proof_utxos):
|
||||
packed_utxos = bytes()
|
||||
for utxo in proof_utxos:
|
||||
packed_utxos += utxo[0] + utxo[1].to_bytes(2, 'big') + utxo[2].to_bytes(1)
|
||||
packed_utxos += utxo[0] + utxo[1].to_bytes(2, 'big') + utxo[2].to_bytes(1, 'big')
|
||||
return packed_utxos
|
||||
|
||||
def decodeProofUtxos(self, msg_utxos):
|
||||
@@ -573,7 +578,7 @@ class DCRInterface(Secp256k1Interface):
|
||||
for outpoint in utxos:
|
||||
hasher.update(outpoint[0])
|
||||
hasher.update(outpoint[1].to_bytes(2, 'big'))
|
||||
hasher.update(outpoint[2].to_bytes(1))
|
||||
hasher.update(outpoint[2].to_bytes(1, 'big'))
|
||||
utxos_hash = hasher.digest()
|
||||
|
||||
passed = self.verifyMessage(address, address + '_swap_proof_' + utxos_hash.hex() + extra_commit_bytes.hex(), signature)
|
||||
@@ -841,19 +846,19 @@ class DCRInterface(Secp256k1Interface):
|
||||
Kaf_enc = Kaf if len(Kaf) == 33 else self.encodePubkey(Kaf)
|
||||
|
||||
script = bytearray()
|
||||
script += OP_IF.to_bytes(1)
|
||||
script += bytes((OP_IF,))
|
||||
push_script_data(script, bytes((2,)))
|
||||
push_script_data(script, Kal_enc)
|
||||
push_script_data(script, Kaf_enc)
|
||||
push_script_data(script, bytes((2,)))
|
||||
script += OP_CHECKMULTISIG.to_bytes(1)
|
||||
script += OP_ELSE.to_bytes(1)
|
||||
script += bytes((OP_CHECKMULTISIG,))
|
||||
script += bytes((OP_ELSE,))
|
||||
script += CScriptNum.encode(CScriptNum(csv_val))
|
||||
script += OP_CHECKSEQUENCEVERIFY.to_bytes(1)
|
||||
script += OP_DROP.to_bytes(1)
|
||||
script += bytes((OP_CHECKSEQUENCEVERIFY,))
|
||||
script += bytes((OP_DROP,))
|
||||
push_script_data(script, Kaf_enc)
|
||||
script += OP_CHECKSIG.to_bytes(1)
|
||||
script += OP_ENDIF.to_bytes(1)
|
||||
script += bytes((OP_CHECKSIG,))
|
||||
script += bytes((OP_ENDIF,))
|
||||
|
||||
return script
|
||||
|
||||
|
||||
@@ -162,7 +162,7 @@ class CTransaction:
|
||||
for txi in self.vin:
|
||||
data += txi.prevout.hash.to_bytes(32, 'little')
|
||||
data += txi.prevout.n.to_bytes(4, 'little')
|
||||
data += txi.prevout.tree.to_bytes(1)
|
||||
data += txi.prevout.tree.to_bytes(1, 'little')
|
||||
data += txi.sequence.to_bytes(4, 'little')
|
||||
|
||||
data += encode_compactsize(len(self.vout))
|
||||
|
||||
@@ -39,7 +39,7 @@ def push_script_data(data_array: bytearray, data: bytes) -> None:
|
||||
return
|
||||
|
||||
if len_data < OP_PUSHDATA1:
|
||||
data_array += len_data.to_bytes(1)
|
||||
data_array += len_data.to_bytes(1, 'little')
|
||||
elif len_data <= 0xff:
|
||||
data_array += bytes((OP_PUSHDATA1, len_data))
|
||||
elif len_data <= 0xffff:
|
||||
|
||||
50
basicswap/interface/dcr/util.py
Normal file
50
basicswap/interface/dcr/util.py
Normal file
@@ -0,0 +1,50 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2024 tecnovert
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
import os
|
||||
import select
|
||||
import subprocess
|
||||
|
||||
|
||||
def createDCRWallet(args, hex_seed, logging, delay_event):
|
||||
logging.info('Creating DCR wallet')
|
||||
(pipe_r, pipe_w) = os.pipe() # subprocess.PIPE is buffered, blocks when read
|
||||
p = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=pipe_w, stderr=pipe_w)
|
||||
|
||||
try:
|
||||
while p.poll() is None:
|
||||
while len(select.select([pipe_r], [], [], 0)[0]) == 1:
|
||||
buf = os.read(pipe_r, 1024).decode('utf-8')
|
||||
logging.debug(f'dcrwallet {buf}')
|
||||
response = None
|
||||
if 'Use the existing configured private passphrase' in buf:
|
||||
response = b'y\n'
|
||||
elif 'Do you want to add an additional layer of encryption' in buf:
|
||||
response = b'n\n'
|
||||
elif 'Do you have an existing wallet seed' in buf:
|
||||
response = b'y\n'
|
||||
elif 'Enter existing wallet seed' in buf:
|
||||
response = (hex_seed + '\n').encode('utf-8')
|
||||
elif 'Seed input successful' in buf:
|
||||
pass
|
||||
elif 'Upgrading database from version' in buf:
|
||||
pass
|
||||
elif 'Ticket commitments db upgrade done' in buf:
|
||||
pass
|
||||
else:
|
||||
raise ValueError(f'Unexpected output: {buf}')
|
||||
if response is not None:
|
||||
p.stdin.write(response)
|
||||
p.stdin.flush()
|
||||
delay_event.wait(0.1)
|
||||
except Exception as e:
|
||||
logging.error(f'dcrwallet --create failed: {e}')
|
||||
finally:
|
||||
if p.poll() is None:
|
||||
p.terminate()
|
||||
os.close(pipe_r)
|
||||
os.close(pipe_w)
|
||||
p.stdin.close()
|
||||
@@ -42,9 +42,6 @@ class FIROInterface(BTCInterface):
|
||||
# No multiwallet support
|
||||
self.rpc_wallet = make_rpc_func(self._rpcport, self._rpcauth, host=self._rpc_host)
|
||||
|
||||
def checkWallets(self) -> int:
|
||||
return 1
|
||||
|
||||
def getExchangeName(self, exchange_name):
|
||||
return 'zcoin'
|
||||
|
||||
|
||||
@@ -73,9 +73,6 @@ class NAVInterface(BTCInterface):
|
||||
# No multiwallet support
|
||||
self.rpc_wallet = make_rpc_func(self._rpcport, self._rpcauth, host=self._rpc_host)
|
||||
|
||||
def checkWallets(self) -> int:
|
||||
return 1
|
||||
|
||||
def use_p2shp2wsh(self) -> bool:
|
||||
# p2sh-p2wsh
|
||||
return True
|
||||
|
||||
@@ -35,9 +35,6 @@ class PIVXInterface(BTCInterface):
|
||||
# No multiwallet support
|
||||
self.rpc_wallet = make_rpc_func(self._rpcport, self._rpcauth, host=self._rpc_host)
|
||||
|
||||
def checkWallets(self) -> int:
|
||||
return 1
|
||||
|
||||
def signTxWithWallet(self, tx):
|
||||
rv = self.rpc('signrawtransaction', [tx.hex()])
|
||||
return bytes.fromhex(rv['hex'])
|
||||
|
||||
@@ -129,9 +129,6 @@ class XMRInterface(CoinInterface):
|
||||
self.rpc2 = make_xmr_rpc2_func(coin_settings['rpcport'], daemon_login, host=rpchost, proxy_host=proxy_host, proxy_port=proxy_port, default_timeout=self._rpctimeout, tag='Node ') # non-json endpoint
|
||||
self.rpc_wallet = make_xmr_rpc_func(coin_settings['walletrpcport'], coin_settings['walletrpcauth'], host=coin_settings.get('walletrpchost', '127.0.0.1'), default_timeout=self._walletrpctimeout, tag='Wallet ')
|
||||
|
||||
def checkWallets(self) -> int:
|
||||
return 1
|
||||
|
||||
def setFeePriority(self, new_priority):
|
||||
ensure(new_priority >= 0 and new_priority < 4, 'Invalid fee_priority value')
|
||||
self._fee_priority = new_priority
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{% include 'header.html' %}
|
||||
{% from 'style.html' import select_box_arrow_svg, select_box_class, circular_arrows_svg, circular_error_svg, circular_info_svg, cross_close_svg, breadcrumb_line_svg, withdraw_svg, utxo_groups_svg, create_utxo_svg, red_cross_close_svg, blue_cross_close_svg, circular_update_messages_svg, circular_error_messages_svg %}
|
||||
{% from 'style.html' import select_box_arrow_svg, select_box_class, circular_arrows_svg, circular_error_svg, circular_info_svg, cross_close_svg, breadcrumb_line_svg, withdraw_svg, utxo_groups_svg, create_utxo_svg, red_cross_close_svg, blue_cross_close_svg, circular_update_messages_svg, circular_error_messages_svg %}
|
||||
<script src="/static/js/libs//qrcode.js"></script>
|
||||
<div class="container mx-auto">
|
||||
<section class="p-5 mt-5">
|
||||
@@ -27,7 +27,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% include 'inc_messages.html' %}
|
||||
{% include 'inc_messages.html' %}
|
||||
{% if w.updating %}
|
||||
<section class="py-4" id="messages_updating" role="alert">
|
||||
<div class="container px-4 mx-auto">
|
||||
@@ -42,7 +42,7 @@
|
||||
<li class="font-semibold text-sm text-blue-500 error_msg"><span class="bold">UPDATING:</span></li>
|
||||
<li class="font-medium text-sm text-blue-500">Please wait...</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-auto p-2">
|
||||
<button type="button" class="ms-auto bg-blue-50 text-blue-500 rounded-lg focus:ring-0 focus:ring-blue-400 p-1.5 hover:bg-blue-200 inline-flex items-center justify-center h-8 w-8 focus:outline-none dark:bg-gray-800 dark:text-blue-400 dark:hover:bg-gray-700" data-dismiss-target="#messages_updating" aria-label="Close"><span class="sr-only">Close</span>
|
||||
@@ -55,7 +55,7 @@
|
||||
</section>
|
||||
{% endif %}
|
||||
{% if w.havedata %}
|
||||
{% if w.error %}
|
||||
{% if w.error %}
|
||||
<section class="py-4" id="messages_error" role="alert">
|
||||
<div class="container px-4 mx-auto">
|
||||
<div class="p-6 text-green-800 rounded-lg bg-red-50 border border-red-400 dark:bg-gray-500 dark:text-red-400 rounded-md">
|
||||
@@ -113,7 +113,7 @@
|
||||
</tr> {% if w.cid == '1' %} {# PART #}
|
||||
<tr class="opacity-100 text-gray-500 dark:text-gray-100 hover:bg-coolGray-200 dark:hover:bg-gray-600">
|
||||
<td class="py-3 px-6 bold"> <span class="inline-flex align-middle items-center justify-center w-9 h-10 bg-white-50 rounded"> <img class="h-7" src="/static/images/coins/{{ w.name }}.png" alt="{{ w.name }} Blind"> </span>Blind Balance: </td>
|
||||
<td class="py-3 px-6 bold coinname-value" data-coinname="{{ w.name }}">{{ w.blind_balance }} {{ w.ticker }} (<span class="usd-value"></span>)
|
||||
<td class="py-3 px-6 bold coinname-value" data-coinname="{{ w.name }}">{{ w.blind_balance }} {{ w.ticker }} (<span class="usd-value"></span>)
|
||||
{% if w.blind_unconfirmed %}
|
||||
<span class="inline-block py-1 px-2 rounded-full bg-green-100 text-green-500 dark:bg-gray-500 dark:text-green-500">Unconfirmed: +{{ w.blind_unconfirmed }} {{ w.ticker }}</span>
|
||||
{% endif %}
|
||||
@@ -136,11 +136,11 @@
|
||||
<td class="py-3 px-6 bold coinname-value" data-coinname="{{ w.name }}">{{ w.mweb_balance }} {{ w.ticker }} (<span class="usd-value"></span>)
|
||||
{% if w.mweb_pending %}
|
||||
<span class="inline-block py-1 px-2 rounded-full bg-green-100 text-green-500 dark:bg-gray-500 dark:text-green-500">Pending: +{{ w.mweb_pending }} {{ w.ticker }} </span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{# / LTC #}
|
||||
{# / LTC #}
|
||||
{% if w.locked_utxos %}
|
||||
<tr class="opacity-100 text-gray-500 dark:text-gray-100 hover:bg-coolGray-200 dark:hover:bg-gray-600">
|
||||
<td class="py-3 px-6 bold">Locked Outputs:</td>
|
||||
@@ -202,9 +202,11 @@
|
||||
<div class="container mt-5 mx-auto">
|
||||
<div class="pt-6 pb-6 bg-coolGray-100 dark:bg-gray-500 rounded-xl">
|
||||
<div class="px-6">
|
||||
{% if w.cid != '4' %} {# DCR #}
|
||||
<div class="flex flex-wrap justify-end">
|
||||
<div class="w-full md:w-auto p-1.5"> <input class="flex flex-wrap justify-center w-full px-4 py-2.5 font-medium text-sm text-white hover:text-red border border-red-500 hover:border-red-500 hover:bg-red-600 bg-red-500 rounded-md shadow-button focus:ring-0 focus:outline-none cursor-pointer" type="submit" name="reseed_{{ w.cid }}" value="Reseed wallet" onclick="return confirmReseed();"> </div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -369,7 +371,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{# / LTC #}
|
||||
</div>
|
||||
</div>
|
||||
@@ -383,7 +385,7 @@
|
||||
<script>
|
||||
// Particl Stealth
|
||||
var stealthAddress = "{{ w.stealth_address }}";
|
||||
|
||||
|
||||
var qrCodeStealth = new QRCode(document.getElementById("qrcode-stealth"), {
|
||||
text: stealthAddress,
|
||||
width: 170,
|
||||
@@ -399,7 +401,7 @@
|
||||
<script>
|
||||
// Litecoin MWEB
|
||||
var mwebAddress = "{{ w.mweb_address }}";
|
||||
|
||||
|
||||
var qrCodeMWEB = new QRCode(document.getElementById("qrcode-mweb"), {
|
||||
text: mwebAddress,
|
||||
width: 170,
|
||||
@@ -408,14 +410,14 @@
|
||||
colorLight: "#ffffff",
|
||||
correctLevel: QRCode.CorrectLevel.L
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
{% endif %}
|
||||
{% if w.cid == '6' %}
|
||||
{# XMR #}
|
||||
<script>
|
||||
// Monero Sub
|
||||
var moneroSubAddress = "{{ w.deposit_address }}";
|
||||
|
||||
|
||||
var qrCodeMoneroSub = new QRCode(document.getElementById("qrcode-monero-sub"), {
|
||||
text: moneroSubAddress,
|
||||
width: 170,
|
||||
@@ -428,7 +430,7 @@
|
||||
<script>
|
||||
// Monero Main
|
||||
var moneroMainAddress = "{{ w.main_address }}";
|
||||
|
||||
|
||||
var qrCodeMoneroMain = new QRCode(document.getElementById("qrcode-monero-main"), {
|
||||
text: moneroMainAddress,
|
||||
width: 170,
|
||||
@@ -442,7 +444,7 @@
|
||||
<script>
|
||||
// Default
|
||||
var defaultAddress = "{{ w.deposit_address }}";
|
||||
|
||||
|
||||
var qrCodeDepost = new QRCode(document.getElementById("qrcode-deposit"), {
|
||||
text: defaultAddress,
|
||||
width: 170,
|
||||
@@ -462,48 +464,48 @@
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(el);
|
||||
}
|
||||
|
||||
|
||||
function copyAndShowMessage(elementId) {
|
||||
const addressElement = document.getElementById(elementId);
|
||||
if (!addressElement) return;
|
||||
const addressText = addressElement.innerText.trim();
|
||||
copyToClipboard(addressText);
|
||||
addressElement.innerText = 'Copied to clipboard';
|
||||
|
||||
|
||||
const originalWidth = addressElement.offsetWidth;
|
||||
|
||||
|
||||
addressElement.classList.add('copying');
|
||||
|
||||
|
||||
addressElement.parentElement.style.width = `${originalWidth}px`;
|
||||
|
||||
|
||||
setTimeout(function () {
|
||||
addressElement.innerText = addressText;
|
||||
addressElement.classList.remove('copying');
|
||||
addressElement.parentElement.style.width = '';
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
|
||||
const stealthAddressElement = document.getElementById('stealth_address');
|
||||
if (stealthAddressElement) {
|
||||
stealthAddressElement.addEventListener('click', function () {
|
||||
copyAndShowMessage('stealth_address');
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
const mainDepositAddressElement = document.getElementById('main_deposit_address');
|
||||
if (mainDepositAddressElement) {
|
||||
mainDepositAddressElement.addEventListener('click', function () {
|
||||
copyAndShowMessage('main_deposit_address');
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
const moneroMainAddressElement = document.getElementById('monero_main_address');
|
||||
if (moneroMainAddressElement) {
|
||||
moneroMainAddressElement.addEventListener('click', function () {
|
||||
copyAndShowMessage('monero_main_address');
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
const moneroSubAddressElement = document.getElementById('monero_sub_address');
|
||||
if (moneroSubAddressElement) {
|
||||
moneroSubAddressElement.addEventListener('click', function () {
|
||||
@@ -572,7 +574,7 @@
|
||||
var selectedType = typeSelect.value;
|
||||
var floatBalance;
|
||||
var calculatedAmount;
|
||||
|
||||
|
||||
switch(selectedType) {
|
||||
case 'plain':
|
||||
floatBalance = parseFloat(balance);
|
||||
@@ -591,7 +593,7 @@
|
||||
calculatedAmount = floatBalance * percent;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
amountInput.value = calculatedAmount.toFixed(8);
|
||||
}
|
||||
</script>
|
||||
@@ -606,7 +608,7 @@
|
||||
var selectedType = typeSelect.value;
|
||||
var floatBalance;
|
||||
var calculatedAmount;
|
||||
|
||||
|
||||
switch(selectedType) {
|
||||
case 'plain':
|
||||
floatBalance = parseFloat(balance);
|
||||
@@ -621,7 +623,7 @@
|
||||
calculatedAmount = floatBalance * percent;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
amountInput.value = calculatedAmount.toFixed(8);
|
||||
}
|
||||
</script>
|
||||
@@ -633,10 +635,10 @@
|
||||
var amountInput = document.getElementById('amount');
|
||||
var floatBalance;
|
||||
var calculatedAmount;
|
||||
|
||||
|
||||
floatBalance = parseFloat(balance);
|
||||
calculatedAmount = floatBalance * percent;
|
||||
|
||||
|
||||
if (cid === '6' && percent === 1) {
|
||||
amountInput.setAttribute('data-hidden', 'true');
|
||||
amountInput.placeholder = 'Sweep All';
|
||||
@@ -652,7 +654,7 @@
|
||||
amountInput.placeholder = '';
|
||||
amountInput.disabled = false;
|
||||
}
|
||||
|
||||
|
||||
if (cid === '6' && percent === 1) {
|
||||
var sweepAllCheckbox = document.getElementById('sweepall');
|
||||
if (sweepAllCheckbox) {
|
||||
@@ -665,7 +667,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -677,7 +679,7 @@
|
||||
<td class="py-3 px-6"> <input class="hover:border-blue-500 w-5 h-5 form-check-input text-blue-600 bg-gray-50 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-1 dark:bg-gray-500 dark:border-gray-400" type="checkbox" id="sweepall" name="sweepall_{{ w.cid }}" {% if w.wd_sweepall==true %} checked=checked{% endif %}> </td> {% else %} <td class="py-3 px-6 bold">Subtract Fee:</td>
|
||||
<td class="py-3 px-6"> <input class="hover:border-blue-500 w-5 h-5 form-check-input text-blue-600 bg-gray-50 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-1 dark:bg-gray-500 dark:border-gray-400" type="checkbox" name="subfee_{{ w.cid }}" {% if w.wd_subfee==true %} checked=checked{% endif %}> </td>
|
||||
{% endif %}
|
||||
<td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
{% if w.cid == '1' %}
|
||||
@@ -855,7 +857,7 @@
|
||||
'DECRED': 'DCR',
|
||||
'WOWNERO': 'WOW'
|
||||
};
|
||||
|
||||
|
||||
const getUsdValue = (cryptoValue, coinSymbol) => fetch(`https://min-api.cryptocompare.com/data/price?fsym=${coinSymbol}&tsyms=USD`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
@@ -866,16 +868,16 @@
|
||||
throw new Error(`Invalid exchange rate for ${coinSymbol}`);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
const updateUsdValue = async (cryptoCell, coinFullName, usdValueSpan) => {
|
||||
const coinSymbol = coinNameToSymbol[coinFullName] || '';
|
||||
if (!coinSymbol) {
|
||||
console.error(`Coin symbol not found for full name: ${coinFullName}`);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const cryptoValue = parseFloat(cryptoCell.textContent);
|
||||
|
||||
|
||||
if (!isNaN(cryptoValue) && cryptoValue !== 0) {
|
||||
try {
|
||||
const usdValue = await getUsdValue(cryptoValue, coinSymbol);
|
||||
@@ -894,19 +896,19 @@
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const calculateTotalUsdValue = async () => {
|
||||
const coinNameValues = document.querySelectorAll('.coinname-value');
|
||||
let totalUsdValue = 0;
|
||||
|
||||
|
||||
for (const coinNameValue of coinNameValues) {
|
||||
const coinFullName = coinNameValue.getAttribute('data-coinname');
|
||||
const cryptoValue = parseFloat(coinNameValue.textContent);
|
||||
const coinSymbol = coinNameToSymbol[coinFullName];
|
||||
|
||||
|
||||
if (coinSymbol) {
|
||||
const usdValueSpan = coinNameValue.querySelector('.usd-value');
|
||||
|
||||
|
||||
if (!isNaN(cryptoValue) && cryptoValue !== 0) {
|
||||
try {
|
||||
const usdValue = await getUsdValue(cryptoValue, coinSymbol);
|
||||
@@ -926,24 +928,24 @@
|
||||
console.error(`Coin symbol not found for full name: ${coinFullName}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const totalUsdValueElement = document.getElementById('total-usd-value');
|
||||
if (totalUsdValueElement) {
|
||||
totalUsdValueElement.textContent = `$${totalUsdValue.toFixed(2)}`;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const coinNameValues = document.querySelectorAll('.coinname-value');
|
||||
|
||||
|
||||
for (const coinNameValue of coinNameValues) {
|
||||
const coinFullName = coinNameValue.getAttribute('data-coinname');
|
||||
const usdValueSpan = coinNameValue.querySelector('.usd-value');
|
||||
updateUsdValue(coinNameValue, coinFullName, usdValueSpan);
|
||||
}
|
||||
|
||||
|
||||
calculateTotalUsdValue();
|
||||
|
||||
|
||||
function set_sweep_all(element) {
|
||||
let input = document.getElementById('amount');
|
||||
if (element.checked) {
|
||||
@@ -952,7 +954,7 @@
|
||||
input.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let cb_sweepall = document.getElementById('sweepall');
|
||||
if (cb_sweepall) {
|
||||
set_sweep_all(cb_sweepall);
|
||||
@@ -960,7 +962,7 @@
|
||||
set_sweep_all(event.currentTarget);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
</script>
|
||||
{% include 'footer.html' %}
|
||||
@@ -968,11 +970,11 @@
|
||||
function confirmReseed() {
|
||||
return confirm("Are you sure?\nBackup your wallet before and after.\nWon't detect used keys.\nShould only be used for new wallets.");
|
||||
}
|
||||
|
||||
|
||||
function confirmWithdrawal() {
|
||||
return confirm("Are you sure?");
|
||||
}
|
||||
|
||||
|
||||
function confirmUTXOResize() {
|
||||
return confirm("Are you sure?");
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ from coincurve.keys import (
|
||||
|
||||
|
||||
def BIP32Hash(chaincode: bytes, child_no: int, key_data_type: int, keydata: bytes):
|
||||
return hmac_sha512(chaincode, key_data_type.to_bytes(1) + keydata + child_no.to_bytes(4, 'big'))
|
||||
return hmac_sha512(chaincode, key_data_type.to_bytes(1, 'big') + keydata + child_no.to_bytes(4, 'big'))
|
||||
|
||||
|
||||
def hash160_dcr(data: bytes) -> bytes:
|
||||
@@ -85,7 +85,7 @@ class ExtKeyPair():
|
||||
return out
|
||||
|
||||
def encode_v(self) -> bytes:
|
||||
return self._depth.to_bytes(1) + \
|
||||
return self._depth.to_bytes(1, 'big') + \
|
||||
self._fingerprint + \
|
||||
self._child_no.to_bytes(4, 'big') + \
|
||||
self._chaincode + \
|
||||
@@ -94,7 +94,7 @@ class ExtKeyPair():
|
||||
|
||||
def encode_p(self) -> bytes:
|
||||
pubkey = PublicKey.from_secret(self._key).format() if self._pubkey is None else self._pubkey
|
||||
return self._depth.to_bytes(1) + \
|
||||
return self._depth.to_bytes(1, 'big') + \
|
||||
self._fingerprint + \
|
||||
self._child_no.to_bytes(4, 'big') + \
|
||||
self._chaincode + \
|
||||
|
||||
Reference in New Issue
Block a user