mirror of
https://github.com/basicswap/basicswap.git
synced 2026-04-13 12:37:23 +02:00
Compare commits
23 Commits
d8e741f2b1
...
release-v0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
151960af3c | ||
|
|
83807d213f | ||
|
|
8d150f0ea8 | ||
|
|
569f4290d0 | ||
|
|
e5023eda33 | ||
|
|
d17560833e | ||
|
|
f577f84f09 | ||
|
|
f668c38cd6 | ||
|
|
f259c18f73 | ||
|
|
486619c2cd | ||
|
|
6ea52611eb | ||
|
|
c41ab51cfc | ||
|
|
bafbff643c | ||
|
|
aad4d0522c | ||
|
|
d4d781bebb | ||
|
|
f52b100cff | ||
|
|
985df85394 | ||
|
|
5b5d72e145 | ||
|
|
2c42629807 | ||
|
|
1687d82cbc | ||
|
|
7ee1cea4eb | ||
|
|
caaad818ef | ||
|
|
0bf4af100a |
@@ -1,3 +1,3 @@
|
||||
name = "basicswap"
|
||||
|
||||
__version__ = "0.15.2"
|
||||
__version__ = "0.15.3"
|
||||
|
||||
@@ -2955,10 +2955,12 @@ class BasicSwap(BaseApp, BSXNetwork, UIApp):
|
||||
self.log.info_s(f"In txn: {txid}")
|
||||
return txid
|
||||
|
||||
def withdrawLTC(self, type_from, value, addr_to, subfee: bool) -> str:
|
||||
ci = self.ci(Coins.LTC)
|
||||
def withdrawCoinExtended(
|
||||
self, coin_type, type_from, value, addr_to, subfee: bool
|
||||
) -> str:
|
||||
ci = self.ci(coin_type)
|
||||
self.log.info(
|
||||
"withdrawLTC{}".format(
|
||||
"withdrawCoinExtended{}".format(
|
||||
""
|
||||
if self.log.safe_logs
|
||||
else " {} {} to {} {}".format(
|
||||
@@ -11676,6 +11678,27 @@ class BasicSwap(BaseApp, BSXNetwork, UIApp):
|
||||
rv["mweb_pending"] = (
|
||||
walletinfo["mweb_unconfirmed"] + walletinfo["mweb_immature"]
|
||||
)
|
||||
elif coin == Coins.FIRO:
|
||||
try:
|
||||
rv["spark_address"] = self.getCachedStealthAddressForCoin(
|
||||
Coins.FIRO
|
||||
)
|
||||
except Exception as e:
|
||||
self.log.warning(
|
||||
f"getCachedStealthAddressForCoin for {ci.coin_name()} failed with: {e}."
|
||||
)
|
||||
# Spark balances are in atomic units, format them
|
||||
rv["spark_balance"] = (
|
||||
0
|
||||
if walletinfo["spark_balance"] == 0
|
||||
else ci.format_amount(walletinfo["spark_balance"])
|
||||
)
|
||||
spark_pending_int = (
|
||||
walletinfo["spark_unconfirmed"] + walletinfo["spark_immature"]
|
||||
)
|
||||
rv["spark_pending"] = (
|
||||
0 if spark_pending_int == 0 else ci.format_amount(spark_pending_int)
|
||||
)
|
||||
|
||||
return rv
|
||||
except Exception as e:
|
||||
@@ -11798,6 +11821,8 @@ class BasicSwap(BaseApp, BSXNetwork, UIApp):
|
||||
if row2[0].startswith("stealth"):
|
||||
if coin_id == Coins.LTC:
|
||||
wallet_data["mweb_address"] = row2[1]
|
||||
elif coin_id == Coins.FIRO:
|
||||
wallet_data["spark_address"] = row2[1]
|
||||
else:
|
||||
wallet_data["stealth_address"] = row2[1]
|
||||
else:
|
||||
|
||||
@@ -55,22 +55,22 @@ PARTICL_VERSION = os.getenv("PARTICL_VERSION", "27.2.3.0")
|
||||
PARTICL_VERSION_TAG = os.getenv("PARTICL_VERSION_TAG", "")
|
||||
PARTICL_LINUX_EXTRA = os.getenv("PARTICL_LINUX_EXTRA", "nousb")
|
||||
|
||||
BITCOIN_VERSION = os.getenv("BITCOIN_VERSION", "29.2")
|
||||
BITCOIN_VERSION = os.getenv("BITCOIN_VERSION", "29.3")
|
||||
BITCOIN_VERSION_TAG = os.getenv("BITCOIN_VERSION_TAG", "")
|
||||
|
||||
LITECOIN_VERSION = os.getenv("LITECOIN_VERSION", "0.21.4")
|
||||
LITECOIN_VERSION_TAG = os.getenv("LITECOIN_VERSION_TAG", "")
|
||||
|
||||
DCR_VERSION = os.getenv("DCR_VERSION", "2.1.2")
|
||||
DCR_VERSION = os.getenv("DCR_VERSION", "2.1.3")
|
||||
DCR_VERSION_TAG = os.getenv("DCR_VERSION_TAG", "")
|
||||
|
||||
NMC_VERSION = os.getenv("NMC_VERSION", "28.0")
|
||||
NMC_VERSION_TAG = os.getenv("NMC_VERSION_TAG", "")
|
||||
|
||||
MONERO_VERSION = os.getenv("MONERO_VERSION", "0.18.4.4")
|
||||
MONERO_VERSION = os.getenv("MONERO_VERSION", "0.18.4.5")
|
||||
MONERO_VERSION_TAG = os.getenv("MONERO_VERSION_TAG", "")
|
||||
XMR_SITE_COMMIT = (
|
||||
"a1bd4cd48a85b6012de20d9e490f83936f477be2" # Lock hashes.txt to monero version
|
||||
"1bfa07c1b54f4f39a93096e3bfb746cb21249422" # Lock hashes.txt to monero version
|
||||
)
|
||||
|
||||
WOWNERO_VERSION = os.getenv("WOWNERO_VERSION", "0.11.3.0")
|
||||
@@ -82,16 +82,16 @@ WOW_SITE_COMMIT = (
|
||||
PIVX_VERSION = os.getenv("PIVX_VERSION", "5.6.1")
|
||||
PIVX_VERSION_TAG = os.getenv("PIVX_VERSION_TAG", "")
|
||||
|
||||
DASH_VERSION = os.getenv("DASH_VERSION", "22.1.3")
|
||||
DASH_VERSION = os.getenv("DASH_VERSION", "23.1.2")
|
||||
DASH_VERSION_TAG = os.getenv("DASH_VERSION_TAG", "")
|
||||
|
||||
FIRO_VERSION = os.getenv("FIRO_VERSION", "0.14.15.0")
|
||||
FIRO_VERSION = os.getenv("FIRO_VERSION", "0.14.15.3")
|
||||
FIRO_VERSION_TAG = os.getenv("FIRO_VERSION_TAG", "")
|
||||
|
||||
NAV_VERSION = os.getenv("NAV_VERSION", "7.0.3")
|
||||
NAV_VERSION_TAG = os.getenv("NAV_VERSION_TAG", "")
|
||||
|
||||
BITCOINCASH_VERSION = os.getenv("BITCOINCASH_VERSION", "28.0.1")
|
||||
BITCOINCASH_VERSION = os.getenv("BITCOINCASH_VERSION", "29.0.0")
|
||||
BITCOINCASH_VERSION_TAG = os.getenv("BITCOINCASH_VERSION_TAG", "")
|
||||
|
||||
DOGECOIN_VERSION = os.getenv("DOGECOIN_VERSION", "23.2.1")
|
||||
@@ -1757,15 +1757,15 @@ def printHelp():
|
||||
|
||||
|
||||
def finalise_daemon(d):
|
||||
logging.info("Interrupting {}".format(d.handle.pid))
|
||||
logging.info(f"Interrupting {d.name} {d.handle.pid}")
|
||||
try:
|
||||
d.handle.send_signal(signal.CTRL_C_EVENT if os.name == "nt" else signal.SIGINT)
|
||||
d.handle.wait(timeout=120)
|
||||
for fp in [d.handle.stdout, d.handle.stderr, d.handle.stdin] + d.files:
|
||||
if fp:
|
||||
fp.close()
|
||||
except Exception as e:
|
||||
logging.info(f"Error {e} for process {d.handle.pid}")
|
||||
for fp in [d.handle.stdout, d.handle.stderr, d.handle.stdin] + d.files:
|
||||
if fp:
|
||||
fp.close()
|
||||
logging.info(f"Error stopping {d.name}, process {d.handle.pid}: {e}")
|
||||
|
||||
|
||||
def test_particl_encryption(data_dir, settings, chain, use_tor_proxy, extra_opts):
|
||||
|
||||
@@ -618,7 +618,7 @@ def runClient(
|
||||
signal.CTRL_C_EVENT if os.name == "nt" else signal.SIGINT
|
||||
)
|
||||
except Exception as e:
|
||||
swap_client.log.info(f"Interrupting {d.name} {d.handle.pid}, error {e}")
|
||||
swap_client.log.error(f"Interrupting {d.name} {d.handle.pid}: {e}")
|
||||
for d in daemons:
|
||||
try:
|
||||
d.handle.wait(timeout=120)
|
||||
@@ -627,7 +627,9 @@ def runClient(
|
||||
fp.close()
|
||||
closed_pids.append(d.handle.pid)
|
||||
except Exception as e:
|
||||
swap_client.log.error(f"Error: {e}")
|
||||
swap_client.log.error(
|
||||
f"Waiting for {d.name} {d.handle.pid} to shutdown: {e}"
|
||||
)
|
||||
|
||||
fail_code: int = swap_client.fail_code
|
||||
del swap_client
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2022-2023 tecnovert
|
||||
# Copyright (c) 2024-2025 The Basicswap developers
|
||||
# Copyright (c) 2024-2026 The Basicswap developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
@@ -102,6 +102,100 @@ class FIROInterface(BTCInterface):
|
||||
return addr_info["ismine"]
|
||||
return addr_info["ismine"] or addr_info["iswatchonly"]
|
||||
|
||||
def getNewSparkAddress(self) -> str:
|
||||
try:
|
||||
return self.rpc_wallet("getnewsparkaddress")[0]
|
||||
except Exception as e:
|
||||
self._log.error(f"getnewsparkaddress failed: {str(e)}")
|
||||
raise
|
||||
|
||||
def getNewStealthAddress(self):
|
||||
"""Get a new Spark address (alias for consistency with other coins)."""
|
||||
return self.getNewSparkAddress()
|
||||
|
||||
def getWalletInfo(self):
|
||||
"""Get wallet info including Spark balance."""
|
||||
rv = super(FIROInterface, self).getWalletInfo()
|
||||
try:
|
||||
spark_balance_info = self.rpc("getsparkbalance")
|
||||
# getsparkbalance returns amounts in atomic units (satoshis)
|
||||
# Field names: availableBalance, unconfirmedBalance, fullBalance
|
||||
confirmed = spark_balance_info.get("availableBalance", 0)
|
||||
unconfirmed = spark_balance_info.get("unconfirmedBalance", 0)
|
||||
full_balance = spark_balance_info.get("fullBalance", 0)
|
||||
# Values are already in atomic units, keep as integers
|
||||
# basicswap.py will format them using format_amount
|
||||
rv["spark_balance"] = confirmed if confirmed else 0
|
||||
rv["spark_unconfirmed"] = unconfirmed if unconfirmed else 0
|
||||
immature = full_balance - confirmed - unconfirmed
|
||||
rv["spark_immature"] = immature if immature > 0 else 0
|
||||
except Exception as e:
|
||||
self._log.warning(f"getsparkbalance failed: {str(e)}")
|
||||
rv["spark_balance"] = 0
|
||||
rv["spark_unconfirmed"] = 0
|
||||
rv["spark_immature"] = 0
|
||||
return rv
|
||||
|
||||
def createUTXO(self, value_sats: int):
|
||||
# Create a new address and send value_sats to it
|
||||
|
||||
spendable_balance = self.getSpendableBalance()
|
||||
if spendable_balance < value_sats:
|
||||
raise ValueError("Balance too low")
|
||||
|
||||
address = self.getNewAddress(self._use_segwit, "create_utxo")
|
||||
return (
|
||||
self.withdrawCoin(self.format_amount(value_sats), "plain", address, False),
|
||||
address,
|
||||
)
|
||||
|
||||
def withdrawCoin(self, value, type_from: str, addr_to: str, subfee: bool) -> str:
|
||||
"""Withdraw coins, supporting both transparent and Spark transactions.
|
||||
|
||||
Args:
|
||||
value: Amount to withdraw
|
||||
type_from: "plain" for transparent, "spark" for Spark
|
||||
addr_to: Destination address
|
||||
subfee: Whether to subtract fee from amount
|
||||
"""
|
||||
type_to = "spark" if addr_to.startswith("sm1") else "plain"
|
||||
|
||||
if "spark" in (type_from, type_to):
|
||||
# RPC format: spendspark {"address": {"amount": ..., "subtractfee": ..., "memo": ...}}
|
||||
# RPC wrapper will serialize this as: {"method": "spendspark", "params": [{...}], ...}
|
||||
try:
|
||||
if type_from == "spark":
|
||||
# Construct params: dict where address is the key, wrapped in array for RPC
|
||||
params = [
|
||||
{"address": addr_to, "amount": value, "subtractfee": subfee}
|
||||
]
|
||||
result = self.rpc_wallet("spendspark", params)
|
||||
else:
|
||||
# Use automintspark to perform a plain -> spark tx of full balance
|
||||
balance = self.rpc_wallet("getbalance")
|
||||
if str(balance) == str(value):
|
||||
result = self.rpc_wallet("automintspark")
|
||||
else:
|
||||
# subfee param is available on plain -> spark transactions
|
||||
mint_params = {"amount": value}
|
||||
if subfee:
|
||||
mint_params["subfee"] = True
|
||||
params = [{addr_to: mint_params}]
|
||||
result = self.rpc_wallet("mintspark", params)
|
||||
# spendspark returns a txid string directly, in a result dict, or as an array
|
||||
if isinstance(result, list) and len(result) > 0:
|
||||
return result[0]
|
||||
if isinstance(result, dict):
|
||||
return result.get("txid", result.get("tx", ""))
|
||||
return result
|
||||
except Exception as e:
|
||||
self._log.error(f"spark tx failed: {str(e)}")
|
||||
raise
|
||||
else:
|
||||
# Use standard sendtoaddress for transparent transactions
|
||||
params = [addr_to, value, "", "", subfee]
|
||||
return self.rpc_wallet("sendtoaddress", params)
|
||||
|
||||
def getSCLockScriptAddress(self, lock_script: bytes) -> str:
|
||||
lock_tx_dest = self.getScriptDest(lock_script)
|
||||
address = self.encodeScriptDest(lock_tx_dest)
|
||||
@@ -252,10 +346,6 @@ class FIROInterface(BTCInterface):
|
||||
assert len(script_hash) == 20
|
||||
return CScript([OP_HASH160, script_hash, OP_EQUAL])
|
||||
|
||||
def withdrawCoin(self, value, addr_to, subfee):
|
||||
params = [addr_to, value, "", "", subfee]
|
||||
return self.rpc("sendtoaddress", params)
|
||||
|
||||
def getWalletSeedID(self):
|
||||
return self.rpc("getwalletinfo")["hdmasterkeyid"]
|
||||
|
||||
|
||||
@@ -79,9 +79,11 @@ def withdraw_coin(swap_client, coin_type, post_string, is_json):
|
||||
txid_hex = swap_client.withdrawParticl(
|
||||
type_from, type_to, value, address, subfee
|
||||
)
|
||||
elif coin_type == Coins.LTC:
|
||||
elif coin_type in (Coins.LTC, Coins.FIRO):
|
||||
type_from = get_data_entry_or(post_data, "type_from", "plain")
|
||||
txid_hex = swap_client.withdrawLTC(type_from, value, address, subfee)
|
||||
txid_hex = swap_client.withdrawCoinExtended(
|
||||
coin_type, type_from, value, address, subfee
|
||||
)
|
||||
elif coin_type in (Coins.XMR, Coins.WOW):
|
||||
txid_hex = swap_client.withdrawCoin(coin_type, value, address, sweepall)
|
||||
else:
|
||||
|
||||
@@ -23,6 +23,11 @@
|
||||
types: ['default'],
|
||||
hasSubfee: false,
|
||||
hasSweepAll: true
|
||||
},
|
||||
13: {
|
||||
types: ['plain', 'spark'],
|
||||
hasSubfee: true,
|
||||
hasSweepAll: false
|
||||
}
|
||||
},
|
||||
|
||||
@@ -64,6 +69,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
if (cid === 13) {
|
||||
switch(selectedType) {
|
||||
case 'plain':
|
||||
return this.safeParseFloat(balances.main || balances.balance);
|
||||
case 'spark':
|
||||
return this.safeParseFloat(balances.spark);
|
||||
default:
|
||||
return this.safeParseFloat(balances.main || balances.balance);
|
||||
}
|
||||
}
|
||||
|
||||
return this.safeParseFloat(balances.main || balances.balance);
|
||||
},
|
||||
|
||||
@@ -188,7 +204,8 @@
|
||||
balance: balance,
|
||||
blind: balance2,
|
||||
anon: balance3,
|
||||
mweb: balance2
|
||||
mweb: balance2,
|
||||
spark: balance2
|
||||
};
|
||||
WalletAmountManager.setAmount(percent, balances, coinId);
|
||||
};
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
</section>
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
{% if w.havedata %}
|
||||
{% if w.error %}
|
||||
<section class="py-4 px-6" id="messages_error" role="alert">
|
||||
@@ -146,8 +148,20 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% elif w.cid == '13' %} {# FIRO #}
|
||||
<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 }} Spark"> </span>Spark Balance: </td>
|
||||
<td class="py-3 px-6 bold">
|
||||
<span class="coinname-value" data-coinname="{{ w.name }}">{{ w.spark_balance }} {{ w.ticker }}</span>
|
||||
(<span class="usd-value"></span>)
|
||||
{% if w.spark_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.spark_pending }} {{ w.ticker }} </span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{# / LTC #}
|
||||
{# / FIRO #}
|
||||
{% 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>
|
||||
@@ -286,8 +300,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if w.cid in '1, 3, 6, 9' %}
|
||||
{# PART | LTC | XMR | WOW | #}
|
||||
{% if w.cid in '1, 3, 6, 9, 13' %}
|
||||
{# PART | LTC | XMR | WOW | FIRO #}
|
||||
<div class="w-full md:w-1/2 p-3 flex justify-center items-center">
|
||||
<div class="h-full">
|
||||
<div class="flex flex-wrap -m-3">
|
||||
@@ -334,6 +348,22 @@
|
||||
</div>
|
||||
</div>
|
||||
{# / LTC #}
|
||||
{% elif w.cid == '13' %}
|
||||
{# FIRO #}
|
||||
<div id="qrcode-spark" class="qrcode" data-qrcode data-address="{{ w.spark_address }}"> </div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="font-normal bold text-gray-500 text-center dark:text-white mb-5">Spark Address: </div>
|
||||
<div class="text-center relative">
|
||||
<div class="input-like-container hover:border-blue-500 bg-gray-50 text-gray-900 appearance-none pr-10 dark:bg-gray-500 dark:text-white border border-gray-300 dark:border-gray-400 dark:text-gray-50 dark:placeholder-gray-400 text-lg lg:text-sm rounded-lg outline-none focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 focus:ring-0" id="stealth_address">{{ w.spark_address }}</div>
|
||||
<span class="absolute inset-y-0 right-0 flex items-center pr-3 cursor-pointer" id="copyIcon"></span>
|
||||
</div>
|
||||
<div class="opacity-100 text-gray-500 dark:text-gray-100 flex justify-center items-center">
|
||||
<div class="py-3 px-6 bold mt-5">
|
||||
<button type="submit" class="flex justify-center py-2 px-4 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" name="newsparkaddr_{{ w.cid }}" value="New Spark Address"> {{ circular_arrows_svg }} New Spark Address </button>
|
||||
</div>
|
||||
</div>
|
||||
{# / FIRO #}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
@@ -397,6 +427,15 @@
|
||||
(<span class="usd-value"></span>)
|
||||
</td>
|
||||
</tr>
|
||||
{% elif w.cid == '13' %}
|
||||
{# FIRO #}
|
||||
<tr class="opacity-100 text-gray-500 dark:text-gray-100">
|
||||
<td class="py-4 pl-6 bold w-1/4"> <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 }}"> </span>Spark Balance: </td>
|
||||
<td class="py-3 px-6">
|
||||
<span class="coinname-value" data-coinname="{{ w.name }}">{{ w.spark_balance }} {{ w.ticker }}</span>
|
||||
(<span class="usd-value"></span>)
|
||||
</td>
|
||||
</tr>
|
||||
{% elif w.cid == '1' %}
|
||||
{# PART #}
|
||||
<tr class="opacity-100 text-gray-500 dark:text-gray-100">
|
||||
@@ -487,6 +526,14 @@
|
||||
<button type="button" class="ml-2 py-1 px-2 bg-blue-500 text-white text-lg lg:text-sm rounded-md focus:outline-none" onclick="setAmount(1, '{{ w.balance }}', {{ w.cid }}, '{{ w.mweb_balance }}')">100%</button>
|
||||
|
||||
{# / LTC #}
|
||||
|
||||
{% elif w.cid == '13' %}
|
||||
{# FIRO #}
|
||||
<button type="button" class="hidden md:block py-1 px-2 bg-blue-500 text-white text-lg lg:text-sm rounded-md focus:outline-none" onclick="setAmount(0.25, '{{ w.balance }}', {{ w.cid }}, '{{ w.spark_balance }}')">25%</button>
|
||||
<button type="button" class="hidden md:block ml-2 py-1 px-2 bg-blue-500 text-white text-lg lg:text-sm rounded-md focus:outline-none" onclick="setAmount(0.5, '{{ w.balance }}', {{ w.cid }}, '{{ w.spark_balance }}')">50%</button>
|
||||
<button type="button" class="ml-2 py-1 px-2 bg-blue-500 text-white text-lg lg:text-sm rounded-md focus:outline-none" onclick="setAmount(1, '{{ w.balance }}', {{ w.cid }}, '{{ w.spark_balance }}')">100%</button>
|
||||
|
||||
{# / FIRO #}
|
||||
{% else %}
|
||||
<button type="button" class="hidden md:block py-1 px-2 bg-blue-500 text-white text-lg lg:text-sm rounded-md focus:outline-none" onclick="setAmount(0.25, '{{ w.balance }}', {{ w.cid }})">25%</button>
|
||||
<button type="button" class="hidden md:block ml-2 py-1 px-2 bg-blue-500 text-white text-lg lg:text-sm rounded-md focus:outline-none" onclick="setAmount(0.5, '{{ w.balance }}', {{ w.cid }})">50%</button>
|
||||
@@ -553,8 +600,21 @@
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% elif w.cid == '13' %} {# FIRO #}
|
||||
<tr class="opacity-100 text-gray-500 dark:text-gray-100">
|
||||
<td class="py-3 px-6 bold">Type From:</td>
|
||||
<td class="py-3 px-6">
|
||||
<div class="w-full md:flex-1">
|
||||
<div class="relative"> {{ select_box_arrow_svg }} <select id="withdraw_type" class="{{ select_box_class }}" name="withdraw_type_from_{{ w.cid }}">
|
||||
<option value="spark" {% if w.wd_type_from=='spark' %} selected{% endif %}>Spark</option>
|
||||
<option value="plain" {% if w.wd_type_from=='plain' %} selected{% endif %}>Plain</option>
|
||||
</select> </div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{# / LTC #}
|
||||
{# / FIRO #}
|
||||
{% if w.cid not in '6,9' %} {# Not XMR WOW #}
|
||||
<tr class="opacity-100 text-gray-500 dark:text-gray-100">
|
||||
<td class="py-3 px-6 bold">Fee Rate:</td>
|
||||
|
||||
@@ -132,6 +132,28 @@
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{# / LTC #}
|
||||
{% if w.cid == '13' %} {# FIRO #}
|
||||
<div class="flex mb-2 justify-between items-center">
|
||||
<h4 class="text-xs font-medium dark:text-white">Spark Balance:</h4>
|
||||
<span class="bold inline-block py-1 px-2 rounded-full bg-blue-100 text-xs text-black-500 dark:bg-gray-500 dark:text-gray-200 coinname-value" data-coinname="{{ w.name }}">{{ w.spark_balance }} {{ w.ticker }}</span>
|
||||
</div>
|
||||
<div class="flex mb-2 justify-between items-center">
|
||||
<h4 class="text-xs font-medium dark:text-white">Spark USD value:</h4>
|
||||
<div class="bold inline-block py-1 px-2 rounded-full bg-blue-100 text-xs text-black-500 dark:bg-gray-500 dark:text-gray-200 usd-value"></div>
|
||||
</div>
|
||||
{% if w.spark_pending %}
|
||||
<div class="flex mb-2 justify-between items-center">
|
||||
<h4 class="text-xs font-bold text-green-500 dark:text-green-500">Spark Pending:</h4>
|
||||
<span class="bold inline-block py-1 px-2 rounded-full bg-green-100 text-xs text-green-500 dark:bg-gray-500 dark:text-green-500 coinname-value" data-coinname="{{ w.name }}">
|
||||
+{{ w.spark_pending }} {{ w.ticker }}</span>
|
||||
</div>
|
||||
<div class="flex mb-2 justify-between items-center">
|
||||
<h4 class="text-xs font-bold text-green-500 dark:text-green-500">Spark Pending USD value:</h4>
|
||||
<div class="bold inline-block py-1 px-2 rounded-full bg-green-100 text-xs text-green-500 dark:bg-gray-500 dark:text-green-500 usd-value"></div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{# / FIRO #}
|
||||
<hr class="border-t border-gray-100 dark:border-gray-500 my-5">
|
||||
<div class="flex mb-2 justify-between items-center">
|
||||
<h4 class="text-xs font-medium dark:text-white">Blocks:</h4>
|
||||
|
||||
@@ -82,6 +82,10 @@ def format_wallet_data(swap_client, ci, w):
|
||||
wf["mweb_address"] = w.get("mweb_address", "?")
|
||||
wf["mweb_balance"] = w.get("mweb_balance", "?")
|
||||
wf["mweb_pending"] = w.get("mweb_pending", "?")
|
||||
elif ci.coin_type() == Coins.FIRO:
|
||||
wf["spark_address"] = w.get("spark_address", "?")
|
||||
wf["spark_balance"] = w.get("spark_balance", "?")
|
||||
wf["spark_pending"] = w.get("spark_pending", "?")
|
||||
|
||||
checkAddressesOwned(swap_client, ci, wf)
|
||||
return wf
|
||||
@@ -163,6 +167,8 @@ def page_wallet(self, url_split, post_string):
|
||||
force_refresh = True
|
||||
elif have_data_entry(form_data, "newmwebaddr_" + cid):
|
||||
swap_client.cacheNewStealthAddressForCoin(coin_id)
|
||||
elif have_data_entry(form_data, "newsparkaddr_" + cid):
|
||||
swap_client.cacheNewStealthAddressForCoin(coin_id)
|
||||
elif have_data_entry(form_data, "reseed_" + cid):
|
||||
try:
|
||||
swap_client.reseedWallet(coin_id)
|
||||
@@ -208,7 +214,7 @@ def page_wallet(self, url_split, post_string):
|
||||
page_data["wd_type_to_" + cid] = type_to
|
||||
except Exception as e: # noqa: F841
|
||||
err_messages.append("Missing type")
|
||||
elif coin_id == Coins.LTC:
|
||||
elif coin_id in (Coins.LTC, Coins.FIRO):
|
||||
try:
|
||||
type_from = form_data[bytes("withdraw_type_from_" + cid, "utf-8")][
|
||||
0
|
||||
@@ -230,9 +236,9 @@ def page_wallet(self, url_split, post_string):
|
||||
value, ticker, type_from, type_to, address, txid
|
||||
)
|
||||
)
|
||||
elif coin_id == Coins.LTC:
|
||||
txid = swap_client.withdrawLTC(
|
||||
type_from, value, address, subfee
|
||||
elif coin_id in (Coins.LTC, Coins.FIRO):
|
||||
txid = swap_client.withdrawCoinExtended(
|
||||
coin_id, type_from, value, address, subfee
|
||||
)
|
||||
messages.append(
|
||||
"Withdrew {} {} (from {}) to address {}<br/>In txid: {}".format(
|
||||
@@ -342,6 +348,8 @@ def page_wallet(self, url_split, post_string):
|
||||
wallet_data["main_address"] = w.get("main_address", "Refresh necessary")
|
||||
elif k == Coins.LTC:
|
||||
wallet_data["mweb_address"] = w.get("mweb_address", "Refresh necessary")
|
||||
elif k == Coins.FIRO:
|
||||
wallet_data["spark_address"] = w.get("spark_address", "Refresh necessary")
|
||||
|
||||
if "wd_type_from_" + cid in page_data:
|
||||
wallet_data["wd_type_from"] = page_data["wd_type_from_" + cid]
|
||||
|
||||
@@ -79,13 +79,13 @@ def main():
|
||||
continue
|
||||
if coin_name in ("monero", "wownero"):
|
||||
with open(
|
||||
os.path.join(fragments_dir, "1_{coin_name}-wallet.yml"), "rb"
|
||||
os.path.join(fragments_dir, f"1_{coin_name}-wallet.yml"), "rb"
|
||||
) as fp_in:
|
||||
for line in fp_in:
|
||||
fp.write(line)
|
||||
fpp.write(line)
|
||||
with open(
|
||||
os.path.join(fragments_dir, "8_{coin_name}-daemon.yml"), "rb"
|
||||
os.path.join(fragments_dir, f"8_{coin_name}-daemon.yml"), "rb"
|
||||
) as fp_in:
|
||||
for line in fp_in:
|
||||
fp.write(line)
|
||||
|
||||
4
guix.scm
4
guix.scm
@@ -140,10 +140,10 @@
|
||||
(method git-fetch)
|
||||
(uri (git-reference
|
||||
(url "https://github.com/basicswap/basicswap")
|
||||
(commit "2259e964b11925587301070f9fc15e2226b2eb69")))
|
||||
(commit "83807d213fab52c99f69dbc06fa7baedb449d66f")))
|
||||
(sha256
|
||||
(base32
|
||||
"0d544bj4kvra9y6rpqai1yvnk2igxj4z8s14g5jpksx5z9l0nyy3"))
|
||||
"08ykwn2wbcny5k6kwj3xkfkim40kmzcb988lpcd70r7kcmn8ggp0"))
|
||||
(file-name (git-file-name name version))))
|
||||
(build-system pyproject-build-system)
|
||||
|
||||
|
||||
@@ -729,7 +729,25 @@ def process_offers(args, config, script_state) -> None:
|
||||
matching_sent_offers.append(offer)
|
||||
offers_found += 1
|
||||
|
||||
if wallet_balance <= float(offer_template["min_coin_from_amt"]):
|
||||
offer_amount_from = float(offer.get("amount_from", 0))
|
||||
min_coin_from_amt = float(offer_template.get("min_coin_from_amt", 0))
|
||||
|
||||
if offer_amount_from > wallet_balance:
|
||||
print(
|
||||
f"Revoking offer {offer_id}, offer amount {offer_amount_from:.8f} > wallet balance {wallet_balance:.8f}"
|
||||
)
|
||||
result = read_json_api(f"revokeoffer/{offer_id}")
|
||||
if args.debug:
|
||||
print("revokeoffer", result)
|
||||
else:
|
||||
print("Offer revoked, will repost with accurate amount")
|
||||
for i, prev_offer in enumerate(prev_template_offers):
|
||||
if prev_offer.get("offer_id") == offer_id:
|
||||
del prev_template_offers[i]
|
||||
break
|
||||
write_state(args.statefile, script_state)
|
||||
offers_found -= 1
|
||||
elif wallet_balance <= min_coin_from_amt:
|
||||
print(
|
||||
"Revoking offer {}, wallet from balance below minimum".format(
|
||||
offer_id
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2022-2023 tecnovert
|
||||
# Copyright (c) 2024 The Basicswap developers
|
||||
# Copyright (c) 2024-2026 The Basicswap developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
@@ -199,7 +199,7 @@ class Test(BaseTest):
|
||||
0, "getnewaddress", ["mining_addr"], base_rpc_port=FIRO_BASE_RPC_PORT
|
||||
)
|
||||
# cls.firo_addr = callnoderpc(0, 'addwitnessaddress', [cls.firo_addr], base_rpc_port=FIRO_BASE_RPC_PORT)
|
||||
logging.info("Mining %d Firo blocks to %s", num_blocks, cls.firo_addr)
|
||||
logging.info(f"Mining {num_blocks} Firo blocks to {cls.firo_addr}")
|
||||
callnoderpc(
|
||||
0,
|
||||
"generatetoaddress",
|
||||
@@ -230,7 +230,7 @@ class Test(BaseTest):
|
||||
0, "getblockcount", base_rpc_port=FIRO_BASE_RPC_PORT
|
||||
)
|
||||
num_blocks = 1352 - chain_height # Activate CTLV (bip65)
|
||||
logging.info("Mining %d Firo blocks to %s", num_blocks, cls.firo_addr)
|
||||
logging.info(f"Mining {num_blocks} Firo blocks to {cls.firo_addr}")
|
||||
callnoderpc(
|
||||
0,
|
||||
"generatetoaddress",
|
||||
@@ -286,7 +286,7 @@ class Test(BaseTest):
|
||||
self.callnoderpc("generatetoaddress", [num_blocks, self.firo_addr])
|
||||
|
||||
def test_001_firo(self):
|
||||
logging.info("---------- Test {} segwit".format(self.test_coin_from.name))
|
||||
logging.info(f"---------- Test {self.test_coin_from.name} segwit")
|
||||
|
||||
"""
|
||||
Segwit is not currently enabled:
|
||||
@@ -339,7 +339,7 @@ class Test(BaseTest):
|
||||
assert txid_with_scriptsig == tx_signed_decoded["txid"]
|
||||
|
||||
def test_007_hdwallet(self):
|
||||
logging.info("---------- Test {} hdwallet".format(self.test_coin_from.name))
|
||||
logging.info(f"---------- Test {self.test_coin_from.name} hdwallet")
|
||||
|
||||
swap_client = self.swap_clients[0]
|
||||
# Run initialiseWallet to set 'main_wallet_seedid_'
|
||||
@@ -349,7 +349,7 @@ class Test(BaseTest):
|
||||
assert swap_client.checkWalletSeed(self.test_coin_from) is True
|
||||
|
||||
def test_008_gettxout(self):
|
||||
logging.info("---------- Test {} gettxout".format(self.test_coin_from.name))
|
||||
logging.info(f"---------- Test {self.test_coin_from.name} gettxout")
|
||||
|
||||
swap_client = self.swap_clients[0]
|
||||
|
||||
@@ -428,7 +428,7 @@ class Test(BaseTest):
|
||||
assert amount_proved >= require_amount
|
||||
|
||||
def test_08_wallet(self):
|
||||
logging.info("---------- Test {} wallet".format(self.test_coin_from.name))
|
||||
logging.info(f"---------- Test {self.test_coin_from.name} wallet")
|
||||
|
||||
logging.info("Test withdrawal")
|
||||
addr = self.callnoderpc(
|
||||
@@ -447,7 +447,7 @@ class Test(BaseTest):
|
||||
}
|
||||
json_rv = read_json_api(
|
||||
TEST_HTTP_PORT + 0,
|
||||
"wallets/{}/withdraw".format(self.test_coin_from.name.lower()),
|
||||
f"wallets/{self.test_coin_from.name.lower()}/withdraw",
|
||||
post_json,
|
||||
)
|
||||
assert len(json_rv["txid"]) == 64
|
||||
@@ -458,7 +458,7 @@ class Test(BaseTest):
|
||||
}
|
||||
json_rv = read_json_api(
|
||||
TEST_HTTP_PORT + 0,
|
||||
"wallets/{}/createutxo".format(self.test_coin_from.name.lower()),
|
||||
f"wallets/{self.test_coin_from.name.lower()}/createutxo",
|
||||
post_json,
|
||||
)
|
||||
assert len(json_rv["txid"]) == 64
|
||||
@@ -473,6 +473,14 @@ class Test(BaseTest):
|
||||
ci_from = swap_clients[0].ci(coin_from)
|
||||
ci_to = swap_clients[1].ci(coin_to)
|
||||
|
||||
id_bidder: int = 1
|
||||
self.prepare_balance(
|
||||
coin_to,
|
||||
100.0,
|
||||
1800 + id_bidder,
|
||||
1801 if coin_to in (Coins.XMR,) else 1800,
|
||||
)
|
||||
|
||||
swap_value = ci_from.make_int(random.uniform(0.2, 20.0), r=1)
|
||||
rate_swap = ci_to.make_int(random.uniform(0.2, 20.0), r=1)
|
||||
offer_id = swap_clients[0].postOffer(
|
||||
@@ -506,9 +514,7 @@ class Test(BaseTest):
|
||||
coin_from = Coins.BTC
|
||||
coin_to = Coins.FIRO
|
||||
logging.info(
|
||||
"---------- Test {} to {} follower recovers coin b lock tx".format(
|
||||
coin_from.name, coin_to.name
|
||||
)
|
||||
f"---------- Test {coin_from.name} to {coin_to.name} follower recovers coin b lock tx"
|
||||
)
|
||||
|
||||
swap_clients = self.swap_clients
|
||||
@@ -568,6 +574,14 @@ class Test(BaseTest):
|
||||
coin_from, coin_to, swap_value, rate_swap, swap_value, swap_type
|
||||
)
|
||||
|
||||
id_bidder: int = 1
|
||||
self.prepare_balance(
|
||||
coin_to,
|
||||
100.0,
|
||||
1800 + id_bidder,
|
||||
1801 if coin_to in (Coins.XMR,) else 1800,
|
||||
)
|
||||
|
||||
wait_for_offer(test_delay_event, swap_clients[1], offer_id)
|
||||
offer = swap_clients[1].getOffer(offer_id)
|
||||
bid_id = swap_clients[1].postBid(offer_id, offer.amount_from)
|
||||
@@ -592,7 +606,7 @@ class Test(BaseTest):
|
||||
)
|
||||
|
||||
def test_101_full_swap(self):
|
||||
logging.info("---------- Test {} to XMR".format(self.test_coin_from.name))
|
||||
logging.info(f"---------- Test {self.test_coin_from.name} to XMR")
|
||||
if not self.test_xmr:
|
||||
logging.warning("Skipping test")
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user