diff --git a/basicswap/basicswap.py b/basicswap/basicswap.py
index 39b3b35..8a5e1d4 100644
--- a/basicswap/basicswap.py
+++ b/basicswap/basicswap.py
@@ -391,7 +391,7 @@ class BasicSwap(BaseApp):
Coins.PART_BLIND,
Coins.BCH,
)
- self.coins_without_segwit = (Coins.PIVX, Coins.DASH, Coins.NMC)
+ self.coins_without_segwit = (Coins.PIVX, Coins.DASH)
# TODO: Adjust ranges
self.min_delay_event = self.get_int_setting("min_delay_event", 10, 0, 20 * 60)
diff --git a/basicswap/bin/prepare.py b/basicswap/bin/prepare.py
index b5f3a11..4bea5c1 100755
--- a/basicswap/bin/prepare.py
+++ b/basicswap/bin/prepare.py
@@ -52,11 +52,17 @@ PARTICL_VERSION = os.getenv("PARTICL_VERSION", "23.2.7.0")
PARTICL_VERSION_TAG = os.getenv("PARTICL_VERSION_TAG", "")
PARTICL_LINUX_EXTRA = os.getenv("PARTICL_LINUX_EXTRA", "nousb")
+BITCOIN_VERSION = os.getenv("BITCOIN_VERSION", "28.0")
+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", "")
-BITCOIN_VERSION = os.getenv("BITCOIN_VERSION", "28.0")
-BITCOIN_VERSION_TAG = os.getenv("BITCOIN_VERSION_TAG", "")
+DCR_VERSION = os.getenv("DCR_VERSION", "1.8.1")
+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.3.4")
MONERO_VERSION_TAG = os.getenv("MONERO_VERSION_TAG", "")
@@ -82,9 +88,6 @@ 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", "")
-DCR_VERSION = os.getenv("DCR_VERSION", "1.8.1")
-DCR_VERSION_TAG = os.getenv("DCR_VERSION_TAG", "")
-
BITCOINCASH_VERSION = os.getenv("BITCOINCASH_VERSION", "28.0.1")
BITCOINCASH_VERSION_TAG = os.getenv("BITCOINCASH_VERSION_TAG", "")
@@ -103,7 +106,7 @@ known_coins = {
"bitcoin": (BITCOIN_VERSION, BITCOIN_VERSION_TAG, ("laanwj",)),
"litecoin": (LITECOIN_VERSION, LITECOIN_VERSION_TAG, ("davidburkett38",)),
"decred": (DCR_VERSION, DCR_VERSION_TAG, ("decred_release",)),
- "namecoin": ("0.18.0", "", ("JeremyRand",)),
+ "namecoin": (NMC_VERSION, NMC_VERSION_TAG, ("RoseTuring",)),
"monero": (MONERO_VERSION, MONERO_VERSION_TAG, ("binaryfate",)),
"wownero": (WOWNERO_VERSION, WOWNERO_VERSION_TAG, ("wowario",)),
"pivx": (PIVX_VERSION, PIVX_VERSION_TAG, ("fuzzbawls",)),
@@ -116,26 +119,32 @@ known_coins = {
disabled_coins = [
"navcoin",
- "namecoin", # Needs update
]
expected_key_ids = {
- "tecnovert": ("13F13651C9CF0D6B",),
- "thrasher": ("FE3348877809386C",),
- "laanwj": ("1E4AED62986CD25D",),
- "JeremyRand": ("2DBE339E29F6294C",),
- "binaryfate": ("F0AF4D462A0BDF92",),
- "wowario": ("793504B449C69220",),
- "davidburkett38": ("3620E9D387E55666",),
- "xanimo": ("6E8F17C1B1BCDCBE",),
- "patricklodder": ("2D3A345B98D0DC1F",),
- "fuzzbawls": ("C1ABA64407731FD9",),
- "pasta": ("52527BEDABE87984", "E2F3D7916E722D38"),
- "reuben": ("1290A1D0FA7EE109",),
- "nav_builder": ("2782262BF6E7FADB",),
- "nicolasdorier": ("6618763EF09186FE", "223FDA69DEBEA82D", "62FE85647DEDDA2E"),
- "decred_release": ("6D897EDF518A031D",),
- "Calin_Culianu": ("21810A542031C02C",),
+ "tecnovert": ("8E517DC12EC1CC37F6423A8A13F13651C9CF0D6B",),
+ "thrasher": ("59CAF0E96F23F53747945FD4FE3348877809386C",),
+ "laanwj": ("9DEAE0DC7063249FB05474681E4AED62986CD25D",),
+ "RoseTuring": ("FD8366A807A99FA27FD9CCEA9FE3BFDDA6C53495",),
+ "binaryfate": ("81AC591FE9C4B65C5806AFC3F0AF4D462A0BDF92",),
+ "wowario": ("AB3A2F725818FCFF2794841C793504B449C69220",),
+ "davidburkett38": ("D35621D53A1CC6A3456758D03620E9D387E55666",),
+ "xanimo": ("2EAA8B1021C71AD5186CA07F6E8F17C1B1BCDCBE",),
+ "patricklodder": ("DC6EF4A8BF9F1B1E4DE1EE522D3A345B98D0DC1F",),
+ "fuzzbawls": ("0CFBDA9F60D661BA31EB5D50C1ABA64407731FD9",),
+ "pasta": (
+ "29590362EC878A81FD3C202B52527BEDABE87984",
+ "02B8E7D002167C8B451AF05FE2F3D7916E722D38",
+ ),
+ "reuben": ("0186454D63E83D85EF91DE4E1290A1D0FA7EE109",),
+ "nav_builder": ("1BF9B51BAED51BA0B3A174EE2782262BF6E7FADB",),
+ "nicolasdorier": (
+ "AB4CFA9895ACA0DBE27F6B346618763EF09186FE",
+ "015B4C837B245509E4AC8995223FDA69DEBEA82D",
+ "7121BDE3555D9BE06BDDC68162FE85647DEDDA2E",
+ ),
+ "decred_release": ("F516ADB7A069852C7C28A02D6D897EDF518A031D",),
+ "Calin_Culianu": ("D465135F97D0047E18E99DC321810A542031C02C",),
}
USE_PLATFORM = os.getenv("USE_PLATFORM", platform.system())
@@ -181,6 +190,36 @@ PART_ONION_PORT = int(os.getenv("PART_ONION_PORT", 51734))
PART_RPC_USER = os.getenv("PART_RPC_USER", "")
PART_RPC_PWD = os.getenv("PART_RPC_PWD", "")
+BTC_RPC_HOST = os.getenv("BTC_RPC_HOST", "127.0.0.1")
+BTC_RPC_PORT = int(os.getenv("BTC_RPC_PORT", 19996))
+BTC_PORT = int(os.getenv("BTC_PORT", 8333))
+BTC_ONION_PORT = int(os.getenv("BTC_ONION_PORT", 8334))
+BTC_RPC_USER = os.getenv("BTC_RPC_USER", "")
+BTC_RPC_PWD = os.getenv("BTC_RPC_PWD", "")
+
+LTC_RPC_HOST = os.getenv("LTC_RPC_HOST", "127.0.0.1")
+LTC_RPC_PORT = int(os.getenv("LTC_RPC_PORT", 19895))
+LTC_ONION_PORT = int(os.getenv("LTC_ONION_PORT", 9333))
+LTC_RPC_USER = os.getenv("LTC_RPC_USER", "")
+LTC_RPC_PWD = os.getenv("LTC_RPC_PWD", "")
+
+DCR_RPC_HOST = os.getenv("DCR_RPC_HOST", "127.0.0.1")
+DCR_RPC_PORT = int(os.getenv("DCR_RPC_PORT", 9109))
+DCR_WALLET_RPC_HOST = os.getenv("DCR_WALLET_RPC_HOST", "127.0.0.1")
+DCR_WALLET_RPC_PORT = int(os.getenv("DCR_WALLET_RPC_PORT", 9209))
+DCR_WALLET_PWD = os.getenv(
+ "DCR_WALLET_PWD", random.randbytes(random.randint(14, 18)).hex()
+)
+DCR_RPC_USER = os.getenv("DCR_RPC_USER", "user")
+DCR_RPC_PWD = os.getenv("DCR_RPC_PWD", random.randbytes(random.randint(14, 18)).hex())
+
+NMC_RPC_HOST = os.getenv("NMC_RPC_HOST", "127.0.0.1")
+NMC_RPC_PORT = int(os.getenv("NMC_RPC_PORT", 19698))
+NMC_PORT = int(os.getenv("NMC_PORT", 8134))
+NMC_ONION_PORT = int(os.getenv("NMC_ONION_PORT", 9698))
+NMC_RPC_USER = os.getenv("NMC_RPC_USER", "")
+NMC_RPC_PWD = os.getenv("NMC_RPC_PWD", "")
+
XMR_RPC_HOST = os.getenv("XMR_RPC_HOST", "127.0.0.1")
XMR_RPC_PORT = int(os.getenv("XMR_RPC_PORT", 29798))
XMR_ZMQ_PORT = int(os.getenv("XMR_ZMQ_PORT", 30898))
@@ -203,32 +242,6 @@ WOW_RPC_USER = os.getenv("WOW_RPC_USER", "")
WOW_RPC_PWD = os.getenv("WOW_RPC_PWD", "")
DEFAULT_WOW_RESTORE_HEIGHT = int(os.getenv("DEFAULT_WOW_RESTORE_HEIGHT", 450000))
-LTC_RPC_HOST = os.getenv("LTC_RPC_HOST", "127.0.0.1")
-LTC_RPC_PORT = int(os.getenv("LTC_RPC_PORT", 19895))
-LTC_ONION_PORT = int(os.getenv("LTC_ONION_PORT", 9333))
-LTC_RPC_USER = os.getenv("LTC_RPC_USER", "")
-LTC_RPC_PWD = os.getenv("LTC_RPC_PWD", "")
-
-BTC_RPC_HOST = os.getenv("BTC_RPC_HOST", "127.0.0.1")
-BTC_RPC_PORT = int(os.getenv("BTC_RPC_PORT", 19996))
-BTC_PORT = int(os.getenv("BTC_PORT", 8333))
-BTC_ONION_PORT = int(os.getenv("BTC_ONION_PORT", 8334))
-BTC_RPC_USER = os.getenv("BTC_RPC_USER", "")
-BTC_RPC_PWD = os.getenv("BTC_RPC_PWD", "")
-
-DCR_RPC_HOST = os.getenv("DCR_RPC_HOST", "127.0.0.1")
-DCR_RPC_PORT = int(os.getenv("DCR_RPC_PORT", 9109))
-DCR_WALLET_RPC_HOST = os.getenv("DCR_WALLET_RPC_HOST", "127.0.0.1")
-DCR_WALLET_RPC_PORT = int(os.getenv("DCR_WALLET_RPC_PORT", 9209))
-DCR_WALLET_PWD = os.getenv(
- "DCR_WALLET_PWD", random.randbytes(random.randint(14, 18)).hex()
-)
-DCR_RPC_USER = os.getenv("DCR_RPC_USER", "user")
-DCR_RPC_PWD = os.getenv("DCR_RPC_PWD", random.randbytes(random.randint(14, 18)).hex())
-
-NMC_RPC_HOST = os.getenv("NMC_RPC_HOST", "127.0.0.1")
-NMC_RPC_PORT = int(os.getenv("NMC_RPC_PORT", 19698))
-
PIVX_RPC_HOST = os.getenv("PIVX_RPC_HOST", "127.0.0.1")
PIVX_RPC_PORT = int(os.getenv("PIVX_RPC_PORT", 51473))
PIVX_ONION_PORT = int(os.getenv("PIVX_ONION_PORT", 51472)) # nDefaultPort
@@ -375,6 +388,12 @@ def getWalletName(coin_params: str, default_name: str, prefix_override=None) ->
return wallet_name
+def getDescriptorWalletOption(coin_params):
+ ticker: str = coin_params["ticker"]
+ default_option: bool = True if ticker in ("NMC",) else False
+ return toBool(os.getenv(ticker + "_USE_DESCRIPTORS", default_option))
+
+
def getKnownVersion(coin_name: str) -> str:
version, version_tag, _ = known_coins[coin_name]
return version + version_tag
@@ -528,7 +547,7 @@ def testOnionLink():
def havePubkey(gpg, key_id):
for key in gpg.list_keys():
- if key["keyid"] == key_id:
+ if key["fingerprint"] == key_id:
return True
return False
@@ -591,8 +610,10 @@ def ensureValidSignatureBy(result, signing_key_name):
if not isValidSignature(result):
raise ValueError("Signature verification failed.")
- if result.key_id not in expected_key_ids[signing_key_name]:
- raise ValueError("Signature made by unexpected keyid: " + result.key_id)
+ if result.fingerprint not in expected_key_ids[signing_key_name]:
+ raise ValueError(
+ "Signature made by unexpected key fingerprint: " + result.fingerprint
+ )
logger.debug(f"Found valid signature by {signing_key_name} ({result.key_id}).")
@@ -931,16 +952,10 @@ def prepareCore(coin, version_data, settings, data_dir, extra_opts={}):
% (version, assert_filename)
)
elif coin == "namecoin":
- release_url = "https://beta.namecoin.org/files/namecoin-core/namecoin-core-{}/{}".format(
- version, release_filename
- )
- assert_filename = "{}-{}-{}-build.assert".format(
- coin, os_name, version.rsplit(".", 1)[0]
- )
- assert_url = (
- "https://raw.githubusercontent.com/namecoin/gitian.sigs/master/%s-%s/%s/%s"
- % (version, os_dir_name, signing_key_name, assert_filename)
- )
+ release_url = f"https://www.namecoin.org/files/namecoin-core/namecoin-core-{version}/{release_filename}"
+ signing_key = "Rose%20Turing"
+ assert_filename = "noncodesigned.SHA256SUMS"
+ assert_url = f"https://raw.githubusercontent.com/namecoin/guix.sigs/main/{version}/{signing_key}/{assert_filename}"
elif coin == "pivx":
release_filename = "{}-{}-{}.{}".format(coin, version, BIN_ARCH, FILE_EXT)
release_url = (
@@ -1345,6 +1360,8 @@ def prepareDataDir(coin, settings, chain, particl_mnemonic, extra_opts={}):
fp.write("printtoconsole=0\n")
fp.write("daemon=0\n")
fp.write(f"wallet={wallet_name}\n")
+ if "watch_wallet_name" in core_settings:
+ fp.write("wallet={}\n".format(core_settings["watch_wallet_name"]))
if tor_control_password is not None:
writeTorSettings(fp, coin, core_settings, tor_control_password)
@@ -1401,6 +1418,10 @@ def prepareDataDir(coin, settings, chain, particl_mnemonic, extra_opts={}):
)
elif coin == "namecoin":
fp.write("prune=2000\n")
+ fp.write("deprecatedrpc=create_bdb\n")
+ fp.write("addresstype=bech32\n")
+ fp.write("changetype=bech32\n")
+ fp.write("fallbackfee=0.001\n") # minrelaytxfee
elif coin == "pivx":
params_dir = os.path.join(data_dir, "pivx-params")
downloadPIVXParams(params_dir)
@@ -1804,6 +1825,7 @@ def initialise_wallets(
Coins.DOGE,
Coins.DCR,
Coins.DASH,
+ Coins.NMC,
)
# Always start Particl, it must be running to initialise a wallet in addcoin mode
# Particl must be loaded first as subsequent coins are initialised from the Particl mnemonic
@@ -1909,7 +1931,7 @@ def initialise_wallets(
f'Creating wallet "{wallet_name}" for {getCoinName(c)}.'
)
- if c in (Coins.BTC, Coins.LTC, Coins.DOGE, Coins.DASH):
+ if c in (Coins.BTC, Coins.LTC, Coins.NMC, Coins.DOGE, Coins.DASH):
# wallet_name, disable_private_keys, blank, passphrase, avoid_reuse, descriptors
use_descriptors = coin_settings.get("use_descriptors", False)
@@ -1926,11 +1948,15 @@ def initialise_wallets(
],
)
if use_descriptors:
+ watch_wallet_name = coin_settings["watch_wallet_name"]
+ logger.info(
+ f'Creating wallet "{watch_wallet_name}" for {getCoinName(c)}.'
+ )
swap_client.callcoinrpc(
c,
"createwallet",
[
- coin_settings["watch_wallet_name"],
+ watch_wallet_name,
True,
True,
"",
@@ -2073,7 +2099,10 @@ def check_btc_fastsync_data(base_dir, sync_filename):
importPubkey(gpg, pubkey_filename, pubkeyurls)
with open(asc_file_path, "rb") as fp:
verified = gpg.verify_file(fp)
- if isValidSignature(verified) and verified.key_id in expected_key_ids["tecnovert"]:
+ if (
+ isValidSignature(verified)
+ and verified.fingerprint in expected_key_ids["tecnovert"]
+ ):
ensureValidSignatureBy(verified, "tecnovert")
else:
pubkey_filename = "nicolasdorier.asc"
@@ -2379,22 +2408,6 @@ def main():
"core_version_no": getKnownVersion("bitcoin"),
"core_version_group": 28,
},
- "bitcoincash": {
- "connection_type": "rpc",
- "manage_daemon": shouldManageDaemon("BCH"),
- "rpchost": BCH_RPC_HOST,
- "rpcport": BCH_RPC_PORT + port_offset,
- "onionport": BCH_ONION_PORT + port_offset,
- "datadir": os.getenv("BCH_DATA_DIR", os.path.join(data_dir, "bitcoincash")),
- "bindir": os.path.join(bin_dir, "bitcoincash"),
- "port": BCH_PORT + port_offset,
- "config_filename": "bitcoin.conf",
- "use_segwit": False,
- "blocks_confirmed": 1,
- "conf_target": 2,
- "core_version_no": getKnownVersion("bitcoincash"),
- "core_version_group": 22,
- },
"litecoin": {
"connection_type": "rpc",
"manage_daemon": shouldManageDaemon("LTC"),
@@ -2410,22 +2423,6 @@ def main():
"core_version_group": 20,
"min_relay_fee": 0.00001,
},
- "dogecoin": {
- "connection_type": "rpc",
- "manage_daemon": shouldManageDaemon("DOGE"),
- "rpchost": DOGE_RPC_HOST,
- "rpcport": DOGE_RPC_PORT + port_offset,
- "onionport": DOGE_ONION_PORT + port_offset,
- "datadir": os.getenv("DOGE_DATA_DIR", os.path.join(data_dir, "dogecoin")),
- "bindir": os.path.join(bin_dir, "dogecoin"),
- "use_segwit": False,
- "use_csv": False,
- "blocks_confirmed": 2,
- "conf_target": 2,
- "core_version_no": getKnownVersion("dogecoin"),
- "core_version_group": 23,
- "min_relay_fee": 0.01, # RECOMMENDED_MIN_TX_FEE
- },
"decred": {
"connection_type": "rpc",
"manage_daemon": shouldManageDaemon("DCR"),
@@ -2453,14 +2450,16 @@ def main():
"manage_daemon": shouldManageDaemon("NMC"),
"rpchost": NMC_RPC_HOST,
"rpcport": NMC_RPC_PORT + port_offset,
+ "onionport": NMC_ONION_PORT + port_offset,
"datadir": os.getenv("NMC_DATA_DIR", os.path.join(data_dir, "namecoin")),
"bindir": os.path.join(bin_dir, "namecoin"),
- "use_segwit": False,
- "use_csv": False,
+ "port": NMC_PORT + port_offset,
+ "use_segwit": True,
+ "use_csv": True,
"blocks_confirmed": 1,
"conf_target": 2,
"core_version_no": getKnownVersion("namecoin"),
- "core_version_group": 18,
+ "core_version_group": 28,
"chain_lookups": "local",
},
"monero": {
@@ -2486,6 +2485,28 @@ def main():
"core_version_no": getKnownVersion("monero"),
"core_type_group": "xmr",
},
+ "wownero": {
+ "connection_type": "rpc",
+ "manage_daemon": shouldManageDaemon("WOW"),
+ "manage_wallet_daemon": shouldManageDaemon("WOW_WALLET"),
+ "rpcport": WOW_RPC_PORT + port_offset,
+ "zmqport": WOW_ZMQ_PORT + port_offset,
+ "walletrpcport": WOW_WALLET_RPC_PORT + port_offset,
+ "rpchost": WOW_RPC_HOST,
+ "trusted_daemon": extra_opts.get("trust_remote_node", "auto"),
+ "walletrpchost": WOW_WALLET_RPC_HOST,
+ "walletrpcuser": WOW_WALLET_RPC_USER,
+ "walletrpcpassword": WOW_WALLET_RPC_PWD,
+ "datadir": os.getenv("WOW_DATA_DIR", os.path.join(data_dir, "wownero")),
+ "bindir": os.path.join(bin_dir, "wownero"),
+ "restore_height": wow_restore_height,
+ "blocks_confirmed": 2,
+ "rpctimeout": 60,
+ "walletrpctimeout": 120,
+ "walletrpctimeoutlong": 300,
+ "core_version_no": getKnownVersion("wownero"),
+ "core_type_group": "xmr",
+ },
"pivx": {
"connection_type": "rpc",
"manage_daemon": shouldManageDaemon("PIVX"),
@@ -2549,27 +2570,37 @@ def main():
"chain_lookups": "local",
"startup_tries": 40,
},
- "wownero": {
+ "bitcoincash": {
"connection_type": "rpc",
- "manage_daemon": shouldManageDaemon("WOW"),
- "manage_wallet_daemon": shouldManageDaemon("WOW_WALLET"),
- "rpcport": WOW_RPC_PORT + port_offset,
- "zmqport": WOW_ZMQ_PORT + port_offset,
- "walletrpcport": WOW_WALLET_RPC_PORT + port_offset,
- "rpchost": WOW_RPC_HOST,
- "trusted_daemon": extra_opts.get("trust_remote_node", "auto"),
- "walletrpchost": WOW_WALLET_RPC_HOST,
- "walletrpcuser": WOW_WALLET_RPC_USER,
- "walletrpcpassword": WOW_WALLET_RPC_PWD,
- "datadir": os.getenv("WOW_DATA_DIR", os.path.join(data_dir, "wownero")),
- "bindir": os.path.join(bin_dir, "wownero"),
- "restore_height": wow_restore_height,
+ "manage_daemon": shouldManageDaemon("BCH"),
+ "rpchost": BCH_RPC_HOST,
+ "rpcport": BCH_RPC_PORT + port_offset,
+ "onionport": BCH_ONION_PORT + port_offset,
+ "datadir": os.getenv("BCH_DATA_DIR", os.path.join(data_dir, "bitcoincash")),
+ "bindir": os.path.join(bin_dir, "bitcoincash"),
+ "port": BCH_PORT + port_offset,
+ "config_filename": "bitcoin.conf",
+ "use_segwit": False,
+ "blocks_confirmed": 1,
+ "conf_target": 2,
+ "core_version_no": getKnownVersion("bitcoincash"),
+ "core_version_group": 22,
+ },
+ "dogecoin": {
+ "connection_type": "rpc",
+ "manage_daemon": shouldManageDaemon("DOGE"),
+ "rpchost": DOGE_RPC_HOST,
+ "rpcport": DOGE_RPC_PORT + port_offset,
+ "onionport": DOGE_ONION_PORT + port_offset,
+ "datadir": os.getenv("DOGE_DATA_DIR", os.path.join(data_dir, "dogecoin")),
+ "bindir": os.path.join(bin_dir, "dogecoin"),
+ "use_segwit": False,
+ "use_csv": False,
"blocks_confirmed": 2,
- "rpctimeout": 60,
- "walletrpctimeout": 120,
- "walletrpctimeoutlong": 300,
- "core_version_no": getKnownVersion("wownero"),
- "core_type_group": "xmr",
+ "conf_target": 2,
+ "core_version_no": getKnownVersion("dogecoin"),
+ "core_version_group": 23,
+ "min_relay_fee": 0.01, # RECOMMENDED_MIN_TX_FEE
},
}
@@ -2593,9 +2624,8 @@ def main():
coin_settings["wallet_name"] = set_name
ticker: str = coin_params["ticker"]
- if toBool(os.getenv(ticker + "_USE_DESCRIPTORS", False)):
-
- if coin_id not in (Coins.BTC,):
+ if getDescriptorWalletOption(coin_params):
+ if coin_id not in (Coins.BTC, Coins.NMC):
raise ValueError(f"Descriptor wallet unavailable for {coin_name}")
coin_settings["use_descriptors"] = True
diff --git a/basicswap/bin/run.py b/basicswap/bin/run.py
index 091e857..c34c721 100755
--- a/basicswap/bin/run.py
+++ b/basicswap/bin/run.py
@@ -265,7 +265,11 @@ def getCoreBinArgs(coin_id: int, coin_settings, prepare=False, use_tor_proxy=Fal
# As BCH may use port 8334, disable it here.
# When tor is enabled a bind option for the onionport will be added to bitcoin.conf.
# https://github.com/bitcoin/bitcoin/blob/master/doc/release-notes/release-notes-28.0.md?plain=1#L84
- if prepare is False and use_tor_proxy is False and coin_id == Coins.BTC:
+ if (
+ prepare is False
+ and use_tor_proxy is False
+ and coin_id in (Coins.BTC, Coins.NMC)
+ ):
port: int = coin_settings.get("port", 8333)
extra_args.append(f"--bind=0.0.0.0:{port}")
return extra_args
diff --git a/basicswap/chainparams.py b/basicswap/chainparams.py
index 7ed0935..efbb58b 100644
--- a/basicswap/chainparams.py
+++ b/basicswap/chainparams.py
@@ -58,6 +58,8 @@ chainparams = {
"bip44": 44,
"min_amount": 100000,
"max_amount": 10000000 * COIN,
+ "ext_public_key_prefix": 0x696E82D1,
+ "ext_secret_key_prefix": 0x8F1DAEB8,
},
"testnet": {
"rpcport": 51935,
@@ -69,6 +71,8 @@ chainparams = {
"bip44": 1,
"min_amount": 100000,
"max_amount": 10000000 * COIN,
+ "ext_public_key_prefix": 0xE1427800,
+ "ext_secret_key_prefix": 0x04889478,
},
"regtest": {
"rpcport": 51936,
@@ -80,6 +84,8 @@ chainparams = {
"bip44": 1,
"min_amount": 100000,
"max_amount": 10000000 * COIN,
+ "ext_public_key_prefix": 0xE1427800,
+ "ext_secret_key_prefix": 0x04889478,
},
},
Coins.BTC: {
@@ -251,29 +257,38 @@ chainparams = {
"rpcport": 8336,
"pubkey_address": 52,
"script_address": 13,
+ "key_prefix": 180,
"hrp": "nc",
"bip44": 7,
"min_amount": 100000,
"max_amount": 10000000 * COIN,
+ "ext_public_key_prefix": 0x0488B21E, # base58Prefixes[EXT_PUBLIC_KEY]
+ "ext_secret_key_prefix": 0x0488ADE4,
},
"testnet": {
"rpcport": 18336,
"pubkey_address": 111,
"script_address": 196,
+ "key_prefix": 239,
"hrp": "tn",
"bip44": 1,
"min_amount": 100000,
"max_amount": 10000000 * COIN,
"name": "testnet3",
+ "ext_public_key_prefix": 0x043587CF,
+ "ext_secret_key_prefix": 0x04358394,
},
"regtest": {
"rpcport": 18443,
"pubkey_address": 111,
"script_address": 196,
+ "key_prefix": 239,
"hrp": "ncrt",
"bip44": 1,
"min_amount": 100000,
"max_amount": 10000000 * COIN,
+ "ext_public_key_prefix": 0x043587CF,
+ "ext_secret_key_prefix": 0x04358394,
},
},
Coins.XMR: {
diff --git a/basicswap/config.py b/basicswap/config.py
index 9c8d06d..cc010a0 100644
--- a/basicswap/config.py
+++ b/basicswap/config.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
-# Copyright (c) 2019-2024 The Basicswap developers
+# Copyright (c) 2019-2025 The Basicswap developers
# Distributed under the MIT software license, see the accompanying
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
@@ -40,13 +40,6 @@ DOGECOIND = os.getenv("DOGECOIND", "dogecoind" + bin_suffix)
DOGECOIN_CLI = os.getenv("DOGECOIN_CLI", "dogecoin-cli" + bin_suffix)
DOGECOIN_TX = os.getenv("DOGECOIN_TX", "dogecoin-tx" + bin_suffix)
-NAMECOIN_BINDIR = os.path.expanduser(
- os.getenv("NAMECOIN_BINDIR", os.path.join(DEFAULT_TEST_BINDIR, "namecoin"))
-)
-NAMECOIND = os.getenv("NAMECOIND", "namecoind" + bin_suffix)
-NAMECOIN_CLI = os.getenv("NAMECOIN_CLI", "namecoin-cli" + bin_suffix)
-NAMECOIN_TX = os.getenv("NAMECOIN_TX", "namecoin-tx" + bin_suffix)
-
XMR_BINDIR = os.path.expanduser(
os.getenv("XMR_BINDIR", os.path.join(DEFAULT_TEST_BINDIR, "monero"))
)
diff --git a/basicswap/interface/btc.py b/basicswap/interface/btc.py
index 618ddec..b8656c8 100644
--- a/basicswap/interface/btc.py
+++ b/basicswap/interface/btc.py
@@ -1862,20 +1862,70 @@ class BTCInterface(Secp256k1Interface):
"Could not find address with enough funds for proof",
)
- self._log.debug("sign_for_addr %s", sign_for_addr)
+ self._log.debug(f"sign_for_addr {sign_for_addr}")
+ funds_addr: str = sign_for_addr
if (
self.using_segwit()
): # TODO: Use isSegwitAddress when scantxoutset can use combo
# 'Address does not refer to key' for non p2pkh
pkh = self.decodeAddress(sign_for_addr)
sign_for_addr = self.pkh_to_address(pkh)
- self._log.debug("sign_for_addr converted %s", sign_for_addr)
+ self._log.debug(f"sign_for_addr converted {sign_for_addr}")
- signature = self.rpc_wallet(
- "signmessage",
- [sign_for_addr, sign_for_addr + "_swap_proof_" + extra_commit_bytes.hex()],
- )
+ if self._use_descriptors:
+ # https://github.com/bitcoin/bitcoin/issues/10542
+ # https://github.com/bitcoin/bitcoin/issues/26046
+ priv_keys = self.rpc_wallet(
+ "listdescriptors",
+ [
+ True,
+ ],
+ )
+ addr_info = self.rpc_wallet(
+ "getaddressinfo",
+ [
+ funds_addr,
+ ],
+ )
+ hdkeypath = addr_info["hdkeypath"]
+
+ sign_for_address_key = None
+ for descriptor in priv_keys["descriptors"]:
+ if descriptor["active"] is False or descriptor["internal"] is True:
+ continue
+ desc = descriptor["desc"]
+ assert desc.startswith("wpkh(")
+ ext_key = desc[5:].split(")")[0].split("/", 1)[0]
+ ext_key_data = decodeAddress(ext_key)[4:]
+ ci_part = self._sc.ci(Coins.PART)
+ ext_key_data_part = ci_part.encode_secret_extkey(ext_key_data)
+ rv = ci_part.rpc_wallet(
+ "extkey", ["info", ext_key_data_part, hdkeypath]
+ )
+ extkey_derived = rv["key_info"]["result"]
+ ext_key_data = decodeAddress(extkey_derived)[4:]
+ ek = ExtKeyPair()
+ ek.decode(ext_key_data)
+ sign_for_address_key = self.encodeKey(ek._key)
+ break
+ assert sign_for_address_key is not None
+ signature = self.rpc(
+ "signmessagewithprivkey",
+ [
+ sign_for_address_key,
+ sign_for_addr + "_swap_proof_" + extra_commit_bytes.hex(),
+ ],
+ )
+ del priv_keys
+ else:
+ signature = self.rpc_wallet(
+ "signmessage",
+ [
+ sign_for_addr,
+ sign_for_addr + "_swap_proof_" + extra_commit_bytes.hex(),
+ ],
+ )
prove_utxos = [] # TODO: Send specific utxos
return (sign_for_addr, signature, prove_utxos)
diff --git a/basicswap/interface/nmc.py b/basicswap/interface/nmc.py
index cf9bae7..0214857 100644
--- a/basicswap/interface/nmc.py
+++ b/basicswap/interface/nmc.py
@@ -2,6 +2,7 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2020-2022 tecnovert
+# Copyright (c) 2025 The Basicswap developers
# Distributed under the MIT software license, see the accompanying
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
@@ -13,39 +14,3 @@ class NMCInterface(BTCInterface):
@staticmethod
def coin_type():
return Coins.NMC
-
- def getLockTxHeight(
- self,
- txid,
- dest_address,
- bid_amount,
- rescan_from,
- find_index: bool = False,
- vout: int = -1,
- ):
- self._log.debug("[rm] scantxoutset start") # scantxoutset is slow
- ro = self.rpc(
- "scantxoutset", ["start", ["addr({})".format(dest_address)]]
- ) # TODO: Use combo(address) where possible
- self._log.debug("[rm] scantxoutset end")
- return_txid = True if txid is None else False
- for o in ro["unspents"]:
- if txid and o["txid"] != txid.hex():
- continue
- # Verify amount
- if self.make_int(o["amount"]) != int(bid_amount):
- self._log.warning(
- "Found output to lock tx address of incorrect value: %s, %s",
- str(o["amount"]),
- o["txid"],
- )
- continue
-
- rv = {"depth": 0, "height": o["height"]}
- if o["height"] > 0:
- rv["depth"] = ro["height"] - o["height"]
- if find_index:
- rv["index"] = o["vout"]
- if return_txid:
- rv["txid"] = o["txid"]
- return rv
diff --git a/basicswap/pgp/keys/bitcoincash_Calin_Culianu.pgp b/basicswap/pgp/keys/bitcoincash_Calin_Culianu.pgp
new file mode 100644
index 0000000..7ddba13
--- /dev/null
+++ b/basicswap/pgp/keys/bitcoincash_Calin_Culianu.pgp
@@ -0,0 +1,25 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQMuBFmZ6L4RCACuqDDCIe2bzKznyKVN1aInzRQnSxdGTXuw0mcDz5HYudAhBjR8
+gY6sxCRPNxvZCJVDZDpCygXMhWZlJtWLR8KMTCXxC4HLXXOY4RxQ5KGnYWxEAcKY
+deq1ymmuOuMUp7ltRTSyWcBKbR9xTd2vW/+0W7GQIOxUW/aiT1V0x3cky+6kqaec
+BorP3+uxJcx0Q8WdlS/6N4x3pBv/lfsdrZSaDD8fU/29pQGMDUEnupKoWJVVei6r
+G+vxLHEtIFYYO8VWjZntymw3dl+aogrjyuxqWzl8mfPi9M/DgiRb4pJnH2yOGDI6
+Lvg+oo9E79Vwi98UjYSicsB1dtcptKiA96UXAQD/hDB+dil7/SX/SDTlaw/+uTdd
+Xg0No63dbN++iY4k3Qf/Xk1ZzbuDviLhe+zEhlJOw6TaMlxfwwQOtxEJXILS5uIL
+jYlGcDbBtJh3p4qUoUduDOgjumJ9m47XqIq81rQ0pqzzGMbK1Y82NQjX5Sn8yTm9
+p1hmOZ/uX9vCrUSbYBjxJXyQ1OXlerlLRLfBf5WQ0+LO+0cmgtCyX0zV4oGK7vph
+XEm7lar7AezOOXaSrWAB+CTPUdJF1E7lcJiUuMVcqMx8pphrH+rfcsqPtN6tkyUD
+TmPDpc5ViqFFelEEQnKSlmAY+3iCNZ3y/VdPPhuJ2lAsL3tm9MMh2JGV378LG45a
+6SOkQrC977Qq1dhgJA+PGJxQvL2RJWsYlJwp79+Npgf9EfFaJVNzbdjGVq1XmNie
+MZYqHRfABkyK0ooDxSyzJrq4vvuhWKInS4JhpKSabgNSsNiiaoDR+YYMHb0H8GRR
+Za6JCmfU8w97R41UTI32N7dhul4xCDs5OV6maOIoNts20oigNGb7TKH9b5N7sDJB
+zh3Of/fHCChO9Y2chbzU0bERfcn+evrWBf/9XdQGQ3ggoLbOtGpcUQuB/7ofTcBZ
+awL6K4VJ2Qlb8DPlRgju6uU9AR/KTYeAlVFC8FX7R0FGgPRcJ3GNkNHGqrbuQ72q
+AOhYOPx9nRrU5u+E2J325vOabLnLbOazze3j6LFPSFV4vfmTO9exYlwhz3g+lFAd
+CrQ2Q2FsaW4gQ3VsaWFudSAoTmlsYWNUaGVHcmltKSA8Y2FsaW4uY3VsaWFudUBn
+bWFpbC5jb20+iHoEExEIACIFAlmZ6L4CGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4B
+AheAAAoJECGBClQgMcAsU5cBAO/ngONpHsxny2uTV4ge2f+5V2ajTjcIfN2jUZtg
+31jJAQCl1NcrwcIu98+aM2IyjB1UFXkoaMANpr8L9jBopivRGQ==
+=cf8I
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/basicswap/pgp/keys/namecoin_JeremyRand.pgp b/basicswap/pgp/keys/namecoin_JeremyRand.pgp
deleted file mode 100644
index 0e0ce2a..0000000
--- a/basicswap/pgp/keys/namecoin_JeremyRand.pgp
+++ /dev/null
@@ -1,14 +0,0 @@
------BEGIN PGP PUBLIC KEY BLOCK-----
-
-mDMEXPNfCBYJKwYBBAHaRw8BAQdAWGFiEJYnlV2TDTesLIO/eoQ3IPduzcG97GpA
-6K+Gj+K0K0BKZXJlbXlSYW5kIG9uIEdpdEh1YiA8amVyZW15QG5hbWVjb2luLm9y
-Zz6IlgQTFggAPhYhBJza8EpykDv+wJWdvi2+M54p9ilMBQJc88q7AhsDBQkB4TOA
-BQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJEC2+M54p9ilMMUoA/1oZn8AtwQ7D
-wXgNKq++zqHaiEcHGgsyFeDRbQARsYRVAQDxa36p181id1YuMjeV1KhC5vaDS4nY
-GB4FHPsQ4bbqDLRESmVyZW15IFJhbmQgKE5hbWVjb2luIENvcmUgR2l0aWFuIFNp
-Z25pbmcgS2V5KSA8amVyZW15QG5hbWVjb2luLm9yZz6ImQQTFggAQQIbAwUJAeEz
-gAULCQgHAgYVCgkICwIEFgIDAQIeAQIXgBYhBJza8EpykDv+wJWdvi2+M54p9ilM
-BQJc9WDrAhkBAAoJEC2+M54p9ilMz3IA/3mCKeFYcEJFlwP43mdIMGOV2zt/R4Fn
-z/rBJpv5hFoHAQDXAY8+mbY/9N+5Rn8Iy51tXEaTq3khdruuFFdty+bXAg==
-=EpnJ
------END PGP PUBLIC KEY BLOCK-----
diff --git a/basicswap/pgp/keys/namecoin_RoseTuring.pgp b/basicswap/pgp/keys/namecoin_RoseTuring.pgp
new file mode 100644
index 0000000..97c8076
--- /dev/null
+++ b/basicswap/pgp/keys/namecoin_RoseTuring.pgp
@@ -0,0 +1,52 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQINBGdeBqoBEADuBizUBhm1m34OQ0rnqUONvkfL3tGsriWuX0n3Bq9rhf3I3kZk
+5fi+R0Jj6jmz+sbUYRULU35S6eeIY77eYiveWl81H+3JAu8kmo/S6gegINnsPM/g
+F7X2P757gQdHMAE0olME3iGfXNpLg/e0OBv3j45eimjvUejgE7eI0e4gjajq8hyf
+bizMrGT+5I2PE0g3h07NqN3OuI5xVYujuZp41EgxY99QgYm5qEoU0wMGy8+F7gXV
+0htjhvUZcSGGpixP5+kaJJXFAP1TkZ/jqya6vy7LLeEEEuU8eMWhViOmzIjqoOFW
+Mq+2rJUrzNEk43tXW5LU+DdGl90HQcXPmQP3aWL27Dx/4AcTMYPDB/0bJrU9qF9Y
+9zfJV2HcNMnkhEb9XKDwkA6m3Jx2gfYG6HoMKp6bWSWsODItEgL1taoy35OnaVSM
+NWb857DC6p6n+eQUXUNx/1ct4LWmf4lN4Uf61i4mD+hkc4cWmRLAh7vTqMGG4xmb
+8Tb3wss8mEXzJvWVP4+bE6EkNPMCVAQleD4ePItaDg3lSJH/cIueIz6NDl5ik07r
+AZOZTxhhGU1CD8NkxQKoZLZ6GgjHDEwiUbxaCoD0FAzqtG5/at+jiwyDmCsJ96aE
+f0tPLXKOOc62BbqsAUuEOIooGwX/swXrhS4Xvfh8GxBYFBlRponoWXG7XQARAQAB
+tEhSb3NlIFR1cmluZyAoUm9zZSBUdXJpbmcncyBzaWduaW5nIGtleSBmb3IgZGV2
+IHdvcmsuKSA8cm9zZXR1cmluZ0BwbS5tZT6JAk4EEwEKADgWIQT9g2aoB6mfon/Z
+zOqf47/dpsU0lQUCZ14GqgIbAwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRCf
+47/dpsU0lTjfD/9WkMBWlbYhJwRU6JrdZdIPsj2jlMIDYEHXxFo+h1lNn1SLKKrE
+4c/+9+H0YGM03pL5ZTtydsxdPMTbAP5l24hBFpokySds3abOcKaPuNcct5BDWiiL
+UxsnV3SxCAsN3QcBt+0tYFYP9yIMkko9BRwsY7pSpjZOSCx26jeTKj7M4XQGdcpT
+4KMtzXe2s8ss1jLyuaDP2B5ikrFI+IZ5dHVBhohK3ug1y0SzHjfSYeskOEYSgJ/4
+uRUJCItWxrkSh16qRz+NFxwsewqIKz8Q0EmpHx4WpAii8z29IFPYKJEqdwcuPyF3
+7SiqAow4tY+CtnLAUYEbSiL52e8W/U8KSnrxqhkpMd5wZ28z+k682A5uEQn5YjOy
+7dBRjytSC2S87FJ+3zp4OtToDio8Wi0zpZWj/BD5K9raE2ct6Uiw3NG6JI8A7yaJ
+pEENfMpxMgKc8G5t8NfiZdDFDw+P+bd6sMAk3q7ZFe/o0zJcsbhtYacBFvwBpeIp
+HZnLdUQlKrZoASku7biTZyt7BBJZuNdVv6Q/K+pigJxTYCZNbbx9s/lzS6KGUKuD
+yi7n/1qYFXVFktomR+Cm045btVNeAQpnfIKiJS77FNeB5saSWEAOcCMtUkoR74lA
+9MGYdeWrPjvdeBu+Muvo/y1h57sVMwvStrXjGrJNs6KBcmvITXrek0osbrkCDQRn
+XgaqARAAu8bgP9AbeNatYshdG1xoYv20FeC0MUz0oYu+FvVuhvaAePl/VFFBlh3O
+CsCzJ+a+/hyeW22ZGZl62yblvlZcSTw1/WOv5zboFVVLD58/iiz3dCYAUUTQ2OaI
++oMLTCmZ/+GIcuVM1ZZMEohvR9eLcyzY89CgOi8R9+agqTXxNg7Uj43tPkgY2vc0
+v66od1SrOAisduXVDAiqTbc6nax9d9aYt27zQlGfuVo5J//rnteHiGA7VphDLlCR
++dra1ZGjbdOieSyhxiEAkBPY2js6UqO/CoRn9uHaTSv4MJqzzMOzLfPni+6y3FqH
+qaUoe3vr07Ehf85gBEL4IBiux/WL3Vi1WceqvNkS9aC0MVnnEgHbyAy2R6pWrtN5
+vlxdrkqQcnnnYHvOupG5KPsgT/CFK0jGfA23I/dBPuI372EcqFLFpAB4q14cSLQE
+ZER81pK7Q445vTv9qQIPu34oq0mg7GWlunduI4v7uGN+oSYIW0kfNLRnM4QjNhTP
+07LJZLZoCRW2MyPqTbk8cM0UQDGFOozcjlSgSZSABLdHpnudArl6fzkMi4VH8WNS
+JNXvtL2yX8cnOWXuOgK5pFuhr6zeRaHsjlMXgR5ZPSCiq0aMR4upk5n/Mn64qGVm
+EnxDEBiGfgL1sl+GGl+rYxvH8vYEEX3fjTtlsaImUzKByfLaY60AEQEAAYkCNgQY
+AQoAIBYhBP2DZqgHqZ+if9nM6p/jv92mxTSVBQJnXgaqAhsMAAoJEJ/jv92mxTSV
++0wP/itANwrdF+9kolUUVJg8Vkx7IgIGlcdIiUTxPAu9c8JdTKpziy9q7oVVpzLf
+zo+4qgzXGUGuGtcHdM8XSFYQ8CAuuOdvPUvtKbNQiZ1DVjoS/wk4vrzIvLTS1VVd
+f4jTgOImx3Tk75/8KX3EpCk26orMMBCHk7nWWia1KF8X2K2Hu1DZ9GqsWlE/uAPN
+tS/+ONlbn6tlk1XWDvFC8DkDkRWNRPva++GP5ACylybOHy2rqWKNEtetYflDuMIc
+5tkrXZ/rdZgzASKzSrNlEjN2DEBjl15WjUppOPkSc4QPK+SVza6UZJaE7oOrIOqs
+tQRchspkyDFreCuK/WZLZC8SUwZ5rzbOsFMLUHeZtFtNkJGxwF1ZUNHbNPPCEaCN
+oqNu/nkjxFqeydJfqDM8K8An9dQE2GkUm1nACpuLNgpILXebdG7ItVbbkjosx7HI
+0i3BXHeQzT+xY1gmuFFGEVCf9bZVmYspXJaiRGFRfGVyc6mMtdow7urb/A9g5Jqb
+Dkc+p29y9hCeOAVZfTY2C/GlWu9X/E64WJ2mQ3ujhtJmSgLM4ieYJU+lxosOC6BW
+EjFrTOeLa+myW7qm+/R6Mo/545s1qXvXnDL5Z4aVkSHtUu+fiWBa4f4WaH3mxAAg
+XLVwKhulQ3wPaCehbbMPbsQ+091iAOo+hn9s2BPfehM0ltgI
+=atlH
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/basicswap/pgp/keys/particl_tecnovert.pgp b/basicswap/pgp/keys/particl_tecnovert.pgp
index fdc95c3..833df15 100644
--- a/basicswap/pgp/keys/particl_tecnovert.pgp
+++ b/basicswap/pgp/keys/particl_tecnovert.pgp
@@ -1,78 +1,29 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
-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
-XHovfCfpcB/C
-=0Wkp
+mQINBFlLyYIBEADW3oJnVMDC94g+7OB1/IBUYNevCqJIOAtC0eeFS5g0XGvvqRLx
+2NLUqn5te+R7deoGElkZFJLLxFUwEnhqGCRH50Iou5aanUzvgI5fVAbK3k0fp9vc
+LKCR0fQVIidcLyqMpkLZo8BSE3+BWxFp/r2OHvh2dYtJC+BZVwblkDS3cqwKvUZx
+IocvDs47Wo3tzZfEsqUavbbiGx+Dm0fCV7TVHdVLU7q3bZsHSRiyTUZ2EAApoAmT
+ir9csVxv2IM8yf6/HwWi6/Lp7dgSG1+qBZ1lUPPTY+dFLPZyt/kul+vuOj6GLZaU
+s3D66d7TaPCHKWAOnP9RHpic/iXODXVXo1KHJfa0x8fW7I+y7/Gb+5x/m4O0Bz2T
+BivdrSAuFpXkPqwawlw4CPgI9fc801g83+ZFzD2jJ6qxkEgfnlmf+zGNn5tC4N5j
+NRTQ+GyHo1w4824SXcSN590wgz8goGJC3QPJxbifvOA8GzQIVzpxHckofOVyqIEq
+qSnkP2xn4mELqD7HcFnoojZBqFbF2cN+oWQ+niLN+v4qrUncpQI9SVWlyp66S+1T
+BhBQj2QuX+3B+K27EiDbhNV7EX6xEbGsnB1poMc2aMiz6veybW3GnoM+2ppr8Ko/
+12Ij7l+ZA44t6PWUfQQbNSbUk/0Yhd9QJ8VQVck+TaS6gtarTbURlSdmHwARAQAB
+tCl0ZWNub3ZlcnQgKGdpdGlhbikgPHRlY25vdmVydEBwYXJ0aWNsLmlvPokCVAQT
+AQgAPhYhBI5RfcEuwcw39kI6ihPxNlHJzw1rBQJZS8mCAhsDBQkSzAMABQsJCAcC
+BhUICQoLAgQWAgMBAh4BAheAAAoJEBPxNlHJzw1rtdYP/22iRX8O2Q++MayPHNx5
+XHAlMk9mfi5FB1qJwshtlhda7P9U/hOTi227wH+Mzh5dBje4t2DkoHzxlz/Wr4cQ
+QUJMOYd0OEZY6kpAQkvtyYobIb6zlRQK1koAfNMxewmfZZGTlr16IUVCovGSFvZ+
+hdYRDEjuHqXjpwBfrxFAy/HCnfY10qSRkJc5w1ypj1IkzlanS+xeRJSDvRTQDAEr
+zv3xKcMGjCCHaaCP+tyAaViBaUOlvmZdWwg0gwQCuPLqIh0cfDbcg0quciRIpnyp
+zINmfwngZCwXdIYfAzmCzMHw1J3iOiqfqK0EcpHMsL689VyQSPgsoEHtcOGHYjRL
+pMPGvRFHtICrnCHENK3IcwFWDGXW+i3zgOlA7g48yYWWvSup+t8I6YT+FeeFlxSO
+dj1GdeMA0O7gXZ7znLVduokL2Ef4dZjc+3NwBlFov52vwCZwQMAGsMriwEDB2rDZ
+B7YOvAxlUB/kavtx/oE8fV7mZcuwYg02lq4bozF9xlhjOFaRit6xXnLVi0TuI76c
+uz67nB9VkWczSLIzCyjNyFpWbx1BMxTYfehZX3+YNajXwG6HdEp9CAYK0u46Guz/
+Pth67bbNVYyP/cuOIrv/hqQ6xo4mOBMDDxcCEAXx3rwxfbxNM8vlwrMcpITrtNON
+r41bcxUIfMEDefPm5wnXep8W
+=szpX
-----END PGP PUBLIC KEY BLOCK-----
diff --git a/basicswap/pgp/keys/wownero_wowario.pgp b/basicswap/pgp/keys/wownero_wowario.pgp
new file mode 100644
index 0000000..fb6078b
--- /dev/null
+++ b/basicswap/pgp/keys/wownero_wowario.pgp
@@ -0,0 +1,29 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQINBGROehcBEACXWWc6dHqCos1PmKI32iHi0jP3mYM3jU57YxbjwT78QEtEwSqf
+YklpXkgTYq7jexx2JElfegM6w1sPYarq1y051RjnCgzl32da5I506SMvcJTmXumV
+Rw6erPeDxAO74PflDSlALgtGOgbKhwwWRudbWgT5hKGkl62qy0mI6GStul0rbT+3
+gq77DCGyURfe1PG1pymhO5XVz3WGtOa12NvRA+3wGIcqIji2MbtXuOhGMg//kVI5
+m2vcfHyMMuQ01xUXRu57WxRujYaJ1RB4p86JCbDX3YU2XlzTxGAhqChDLuJGqo54
+AZMUWDceftXsAoOqH8Hwmm5gFkYSpMt86ZT+umvWygmxohD5k85MuRj4AGagFj/u
+CMcQjI/SN1UU/Qozg6VL/5FO8aH9IybDzX7eE3j0V/jTweStw1CIUajYgfemWOWl
+whLPBDflRz/8EEqTN0CaSSaiYiULZUiawBO/bRIiCO2Q6QrAi3KpPUhCwiw/Yecd
+rAMLH7bytpECDdbNonQ/VMxWwtWJQ87qBtWvHFQxXBKjyuANsKL9X7v3KcYOUdd2
+fSt7eqE9GDT4DbK6sTmuTpq2TgHXET0cA39+N2zxTh5xFupI/pi2iAHJ6hgIiQnn
+662TngjGOSFvrTV/51Ua0Vx8OCMJJOcRdOVaYzuzg9DsjVcJin3aRqUh4wARAQAB
+tCBXb3dhcmlvIDx3b3dhcmlvQHByb3Rvbm1haWwuY29tPokCVAQTAQgAPhYhBKs6
+L3JYGPz/J5SEHHk1BLRJxpIgBQJkTnoXAhsDBQkHhh77BQsJCAcCBhUKCQgLAgQW
+AgMBAh4BAheAAAoJEHk1BLRJxpIgwgEP/109vw1WXRh9EaRr3Y1+sBi+/PRQ5TCx
+UEcP9ru5sQPJ0BsZK8RYw0BNIfDQX9OB1k/AoiBelL+0EoDKvjXmwz9fPUmSVk5r
+3RzfClXTnxn4HXPKkSGMt4WBUnvohTexK7CPkb9xy+K0Jtx8XF1XiQLDFg2a9lBj
+IIX2H6aHn4VjdUBv7TrTCAI2Vg0cQUpeJUwyHH+lk0r2WM3zAxzS3Iy2yDDstNT8
+audXEX4BtJhyEU1m57jwgscrbTtgwYOAsaRLcnUaAFWhbov3IiGInk7N1fkMsuW5
+HE5RcegSZRS3X4o6O/nmwdSjCEB9weydOCPrtfdbvfvuTiMg/jZBikOk/Sj7FM/D
+eZKghSHpLbT/V3S76FyIcc/xFkUmR+2fGvCNjJ1Qn2lXTS8xcbyzqR4LZPeUGppV
+hvriilLnXSjyc60wuD3kmCCo1Zw4tNL8pr09BtVmScUy6eiwca8LLzvbbivqxF1g
+Mrkkv8yQE0ZwO1kgNSn+PSzUPbwAoklcyN5Rhr5DxZh0UudiH5Jt5WWYeE8O2Uc1
+si13X575kymGkkeiUcp9WtBkh2uial+RVmTrUTDUTIR2HzT6MAR84/DHlC5dsW8a
+h4uDUhzeG2cTxuIfZC881UHKL+xT/I3PPuFdLbU5uoWJpXYpxKYulYWd7LA/k4bi
+JWBrQo7VDvvP
+=H3wS
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/basicswap/static/images/coins/Namecoin-20.png b/basicswap/static/images/coins/Namecoin-20.png
new file mode 100644
index 0000000..204808d
Binary files /dev/null and b/basicswap/static/images/coins/Namecoin-20.png differ
diff --git a/basicswap/static/images/coins/Namecoin.png b/basicswap/static/images/coins/Namecoin.png
new file mode 100644
index 0000000..4e8f2d6
Binary files /dev/null and b/basicswap/static/images/coins/Namecoin.png differ
diff --git a/basicswap/static/js/bids_available.js b/basicswap/static/js/bids_available.js
index 3cb11e8..53d5251 100644
--- a/basicswap/static/js/bids_available.js
+++ b/basicswap/static/js/bids_available.js
@@ -10,6 +10,7 @@ const COIN_NAME_TO_SYMBOL = {
'Firo': 'FIRO',
'Dash': 'DASH',
'Decred': 'DCR',
+ 'Namecoin': 'NMC',
'Wownero': 'WOW',
'Bitcoin Cash': 'BCH',
'Dogecoin': 'DOGE'
@@ -335,13 +336,13 @@ const createBidTableRow = async (bid) => {
-
Bid ID:
+
Bid ID:
${formatAddress(bid.bid_id)}
@@ -366,8 +367,8 @@ const createBidTableRow = async (bid) => {
-
@@ -375,15 +376,14 @@ const createBidTableRow = async (bid) => {
-
-
@@ -410,7 +410,7 @@ const createBidTableRow = async (bid) => {
-
Accept
@@ -506,13 +506,13 @@ const createDetailsColumn = (bid, identity, uniqueId) => `
- Bid ID:
+ Bid ID:
${formatAddress(bid.bid_id)}
diff --git a/basicswap/static/js/modules/api-manager.js b/basicswap/static/js/modules/api-manager.js
index 9f299e1..e166593 100644
--- a/basicswap/static/js/modules/api-manager.js
+++ b/basicswap/static/js/modules/api-manager.js
@@ -220,7 +220,7 @@ const ApiManager = (function() {
.filter(coin => coin.usesCoinGecko)
.map(coin => coin.name)
.join(',') :
- 'bitcoin,monero,particl,bitcoincash,pivx,firo,dash,litecoin,dogecoin,decred';
+ 'bitcoin,monero,particl,bitcoincash,pivx,firo,dash,litecoin,dogecoin,decred,namecoin';
//console.log('Fetching coin prices for:', coins);
const response = await this.fetchCoinPrices(coins);
@@ -254,7 +254,7 @@ const ApiManager = (function() {
.filter(coin => coin.usesCoinGecko)
.map(coin => getCoinBackendId ? getCoinBackendId(coin.name) : coin.name)
.join(',') :
- 'bitcoin,monero,particl,bitcoin-cash,pivx,firo,dash,litecoin,dogecoin,decred';
+ 'bitcoin,monero,particl,bitcoin-cash,pivx,firo,dash,litecoin,dogecoin,decred,namecoin';
const url = `https://api.coingecko.com/api/v3/simple/price?ids=${coins}&vs_currencies=usd&include_24hr_vol=true&include_24hr_change=true`;
diff --git a/basicswap/static/js/modules/cache-manager.js b/basicswap/static/js/modules/cache-manager.js
index e8fba7c..1deddc8 100644
--- a/basicswap/static/js/modules/cache-manager.js
+++ b/basicswap/static/js/modules/cache-manager.js
@@ -504,13 +504,14 @@ const CacheManager = (function() {
'bitcoin': 'BTC',
'litecoin': 'LTC',
'monero': 'XMR',
+ 'wownero': 'WOW',
'particl': 'PART',
'pivx': 'PIVX',
'firo': 'FIRO',
'zcoin': 'FIRO',
'dash': 'DASH',
'decred': 'DCR',
- 'wownero': 'WOW',
+ 'namecoin': 'NMR',
'bitcoin-cash': 'BCH',
'dogecoin': 'DOGE'
};
diff --git a/basicswap/static/js/modules/config-manager.js b/basicswap/static/js/modules/config-manager.js
index 1176cc3..0b70751 100644
--- a/basicswap/static/js/modules/config-manager.js
+++ b/basicswap/static/js/modules/config-manager.js
@@ -72,6 +72,7 @@ const ConfigManager = (function() {
{ symbol: 'LTC', name: 'litecoin', usesCryptoCompare: true, usesCoinGecko: true, historicalDays: 30 },
{ symbol: 'DOGE', name: 'dogecoin', usesCryptoCompare: true, usesCoinGecko: true, historicalDays: 30 },
{ symbol: 'DCR', name: 'decred', usesCryptoCompare: true, usesCoinGecko: true, historicalDays: 30 },
+ { symbol: 'NMC', name: 'namecoin', usesCryptoCompare: true, usesCoinGecko: true, historicalDays: 30 },
{ symbol: 'WOW', name: 'wownero', usesCryptoCompare: false, usesCoinGecko: true, historicalDays: 30 }
],
@@ -88,6 +89,7 @@ const ConfigManager = (function() {
'Zcoin': 'FIRO',
'Dash': 'DASH',
'Decred': 'DCR',
+ 'Namecoin': 'NMC',
'Wownero': 'WOW',
'Bitcoin Cash': 'BCH',
'Dogecoin': 'DOGE'
@@ -105,13 +107,14 @@ const ConfigManager = (function() {
'Zcoin': 'Firo',
'Dash': 'Dash',
'Decred': 'Decred',
+ 'Namecoin': 'Namecoin',
'Wownero': 'Wownero',
'Bitcoin Cash': 'Bitcoin Cash',
'Dogecoin': 'Dogecoin'
},
idToName: {
- 1: 'particl', 2: 'bitcoin', 3: 'litecoin', 4: 'decred',
+ 1: 'particl', 2: 'bitcoin', 3: 'litecoin', 4: 'decred', 5: 'namecoin',
6: 'monero', 7: 'particl blind', 8: 'particl anon',
9: 'wownero', 11: 'pivx', 13: 'firo', 17: 'bitcoincash',
18: 'dogecoin'
@@ -130,6 +133,7 @@ const ConfigManager = (function() {
'litecoin': 'litecoin',
'dogecoin': 'dogecoin',
'decred': 'decred',
+ 'namecoin': 'namecoin',
'wownero': 'wownero'
}
},
@@ -367,6 +371,7 @@ const ConfigManager = (function() {
'dash': { usd: null, btc: null },
'dogecoin': { usd: null, btc: null },
'decred': { usd: null, btc: null },
+ 'namecoin': { usd: null, btc: null },
'litecoin': { usd: null, btc: null },
'particl': { usd: null, btc: null },
'pivx': { usd: null, btc: null },
diff --git a/basicswap/static/js/modules/wallet-manager.js b/basicswap/static/js/modules/wallet-manager.js
index b97f5b6..6b4b775 100644
--- a/basicswap/static/js/modules/wallet-manager.js
+++ b/basicswap/static/js/modules/wallet-manager.js
@@ -35,6 +35,7 @@ const WalletManager = (function() {
'Dash': 'DASH',
'PIVX': 'PIVX',
'Decred': 'DCR',
+ 'Namecoin': 'NMC',
'Bitcoin Cash': 'BCH'
},
@@ -49,6 +50,7 @@ const WalletManager = (function() {
'DASH': 'dash',
'PIVX': 'pivx',
'DCR': 'dcr',
+ 'NMC': 'nmc',
'BCH': 'bch'
},
@@ -63,6 +65,7 @@ const WalletManager = (function() {
'Dash': 'DASH',
'PIVX': 'PIVX',
'Decred': 'DCR',
+ 'Namecoin': 'NMC',
'Bitcoin Cash': 'BCH',
'Dogecoin': 'DOGE'
}
diff --git a/basicswap/static/js/offers.js b/basicswap/static/js/offers.js
index 1d534cf..355f3ec 100644
--- a/basicswap/static/js/offers.js
+++ b/basicswap/static/js/offers.js
@@ -34,6 +34,7 @@ window.tableRateModule = {
'Dash': 'DASH',
'PIVX': 'PIVX',
'Decred': 'DCR',
+ 'Namecoin': 'NMC',
'Zano': 'ZANO',
'Bitcoin Cash': 'BCH',
'Dogecoin': 'DOGE'
@@ -56,9 +57,9 @@ window.tableRateModule = {
},
setCachedValue(key, value, resourceType = null) {
- const ttl = resourceType ?
- window.config.cacheConfig.ttlSettings[resourceType] ||
- window.config.cacheConfig.defaultTTL :
+ const ttl = resourceType ?
+ window.config.cacheConfig.ttlSettings[resourceType] ||
+ window.config.cacheConfig.defaultTTL :
900000;
const item = {
@@ -306,13 +307,14 @@ async function calculateProfitLoss(fromCoin, toCoin, fromAmount, toAmount, isOwn
'ltc': 'litecoin',
'doge': 'dogecoin',
'dcr': 'decred',
+ 'nmc': 'namecoin',
'wow': 'wownero'
};
if (lowerCoin === 'zcoin') return 'firo';
if (lowerCoin === 'bitcoin cash') return 'bitcoin-cash';
if (lowerCoin === 'particl anon' || lowerCoin === 'particl blind') return 'particl';
-
+
return symbolToName[lowerCoin] || lowerCoin;
};
@@ -406,7 +408,7 @@ async function fetchLatestPrices() {
const coinIds = [
'bitcoin', 'particl', 'monero', 'litecoin',
'dogecoin', 'firo', 'dash', 'pivx',
- 'decred', 'bitcoincash'
+ 'decred', 'namecoin', 'bitcoincash'
];
let processedData = {};
@@ -419,7 +421,7 @@ async function fetchLatestPrices() {
if (mainResponse && mainResponse.rates) {
Object.entries(mainResponse.rates).forEach(([coinId, price]) => {
const normalizedCoinId = coinId === 'bitcoincash' ? 'bitcoin-cash' : coinId.toLowerCase();
-
+
processedData[normalizedCoinId] = {
usd: price,
btc: normalizedCoinId === 'bitcoin' ? 1 : price / (mainResponse.rates.bitcoin || 1)
@@ -453,7 +455,7 @@ async function fetchLatestPrices() {
} catch (error) {
console.error(`Price fetch attempt ${attempt + 1} failed:`, error);
NetworkManager.handleNetworkError(error);
-
+
if (attempt < MAX_RETRIES - 1) {
const delay = Math.min(500 * Math.pow(2, attempt), 5000);
await new Promise(resolve => setTimeout(resolve, delay));
@@ -520,7 +522,7 @@ async function fetchOffers() {
originalJsonData = [...jsonData];
latestPrices = pricesData || getEmptyPriceData();
-
+
CacheManager.set('offers_cached', jsonData, 'offers');
await updateOffersTable();
@@ -1353,7 +1355,7 @@ function createRateColumn(offer, coinFrom, coinTo) {
const getPriceKey = (coin) => {
const lowerCoin = coin.toLowerCase();
-
+
const symbolToName = {
'btc': 'bitcoin',
'xmr': 'monero',
@@ -1365,13 +1367,14 @@ function createRateColumn(offer, coinFrom, coinTo) {
'ltc': 'litecoin',
'doge': 'dogecoin',
'dcr': 'decred',
+ 'nmc': 'namecoin',
'wow': 'wownero'
};
-
+
if (lowerCoin === 'zcoin') return 'firo';
if (lowerCoin === 'bitcoin cash') return 'bitcoin-cash';
if (lowerCoin === 'particl anon' || lowerCoin === 'particl blind') return 'particl';
-
+
return symbolToName[lowerCoin] || lowerCoin;
};
@@ -1655,23 +1658,24 @@ function createTooltipContent(isSentOffers, coinFrom, coinTo, fromAmount, toAmou
'ltc': 'litecoin',
'doge': 'dogecoin',
'dcr': 'decred',
+ 'nmc': 'namecoin',
'wow': 'wownero'
};
if (lowerCoin === 'zcoin') return 'firo';
if (lowerCoin === 'bitcoin cash') return 'bitcoin-cash';
if (lowerCoin === 'particl anon' || lowerCoin === 'particl blind') return 'particl';
-
+
return symbolToName[lowerCoin] || lowerCoin;
};
-
+
if (latestPrices && latestPrices['firo'] && !latestPrices['zcoin']) {
latestPrices['zcoin'] = JSON.parse(JSON.stringify(latestPrices['firo']));
}
const fromSymbol = getPriceKey(coinFrom);
const toSymbol = getPriceKey(coinTo);
-
+
let fromPriceUSD = latestPrices && latestPrices[fromSymbol] ? latestPrices[fromSymbol].usd : null;
let toPriceUSD = latestPrices && latestPrices[toSymbol] ? latestPrices[toSymbol].usd : null;
@@ -1685,7 +1689,7 @@ function createTooltipContent(isSentOffers, coinFrom, coinTo, fromAmount, toAmou
isNaN(fromPriceUSD) || isNaN(toPriceUSD)) {
return ` Price Information Unavailable
Current market prices are temporarily unavailable.
- You are ${isSentOffers ? 'selling' : 'buying'} ${fromAmount.toFixed(8)} ${coinFrom}
+ You are ${isSentOffers ? 'selling' : 'buying'} ${fromAmount.toFixed(8)} ${coinFrom}
for ${toAmount.toFixed(8)} ${coinTo}.
Note:
Profit/loss calculations will be available when price data is restored. `;
@@ -1757,13 +1761,14 @@ function createCombinedRateTooltip(offer, coinFrom, coinTo, treatAsSentOffer) {
'ltc': 'litecoin',
'doge': 'dogecoin',
'dcr': 'decred',
+ 'nmc': 'namecoin',
'wow': 'wownero'
};
if (lowerCoin === 'zcoin') return 'firo';
if (lowerCoin === 'bitcoin cash') return 'bitcoin-cash';
if (lowerCoin === 'particl anon' || lowerCoin === 'particl blind') return 'particl';
-
+
return symbolToName[lowerCoin] || lowerCoin;
};
@@ -1876,7 +1881,7 @@ function clearFilters() {
jsonData = [...originalJsonData];
currentPage = 1;
-
+
const storageKey = isSentOffers ? 'sentOffersTableSettings' : 'networkOffersTableSettings';
localStorage.removeItem(storageKey);
@@ -2194,7 +2199,7 @@ async function initializeTableAndData() {
function loadSavedSettings() {
const storageKey = isSentOffers ? 'sentOffersTableSettings' : 'networkOffersTableSettings';
const saved = localStorage.getItem(storageKey);
-
+
if (saved) {
const settings = JSON.parse(saved);
@@ -2229,7 +2234,7 @@ document.addEventListener('DOMContentLoaded', async () => {
NetworkManager.initialize({
connectionTestEndpoint: '/json',
connectionTestTimeout: 3000,
- reconnectDelay: 5000,
+ reconnectDelay: 5000,
maxReconnectAttempts: 5
});
window.networkManagerInitialized = true;
@@ -2252,7 +2257,7 @@ document.addEventListener('DOMContentLoaded', async () => {
});
const tableLoadPromise = initializeTableAndData();
-
+
WebSocketManager.initialize({
debug: false
});
@@ -2262,7 +2267,7 @@ document.addEventListener('DOMContentLoaded', async () => {
if (!NetworkManager.isOnline()) {
return;
}
-
+
const endpoint = isSentOffers ? '/json/sentoffers' : '/json/offers';
const response = await fetch(endpoint);
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
@@ -2349,7 +2354,7 @@ async function cleanup() {
lastRefreshTime = null;
const domRefs = [
- 'offersBody', 'filterForm', 'prevPageButton', 'nextPageButton',
+ 'offersBody', 'filterForm', 'prevPageButton', 'nextPageButton',
'currentPageSpan', 'totalPagesSpan', 'lastRefreshTimeSpan', 'newEntriesCountSpan'
];
diff --git a/basicswap/static/js/pricechart.js b/basicswap/static/js/pricechart.js
index 1e785d1..b8b818a 100644
--- a/basicswap/static/js/pricechart.js
+++ b/basicswap/static/js/pricechart.js
@@ -548,7 +548,7 @@ const ui = {
},
setActiveContainer: (containerId) => {
- const containerIds = ['btc', 'xmr', 'part', 'pivx', 'firo', 'dash', 'ltc', 'doge', 'eth', 'dcr', 'zano', 'wow', 'bch'].map(id => `${id}-container`);
+ const containerIds = ['btc', 'xmr', 'part', 'pivx', 'firo', 'dash', 'ltc', 'doge', 'eth', 'dcr', 'nmc', 'zano', 'wow', 'bch'].map(id => `${id}-container`);
containerIds.forEach(id => {
const container = document.getElementById(id);
if (container) {
diff --git a/basicswap/static/js/swaps_in_progress.js b/basicswap/static/js/swaps_in_progress.js
index 3724bbd..8aeee3d 100644
--- a/basicswap/static/js/swaps_in_progress.js
+++ b/basicswap/static/js/swaps_in_progress.js
@@ -10,6 +10,7 @@ const COIN_NAME_TO_SYMBOL = {
'Firo': 'FIRO',
'Dash': 'DASH',
'Decred': 'DCR',
+ 'Namecoin': 'NMC',
'Wownero': 'WOW',
'Bitcoin Cash': 'BCH',
'Dogecoin': 'DOGE'
@@ -383,8 +384,8 @@ const createSwapTableRow = async (swap) => {
-
@@ -392,8 +393,8 @@ const createSwapTableRow = async (swap) => {
-
@@ -421,7 +422,7 @@ const createSwapTableRow = async (swap) => {
-
Details
diff --git a/basicswap/templates/offers.html b/basicswap/templates/offers.html
index eb04efb..7cb93b1 100644
--- a/basicswap/templates/offers.html
+++ b/basicswap/templates/offers.html
@@ -13,7 +13,7 @@

-
@@ -21,7 +21,7 @@
{{ page_type_description }}
-
{{ place_new_offer_svg | safe }}
Place new Offer
@@ -136,12 +136,13 @@
'ETH': {'name': 'Ethereum', 'symbol': 'ETH', 'image': 'Ethereum.png', 'show': false},
'DOGE': {'name': 'Dogecoin', 'symbol': 'DOGE', 'image': 'Dogecoin.png', 'show': true},
'DCR': {'name': 'Decred', 'symbol': 'DCR', 'image': 'Decred.png', 'show': true},
+ 'NMC': {'name': 'Namecoin', 'symbol': 'NMC', 'image': 'Namecoin.png', 'show': true},
'ZANO': {'name': 'Zano', 'symbol': 'ZANO', 'image': 'Zano.png', 'show': false},
'WOW': {'name': 'Wownero', 'symbol': 'WOW', 'image': 'Wownero.png', 'show': true}
}
%}
- {% set custom_order = ['BTC', 'ETH', 'XMR', 'PART', 'LTC', 'BCH', 'FIRO', 'PIVX', 'DASH', 'DOGE', 'DCR', 'ZANO', 'WOW'] %}
-
+ {% set custom_order = ['BTC', 'ETH', 'XMR', 'PART', 'LTC', 'BCH', 'FIRO', 'PIVX', 'DASH', 'DOGE', 'DCR', 'NMC', 'ZANO', 'WOW'] %}
+
{% if enabled_chart_coins is string %}
{% if enabled_chart_coins == "" %}
{% set display_coins = coin_data.keys()|list %}
diff --git a/tests/basicswap/common_xmr.py b/tests/basicswap/common_xmr.py
index 808ac7b..583901d 100644
--- a/tests/basicswap/common_xmr.py
+++ b/tests/basicswap/common_xmr.py
@@ -34,6 +34,11 @@ from tests.basicswap.common import (
PIVX_BASE_PORT,
BTC_USE_DESCRIPTORS,
)
+from tests.basicswap.extended.test_nmc import (
+ NMC_BASE_PORT,
+ NMC_BASE_RPC_PORT,
+ NMC_BASE_TOR_PORT,
+)
from tests.basicswap.extended.test_dcr import (
DCR_BASE_PORT,
DCR_BASE_RPC_PORT,
@@ -50,13 +55,6 @@ from tests.basicswap.extended.test_doge import (
import basicswap.config as cfg
import basicswap.bin.run as runSystem
-XMR_BASE_P2P_PORT = 17792
-XMR_BASE_RPC_PORT = 29798
-XMR_BASE_WALLET_RPC_PORT = 29998
-
-FIRO_BASE_PORT = 34832
-FIRO_BASE_RPC_PORT = 35832
-FIRO_RPC_PORT_BASE = int(os.getenv("FIRO_RPC_PORT_BASE", FIRO_BASE_RPC_PORT))
TEST_PATH = os.path.expanduser(os.getenv("TEST_PATH", "~/test_basicswap1"))
@@ -68,7 +66,21 @@ BITCOIN_RPC_PORT_BASE = int(os.getenv("BITCOIN_RPC_PORT_BASE", BTC_BASE_RPC_PORT
BITCOIN_TOR_PORT_BASE = int(os.getenv("BITCOIN_TOR_PORT_BASE", BTC_BASE_TOR_PORT))
LITECOIN_RPC_PORT_BASE = int(os.getenv("LITECOIN_RPC_PORT_BASE", LTC_BASE_RPC_PORT))
+
DECRED_RPC_PORT_BASE = int(os.getenv("DECRED_RPC_PORT_BASE", DCR_BASE_RPC_PORT))
+
+NAMECOIN_PORT_BASE = int(os.getenv("NAMECOIN_PORT_BASE", NMC_BASE_PORT))
+NAMECOIN_RPC_PORT_BASE = int(os.getenv("NAMECOIN_RPC_PORT_BASE", NMC_BASE_RPC_PORT))
+NAMECOIN_TOR_PORT_BASE = int(os.getenv("NAMECOIN_TOR_PORT_BASE", NMC_BASE_TOR_PORT))
+
+XMR_BASE_P2P_PORT = 17792
+XMR_BASE_RPC_PORT = 29798
+XMR_BASE_WALLET_RPC_PORT = 29998
+
+FIRO_BASE_PORT = 34832
+FIRO_BASE_RPC_PORT = 35832
+FIRO_RPC_PORT_BASE = int(os.getenv("FIRO_RPC_PORT_BASE", FIRO_BASE_RPC_PORT))
+
BITCOINCASH_RPC_PORT_BASE = int(
os.getenv("BITCOINCASH_RPC_PORT_BASE", BCH_BASE_RPC_PORT)
)
@@ -130,19 +142,21 @@ def run_prepare(
os.environ["BTC_RPC_PORT"] = str(BITCOIN_RPC_PORT_BASE)
os.environ["BTC_PORT"] = str(BITCOIN_PORT_BASE)
os.environ["BTC_USE_DESCRIPTORS"] = str(BTC_USE_DESCRIPTORS)
+ os.environ["BTC_ONION_PORT"] = str(BITCOIN_TOR_PORT_BASE)
os.environ["LTC_RPC_PORT"] = str(LITECOIN_RPC_PORT_BASE)
os.environ["DCR_RPC_PORT"] = str(DECRED_RPC_PORT_BASE)
+ os.environ["DCR_RPC_PWD"] = "dcr_pwd"
+ os.environ["NMC_RPC_PORT"] = str(NAMECOIN_RPC_PORT_BASE)
+ os.environ["NMC_PORT"] = str(NMC_BASE_PORT)
+ os.environ["NMC_ONION_PORT"] = str(NAMECOIN_TOR_PORT_BASE)
+ os.environ["XMR_RPC_USER"] = "xmr_user"
+ os.environ["XMR_RPC_PWD"] = "xmr_pwd"
os.environ["FIRO_RPC_PORT"] = str(FIRO_RPC_PORT_BASE)
os.environ["BCH_PORT"] = str(BCH_BASE_PORT)
os.environ["BCH_RPC_PORT"] = str(BITCOINCASH_RPC_PORT_BASE)
os.environ["DOGE_PORT"] = str(DOGE_BASE_PORT)
os.environ["DOGE_RPC_PORT"] = str(DOGECOIN_RPC_PORT_BASE)
- os.environ["XMR_RPC_USER"] = "xmr_user"
- os.environ["XMR_RPC_PWD"] = "xmr_pwd"
-
- os.environ["DCR_RPC_PWD"] = "dcr_pwd"
-
import basicswap.bin.prepare as prepareSystem
# Hack: Reload module to set env vars as the basicswap_prepare module is initialised if imported from elsewhere earlier
@@ -320,6 +334,62 @@ def run_prepare(
with open(config_filename, "a") as fp:
fp.write("enablevoting=1\n")
+ if "namecoin" in coins_array:
+ # Pruned nodes don't provide blocks
+ config_filename = os.path.join(datadir_path, "namecoin", "namecoin.conf")
+ with open(config_filename, "r") as fp:
+ lines = fp.readlines()
+ with open(config_filename, "w") as fp:
+ for line in lines:
+ if not line.startswith("prune"):
+ fp.write(line)
+ # fp.write("bind=127.0.0.1\n") # Causes BTC v28 to try and bind to bind=127.0.0.1:8444, even with a bind...=onion present
+ # listenonion=0 does not stop the node from trying to bind to the tor port
+ # https://github.com/bitcoin/bitcoin/issues/22726
+ fp.write(
+ "bind=127.0.0.1:{}=onion\n".format(
+ NAMECOIN_TOR_PORT_BASE + node_id + port_ofs
+ )
+ )
+ fp.write("dnsseed=0\n")
+ fp.write("discover=0\n")
+ fp.write("listenonion=0\n")
+ fp.write("upnp=0\n")
+ if use_rpcauth:
+ salt = generate_salt(16)
+ rpc_user = "test_nmc_" + str(node_id)
+ rpc_pass = "test_nmc_pwd_" + str(node_id)
+ fp.write(
+ "rpcauth={}:{}${}\n".format(
+ rpc_user, salt, password_to_hmac(salt, rpc_pass)
+ )
+ )
+ settings["chainclients"]["namecoin"]["rpcuser"] = rpc_user
+ settings["chainclients"]["namecoin"]["rpcpassword"] = rpc_pass
+ for ip in range(num_nodes):
+ if ip != node_id:
+ fp.write(
+ "connect=127.0.0.1:{}\n".format(
+ NAMECOIN_PORT_BASE + ip + port_ofs
+ )
+ )
+ for opt in EXTRA_CONFIG_JSON.get("ncm{}".format(node_id), []):
+ fp.write(opt + "\n")
+
+ if "monero" in coins_array:
+ with open(os.path.join(datadir_path, "monero", "monerod.conf"), "a") as fp:
+ fp.write("p2p-bind-ip=127.0.0.1\n")
+ fp.write(
+ "p2p-bind-port={}\n".format(XMR_BASE_P2P_PORT + node_id + port_ofs)
+ )
+ for ip in range(num_nodes):
+ if ip != node_id:
+ fp.write(
+ "add-exclusive-node=127.0.0.1:{}\n".format(
+ XMR_BASE_P2P_PORT + ip + port_ofs
+ )
+ )
+
if "pivx" in coins_array:
# Pruned nodes don't provide blocks
config_filename = os.path.join(datadir_path, "pivx", "pivx.conf")
@@ -388,20 +458,6 @@ def run_prepare(
for opt in EXTRA_CONFIG_JSON.get("firo{}".format(node_id), []):
fp.write(opt + "\n")
- if "monero" in coins_array:
- with open(os.path.join(datadir_path, "monero", "monerod.conf"), "a") as fp:
- fp.write("p2p-bind-ip=127.0.0.1\n")
- fp.write(
- "p2p-bind-port={}\n".format(XMR_BASE_P2P_PORT + node_id + port_ofs)
- )
- for ip in range(num_nodes):
- if ip != node_id:
- fp.write(
- "add-exclusive-node=127.0.0.1:{}\n".format(
- XMR_BASE_P2P_PORT + ip + port_ofs
- )
- )
-
if "bitcoincash" in coins_array:
config_filename = os.path.join(datadir_path, "bitcoincash", "bitcoin.conf")
with open(config_filename, "r") as fp:
diff --git a/tests/basicswap/extended/test_dcr.py b/tests/basicswap/extended/test_dcr.py
index d063160..e3c7bfe 100644
--- a/tests/basicswap/extended/test_dcr.py
+++ b/tests/basicswap/extended/test_dcr.py
@@ -138,7 +138,6 @@ def run_test_success_path(self, coin_from: Coins, coin_to: Coins):
# Verify lock tx spends are found in the expected wallets
bid, offer = swap_clients[node_from].getBidAndOffer(bid_id)
- max_fee: int = 10000
itx_spend = bid.initiate_tx.spend_txid.hex()
node_to_ci_from = swap_clients[node_to].ci(coin_from)
wtx = node_to_ci_from.rpc_wallet(
@@ -147,7 +146,9 @@ def run_test_success_path(self, coin_from: Coins, coin_to: Coins):
itx_spend,
],
)
- assert amt_swap - node_to_ci_from.make_int(wtx["details"][0]["amount"]) < max_fee
+ assert (
+ amt_swap - node_to_ci_from.make_int(wtx["details"][0]["amount"]) < self.max_fee
+ )
node_from_ci_to = swap_clients[node_from].ci(coin_to)
ptx_spend = bid.participate_tx.spend_txid.hex()
@@ -158,7 +159,8 @@ def run_test_success_path(self, coin_from: Coins, coin_to: Coins):
],
)
assert (
- bid.amount_to - node_from_ci_to.make_int(wtx["details"][0]["amount"]) < max_fee
+ bid.amount_to - node_from_ci_to.make_int(wtx["details"][0]["amount"])
+ < self.max_fee
)
js_0 = read_json_api(1800 + node_from)
@@ -235,7 +237,6 @@ def run_test_bad_ptx(self, coin_from: Coins, coin_to: Coins):
# Verify lock tx spends are found in the expected wallets
bid, offer = swap_clients[node_from].getBidAndOffer(bid_id)
- max_fee: int = 10000
itx_spend = bid.initiate_tx.spend_txid.hex()
node_from_ci_from = swap_clients[node_from].ci(coin_from)
wtx = node_from_ci_from.rpc_wallet(
@@ -244,7 +245,10 @@ def run_test_bad_ptx(self, coin_from: Coins, coin_to: Coins):
itx_spend,
],
)
- assert amt_swap - node_from_ci_from.make_int(wtx["details"][0]["amount"]) < max_fee
+ assert (
+ amt_swap - node_from_ci_from.make_int(wtx["details"][0]["amount"])
+ < self.max_fee
+ )
node_to_ci_to = swap_clients[node_to].ci(coin_to)
bid, offer = swap_clients[node_to].getBidAndOffer(bid_id)
@@ -255,7 +259,10 @@ def run_test_bad_ptx(self, coin_from: Coins, coin_to: Coins):
ptx_spend,
],
)
- assert bid.amount_to - node_to_ci_to.make_int(wtx["details"][0]["amount"]) < max_fee
+ assert (
+ bid.amount_to - node_to_ci_to.make_int(wtx["details"][0]["amount"])
+ < self.max_fee
+ )
bid_id_hex = bid_id.hex()
path = f"bids/{bid_id_hex}/states"
@@ -338,7 +345,6 @@ def run_test_itx_refund(self, coin_from: Coins, coin_to: Coins):
# Verify lock tx spends are found in the expected wallets
bid, offer = swap_clients[node_from].getBidAndOffer(bid_id)
- max_fee: int = 10000
itx_spend = bid.initiate_tx.spend_txid.hex()
node_from_ci_from = swap_clients[node_from].ci(coin_from)
wtx = node_from_ci_from.rpc_wallet(
@@ -348,7 +354,8 @@ def run_test_itx_refund(self, coin_from: Coins, coin_to: Coins):
],
)
assert (
- swap_value - node_from_ci_from.make_int(wtx["details"][0]["amount"]) < max_fee
+ swap_value - node_from_ci_from.make_int(wtx["details"][0]["amount"])
+ < self.max_fee
)
node_from_ci_to = swap_clients[node_from].ci(coin_to)
@@ -360,7 +367,8 @@ def run_test_itx_refund(self, coin_from: Coins, coin_to: Coins):
],
)
assert (
- bid.amount_to - node_from_ci_to.make_int(wtx["details"][0]["amount"]) < max_fee
+ bid.amount_to - node_from_ci_to.make_int(wtx["details"][0]["amount"])
+ < self.max_fee
)
@@ -425,7 +433,6 @@ def run_test_ads_success_path(self, coin_from: Coins, coin_to: Coins):
bid, xmr_swap = swap_clients[id_offerer].getXmrBid(bid_id)
node_from_ci_to = swap_clients[0].ci(coin_to)
- max_fee: int = 10000
if node_from_ci_to.coin_type() in (Coins.XMR, Coins.WOW):
pass
else:
@@ -437,7 +444,7 @@ def run_test_ads_success_path(self, coin_from: Coins, coin_to: Coins):
)
assert (
bid.amount_to - node_from_ci_to.make_int(wtx["details"][0]["amount"])
- < max_fee
+ < self.max_fee
)
node_to_ci_from = swap_clients[1].ci(coin_from)
@@ -451,7 +458,8 @@ def run_test_ads_success_path(self, coin_from: Coins, coin_to: Coins):
],
)
assert (
- bid.amount - node_to_ci_from.make_int(wtx["details"][0]["amount"]) < max_fee
+ bid.amount - node_to_ci_from.make_int(wtx["details"][0]["amount"])
+ < self.max_fee
)
bid_id_hex = bid_id.hex()
@@ -550,7 +558,6 @@ def run_test_ads_both_refund(
bid, xmr_swap = swap_clients[id_bidder].getXmrBid(bid_id)
node_from_ci_from = swap_clients[0].ci(coin_from)
- max_fee: int = 10000
if node_from_ci_from.coin_type() in (Coins.XMR, Coins.WOW):
pass
else:
@@ -562,7 +569,7 @@ def run_test_ads_both_refund(
)
assert (
bid.amount - node_from_ci_from.make_int(wtx["details"][0]["amount"])
- < max_fee
+ < self.max_fee
)
node_to_ci_to = swap_clients[1].ci(coin_to)
@@ -577,7 +584,7 @@ def run_test_ads_both_refund(
)
assert (
bid.amount_to - node_to_ci_to.make_int(wtx["details"][0]["amount"])
- < max_fee
+ < self.max_fee
)
bid_id_hex = bid_id.hex()
@@ -720,6 +727,7 @@ class Test(BaseTest):
start_xmr_nodes = True
dcr_mining_addr = "SsYbXyjkKAEXXcGdFgr4u4bo4L8RkCxwQpH"
extra_wait_time = 0
+ max_fee: int = 10000
hex_seeds = [
"e8574b2a94404ee62d8acc0258cab4c0defcfab8a5dfc2f4954c1f9d7e09d72a",
diff --git a/tests/basicswap/extended/test_nmc.py b/tests/basicswap/extended/test_nmc.py
index 80c29bf..afe7647 100644
--- a/tests/basicswap/extended/test_nmc.py
+++ b/tests/basicswap/extended/test_nmc.py
@@ -11,78 +11,58 @@ basicswap]$ python tests/basicswap/extended/test_nmc.py
"""
-import json
import logging
import os
-import shutil
-import signal
+import random
import sys
-import threading
-import time
import unittest
import basicswap.config as cfg
from basicswap.basicswap import (
- BasicSwap,
Coins,
- SwapTypes,
- BidStates,
- TxStates,
)
from basicswap.util import (
- COIN,
-)
-from basicswap.basicswap_util import (
- TxLockTypes,
-)
-from basicswap.util.address import (
- toWIF,
-)
-from basicswap.rpc import (
- callrpc_cli,
-)
-from basicswap.contrib.key import (
- ECKey,
-)
-from basicswap.http_server import (
- HttpThread,
-)
-from tests.basicswap.util import (
- read_json_api,
-)
-from tests.basicswap.common import (
- checkForks,
- stopDaemons,
- wait_for_offer,
- wait_for_bid,
- wait_for_bid_tx_state,
- wait_for_in_progress,
- TEST_HTTP_HOST,
- TEST_HTTP_PORT,
- BASE_PORT,
- BASE_RPC_PORT,
- BASE_ZMQ_PORT,
- PREFIX_SECRET_KEY_REGTEST,
- waitForRPC,
+ toBool,
)
from basicswap.bin.run import startDaemon
+from basicswap.contrib.rpcauth import generate_salt, password_to_hmac
+from tests.basicswap.common import (
+ stopDaemons,
+ waitForRPC,
+ make_rpc_func,
+)
+
+from tests.basicswap.test_btc_xmr import BasicSwapTest, test_delay_event
+from tests.basicswap.test_xmr import NUM_NODES
+from tests.basicswap.extended.test_dcr import (
+ run_test_success_path,
+ run_test_bad_ptx,
+ run_test_itx_refund,
+)
-logger = logging.getLogger()
-logger.level = logging.DEBUG
+logger = logging.getLogger("BSX Tests")
+
if not len(logger.handlers):
logger.addHandler(logging.StreamHandler(sys.stdout))
-NUM_NODES = 3
-NMC_NODE = 3
-BTC_NODE = 4
-delay_event = threading.Event()
-stop_test = False
+NAMECOIN_BINDIR = os.path.expanduser(
+ os.getenv("NAMECOIN_BINDIR", os.path.join(cfg.DEFAULT_TEST_BINDIR, "namecoin"))
+)
+NAMECOIND = os.getenv("NAMECOIND", "namecoind" + cfg.bin_suffix)
+NAMECOIN_CLI = os.getenv("NAMECOIN_CLI", "namecoin-cli" + cfg.bin_suffix)
+NAMECOIN_TX = os.getenv("NAMECOIN_TX", "namecoin-tx" + cfg.bin_suffix)
+
+NMC_USE_DESCRIPTORS = toBool(os.getenv("NMC_USE_DESCRIPTORS", True))
+
+NMC_BASE_PORT = 8136
+NMC_BASE_RPC_PORT = 8146
+NMC_BASE_TOR_PORT = 8156
-def prepareOtherDir(datadir, nodeId, conf_file="namecoin.conf"):
- node_dir = os.path.join(datadir, str(nodeId))
+def prepareNMCDataDir(datadir, nodeId, conf_file="namecoin.conf"):
+ node_dir = os.path.join(datadir, "nmc_" + str(nodeId))
if not os.path.exists(node_dir):
os.makedirs(node_dir)
filePath = os.path.join(node_dir, conf_file)
@@ -90,8 +70,17 @@ def prepareOtherDir(datadir, nodeId, conf_file="namecoin.conf"):
with open(filePath, "w+") as fp:
fp.write("regtest=1\n")
fp.write("[regtest]\n")
- fp.write("port=" + str(BASE_PORT + nodeId) + "\n")
- fp.write("rpcport=" + str(BASE_RPC_PORT + nodeId) + "\n")
+
+ fp.write("port=" + str(NMC_BASE_PORT + nodeId) + "\n")
+ fp.write("rpcport=" + str(NMC_BASE_RPC_PORT + nodeId) + "\n")
+ salt = generate_salt(16)
+ fp.write(
+ "rpcauth={}:{}${}\n".format(
+ "test" + str(nodeId),
+ salt,
+ password_to_hmac(salt, "test_pass" + str(nodeId)),
+ )
+ )
fp.write("daemon=0\n")
fp.write("printtoconsole=0\n")
@@ -99,595 +88,182 @@ def prepareOtherDir(datadir, nodeId, conf_file="namecoin.conf"):
fp.write("discover=0\n")
fp.write("listenonion=0\n")
fp.write("bind=127.0.0.1\n")
- fp.write("findpeers=0\n")
fp.write("debug=1\n")
fp.write("debugexclude=libevent\n")
fp.write("fallbackfee=0.01\n")
fp.write("acceptnonstdtxn=0\n")
-
- if conf_file == "bitcoin.conf":
- fp.write("wallet=wallet.dat\n")
-
-
-def prepareDir(datadir, nodeId, network_key, network_pubkey):
- node_dir = os.path.join(datadir, str(nodeId))
- if not os.path.exists(node_dir):
- os.makedirs(node_dir)
- filePath = os.path.join(node_dir, "particl.conf")
-
- with open(filePath, "w+") as fp:
- fp.write("regtest=1\n")
- fp.write("[regtest]\n")
- fp.write("port=" + str(BASE_PORT + nodeId) + "\n")
- fp.write("rpcport=" + str(BASE_RPC_PORT + nodeId) + "\n")
-
- fp.write("daemon=0\n")
- fp.write("printtoconsole=0\n")
- fp.write("server=1\n")
- fp.write("discover=0\n")
- fp.write("listenonion=0\n")
- fp.write("bind=127.0.0.1\n")
- fp.write("findpeers=0\n")
- fp.write("debug=1\n")
- fp.write("debugexclude=libevent\n")
- fp.write("zmqpubsmsg=tcp://127.0.0.1:" + str(BASE_ZMQ_PORT + nodeId) + "\n")
- fp.write("wallet=wallet.dat\n")
- fp.write("fallbackfee=0.01\n")
-
- fp.write("acceptnonstdtxn=0\n")
- fp.write("minstakeinterval=5\n")
- fp.write("smsgsregtestadjust=0\n")
+ fp.write("deprecatedrpc=create_bdb\n")
+ fp.write("addresstype=bech32\n")
+ fp.write("changetype=bech32\n")
for i in range(0, NUM_NODES):
if nodeId == i:
continue
- fp.write("addnode=127.0.0.1:%d\n" % (BASE_PORT + i))
-
- if nodeId < 2:
- fp.write("spentindex=1\n")
- fp.write("txindex=1\n")
-
- basicswap_dir = os.path.join(datadir, str(nodeId), "basicswap")
- if not os.path.exists(basicswap_dir):
- os.makedirs(basicswap_dir)
-
- nmcdatadir = os.path.join(datadir, str(NMC_NODE))
- btcdatadir = os.path.join(datadir, str(BTC_NODE))
- settings_path = os.path.join(basicswap_dir, cfg.CONFIG_FILENAME)
- settings = {
- "debug": True,
- "zmqhost": "tcp://127.0.0.1",
- "zmqport": BASE_ZMQ_PORT + nodeId,
- "htmlhost": "127.0.0.1",
- "htmlport": 12700 + nodeId,
- "network_key": network_key,
- "network_pubkey": network_pubkey,
- "chainclients": {
- "particl": {
- "connection_type": "rpc",
- "manage_daemon": False,
- "rpcport": BASE_RPC_PORT + nodeId,
- "datadir": node_dir,
- "bindir": cfg.PARTICL_BINDIR,
- "blocks_confirmed": 2, # Faster testing
- },
- "namecoin": {
- "connection_type": "rpc",
- "manage_daemon": False,
- "rpcport": BASE_RPC_PORT + NMC_NODE,
- "datadir": nmcdatadir,
- "bindir": cfg.NAMECOIN_BINDIR,
- "use_csv": False,
- # 'use_segwit': True,
- },
- "bitcoin": {
- "connection_type": "rpc",
- "manage_daemon": False,
- "rpcport": BASE_RPC_PORT + BTC_NODE,
- "datadir": btcdatadir,
- "bindir": cfg.BITCOIN_BINDIR,
- "use_segwit": True,
- },
- },
- "check_progress_seconds": 2,
- "check_watched_seconds": 4,
- "check_expired_seconds": 60,
- "restrict_unknown_seed_wallets": False,
- }
- with open(settings_path, "w") as fp:
- json.dump(settings, fp, indent=4)
+ fp.write("addnode=127.0.0.1:{}\n".format(NMC_BASE_PORT + i))
-def partRpc(cmd, node_id=0):
- return callrpc_cli(
- cfg.PARTICL_BINDIR,
- os.path.join(cfg.TEST_DATADIRS, str(node_id)),
- "regtest",
- cmd,
- cfg.PARTICL_CLI,
- )
+class TestNMC(BasicSwapTest):
+ __test__ = True
+ test_coin = Coins.NMC
+ test_coin_from = Coins.NMC
+ nmc_daemons = []
+ start_ltc_nodes = False
+ start_xmr_nodes = True
+ base_rpc_port = NMC_BASE_RPC_PORT
+ nmc_addr = None
+ max_fee: int = 200000
+ test_fee_rate: int = 100000 # sats/kvB
-
-def btcRpc(cmd):
- return callrpc_cli(
- cfg.BITCOIN_BINDIR,
- os.path.join(cfg.TEST_DATADIRS, str(BTC_NODE)),
- "regtest",
- cmd,
- cfg.BITCOIN_CLI,
- )
-
-
-def nmcRpc(cmd):
- return callrpc_cli(
- cfg.NAMECOIN_BINDIR,
- os.path.join(cfg.TEST_DATADIRS, str(NMC_NODE)),
- "regtest",
- cmd,
- cfg.NAMECOIN_CLI,
- )
-
-
-def signal_handler(sig, frame):
- global stop_test
- os.write(sys.stdout.fileno(), f"Signal {sig} detected.\n".encode("utf-8"))
- stop_test = True
- delay_event.set()
-
-
-def run_coins_loop(cls):
- while not stop_test:
- try:
- nmcRpc("generatetoaddress 1 {}".format(cls.nmc_addr))
- btcRpc("generatetoaddress 1 {}".format(cls.btc_addr))
- except Exception as e:
- logging.warning("run_coins_loop " + str(e))
- time.sleep(1.0)
-
-
-def run_loop(self):
- while not stop_test:
- for c in self.swap_clients:
- c.update()
- time.sleep(1)
-
-
-def make_part_cli_rpc_func(node_id):
- node_id = node_id
-
- def rpc_func(method, params=None, wallet=None):
- cmd = method
- if params:
- for p in params:
- cmd += ' "' + p + '"'
- return partRpc(cmd, node_id)
-
- return rpc_func
-
-
-class Test(unittest.TestCase):
-
- @classmethod
- def setUpClass(cls):
- super(Test, cls).setUpClass()
-
- eckey = ECKey()
- eckey.generate()
- cls.network_key = toWIF(PREFIX_SECRET_KEY_REGTEST, eckey.get_bytes())
- cls.network_pubkey = eckey.get_pubkey().get_bytes().hex()
-
- if os.path.isdir(cfg.TEST_DATADIRS):
- logging.info("Removing " + cfg.TEST_DATADIRS)
- shutil.rmtree(cfg.TEST_DATADIRS)
-
- for i in range(NUM_NODES):
- prepareDir(cfg.TEST_DATADIRS, i, cls.network_key, cls.network_pubkey)
-
- prepareOtherDir(cfg.TEST_DATADIRS, NMC_NODE)
- prepareOtherDir(cfg.TEST_DATADIRS, BTC_NODE, "bitcoin.conf")
-
- cls.daemons = []
- cls.swap_clients = []
- cls.http_threads = []
-
- btc_data_dir = os.path.join(cfg.TEST_DATADIRS, str(BTC_NODE))
- if os.path.exists(os.path.join(cfg.BITCOIN_BINDIR, "bitcoin-wallet")):
- callrpc_cli(
- cfg.BITCOIN_BINDIR,
- btc_data_dir,
- "regtest",
- "-wallet=wallet.dat -legacy create",
- "bitcoin-wallet",
- )
- cls.daemons.append(startDaemon(btc_data_dir, cfg.BITCOIN_BINDIR, cfg.BITCOIND))
- logging.info("Started %s %d", cfg.BITCOIND, cls.daemons[-1].handle.pid)
- cls.daemons.append(
- startDaemon(
- os.path.join(cfg.TEST_DATADIRS, str(NMC_NODE)),
- cfg.NAMECOIN_BINDIR,
- cfg.NAMECOIND,
- )
- )
- logging.info("Started %s %d", cfg.NAMECOIND, cls.daemons[-1].handle.pid)
-
- for i in range(NUM_NODES):
- data_dir = os.path.join(cfg.TEST_DATADIRS, str(i))
- if os.path.exists(os.path.join(cfg.PARTICL_BINDIR, "particl-wallet")):
- callrpc_cli(
- cfg.PARTICL_BINDIR,
- data_dir,
- "regtest",
- "-wallet=wallet.dat -legacy create",
- "particl-wallet",
- )
- cls.daemons.append(startDaemon(data_dir, cfg.PARTICL_BINDIR, cfg.PARTICLD))
- logging.info("Started %s %d", cfg.PARTICLD, cls.daemons[-1].handle.pid)
-
- for i in range(NUM_NODES):
- rpc = make_part_cli_rpc_func(i)
- waitForRPC(rpc, delay_event)
- if i == 0:
- rpc(
- "extkeyimportmaster",
- [
- "abandon baby cabbage dad eager fabric gadget habit ice kangaroo lab absorb"
- ],
- )
- elif i == 1:
- rpc(
- "extkeyimportmaster",
- [
- "pact mammal barrel matrix local final lecture chunk wasp survey bid various book strong spread fall ozone daring like topple door fatigue limb olympic",
- "",
- "true",
- ],
- )
- rpc("getnewextaddress", ["lblExtTest"])
- rpc("rescanblockchain")
- else:
- rpc("extkeyimportmaster", [rpc("mnemonic", ["new"])["master"]])
- rpc(
- "walletsettings",
- [
- "stakingoptions",
- json.dumps(
- {"stakecombinethreshold": 100, "stakesplitthreshold": 200}
- ).replace('"', '\\"'),
- ],
- )
- rpc("reservebalance", ["false"])
-
- basicswap_dir = os.path.join(
- os.path.join(cfg.TEST_DATADIRS, str(i)), "basicswap"
- )
- settings_path = os.path.join(basicswap_dir, cfg.CONFIG_FILENAME)
- with open(settings_path) as fs:
- settings = json.load(fs)
- sc = BasicSwap(
- basicswap_dir, settings, "regtest", log_name="BasicSwap{}".format(i)
- )
- cls.swap_clients.append(sc)
-
- sc.setDaemonPID(Coins.BTC, cls.daemons[0].handle.pid)
- sc.setDaemonPID(Coins.NMC, cls.daemons[1].handle.pid)
- sc.setDaemonPID(Coins.PART, cls.daemons[2 + i].handle.pid)
- sc.start()
-
- t = HttpThread(TEST_HTTP_HOST, TEST_HTTP_PORT + i, False, sc)
- cls.http_threads.append(t)
- t.start()
-
- waitForRPC(nmcRpc, delay_event)
- num_blocks = 500
- logging.info("Mining %d namecoin blocks", num_blocks)
- cls.nmc_addr = nmcRpc("getnewaddress mining_addr legacy")
- nmcRpc("generatetoaddress {} {}".format(num_blocks, cls.nmc_addr))
-
- ro = nmcRpc("getblockchaininfo")
- try:
- assert ro["bip9_softforks"]["csv"]["status"] == "active"
- except Exception:
- logging.info("nmc: csv is not active")
- try:
- assert ro["bip9_softforks"]["segwit"]["status"] == "active"
- except Exception:
- logging.info("nmc: segwit is not active")
-
- waitForRPC(btcRpc, delay_event)
- cls.btc_addr = btcRpc("getnewaddress mining_addr bech32")
- logging.info("Mining %d Bitcoin blocks to %s", num_blocks, cls.btc_addr)
- btcRpc("generatetoaddress {} {}".format(num_blocks, cls.btc_addr))
-
- ro = btcRpc("getblockchaininfo")
- checkForks(ro)
-
- ro = nmcRpc("getwalletinfo")
- print("nmcRpc", ro)
-
- signal.signal(signal.SIGINT, signal_handler)
- cls.update_thread = threading.Thread(target=run_loop, args=(cls,))
- cls.update_thread.start()
-
- cls.coins_update_thread = threading.Thread(target=run_coins_loop, args=(cls,))
- cls.coins_update_thread.start()
-
- # Wait for height, or sequencelock is thrown off by genesis blocktime
- num_blocks = 3
- logging.info("Waiting for Particl chain height %d", num_blocks)
- for i in range(60):
- particl_blocks = cls.swap_clients[0].callrpc("getblockcount")
- print("particl_blocks", particl_blocks)
- if particl_blocks >= num_blocks:
- break
- delay_event.wait(1)
- assert particl_blocks >= num_blocks
+ def mineBlock(self, num_blocks: int = 1) -> None:
+ self.callnoderpc("generatetoaddress", [num_blocks, self.nmc_addr])
@classmethod
def tearDownClass(cls):
- global stop_test
- logging.info("Finalising")
- stop_test = True
- cls.update_thread.join()
- cls.coins_update_thread.join()
- for t in cls.http_threads:
- t.stop()
- t.join()
- for c in cls.swap_clients:
- c.finalise()
+ logging.info("Finalising Namecoin Test")
+ stopDaemons(cls.nmc_daemons)
+ cls.nmc_daemons.clear()
- stopDaemons(cls.daemons)
- cls.http_threads.clear()
- cls.swap_clients.clear()
- cls.daemons.clear()
+ super(TestNMC, cls).tearDownClass()
- super(Test, cls).tearDownClass()
-
- def test_02_part_nmc(self):
- logging.info("---------- Test PART to NMC")
- swap_clients = self.swap_clients
-
- offer_id = swap_clients[0].postOffer(
- Coins.PART,
- Coins.NMC,
- 100 * COIN,
- 0.1 * COIN,
- 100 * COIN,
- SwapTypes.SELLER_FIRST,
- TxLockTypes.ABS_LOCK_TIME,
- )
-
- wait_for_offer(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)
-
- wait_for_bid(delay_event, swap_clients[0], bid_id)
-
- swap_clients[0].acceptBid(bid_id)
-
- wait_for_in_progress(delay_event, swap_clients[1], bid_id, sent=True)
-
- wait_for_bid(
- delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=60
- )
- wait_for_bid(
- delay_event,
- swap_clients[1],
- bid_id,
- BidStates.SWAP_COMPLETED,
- sent=True,
- wait_for=60,
- )
-
- js_0 = read_json_api(1800)
- js_1 = read_json_api(1801)
- assert js_0["num_swapping"] == 0 and js_0["num_watched_outputs"] == 0
- assert js_1["num_swapping"] == 0 and js_1["num_watched_outputs"] == 0
-
- def test_03_nmc_part(self):
- logging.info("---------- Test NMC to PART")
- swap_clients = self.swap_clients
-
- offer_id = swap_clients[1].postOffer(
- Coins.NMC,
- Coins.PART,
- 10 * COIN,
- 9.0 * COIN,
- 10 * COIN,
- SwapTypes.SELLER_FIRST,
- TxLockTypes.ABS_LOCK_TIME,
- )
-
- wait_for_offer(delay_event, swap_clients[0], offer_id)
- offer = swap_clients[0].getOffer(offer_id)
- bid_id = swap_clients[0].postBid(offer_id, offer.amount_from)
-
- wait_for_bid(delay_event, swap_clients[1], bid_id)
- swap_clients[1].acceptBid(bid_id)
-
- wait_for_in_progress(delay_event, swap_clients[0], bid_id, sent=True)
-
- wait_for_bid(
- delay_event,
- swap_clients[0],
- bid_id,
- BidStates.SWAP_COMPLETED,
- sent=True,
- wait_for=60,
- )
- wait_for_bid(
- delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, wait_for=60
- )
-
- js_0 = read_json_api(1800)
- js_1 = read_json_api(1801)
- assert js_0["num_swapping"] == 0 and js_0["num_watched_outputs"] == 0
- assert js_1["num_swapping"] == 0 and js_1["num_watched_outputs"] == 0
-
- def test_04_nmc_btc(self):
- logging.info("---------- Test NMC to BTC")
- swap_clients = self.swap_clients
-
- offer_id = swap_clients[0].postOffer(
- Coins.NMC,
- Coins.BTC,
- 10 * COIN,
- 0.1 * COIN,
- 10 * COIN,
- SwapTypes.SELLER_FIRST,
- TxLockTypes.ABS_LOCK_TIME,
- )
-
- wait_for_offer(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)
-
- wait_for_bid(delay_event, swap_clients[0], bid_id)
- swap_clients[0].acceptBid(bid_id)
-
- wait_for_in_progress(delay_event, swap_clients[1], bid_id, sent=True)
-
- wait_for_bid(
- delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=60
- )
- wait_for_bid(
- delay_event,
- swap_clients[1],
- bid_id,
- BidStates.SWAP_COMPLETED,
- sent=True,
- wait_for=60,
- )
-
- js_0 = read_json_api(1800)
- js_1 = read_json_api(1801)
-
- assert js_0["num_swapping"] == 0 and js_0["num_watched_outputs"] == 0
- assert js_1["num_swapping"] == 0 and js_1["num_watched_outputs"] == 0
-
- def test_05_refund(self):
- # Seller submits initiate txn, buyer doesn't respond
- logging.info("---------- Test refund, NMC to BTC")
- swap_clients = self.swap_clients
-
- offer_id = swap_clients[0].postOffer(
- Coins.NMC,
- Coins.BTC,
- 10 * COIN,
- 0.1 * COIN,
- 10 * COIN,
- SwapTypes.SELLER_FIRST,
- TxLockTypes.ABS_LOCK_BLOCKS,
- 10,
- )
-
- wait_for_offer(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)
-
- wait_for_bid(delay_event, swap_clients[0], bid_id)
- swap_clients[1].abandonBid(bid_id)
- swap_clients[0].acceptBid(bid_id)
-
- wait_for_bid(
- delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=60
- )
- wait_for_bid(
- delay_event,
- swap_clients[1],
- bid_id,
- BidStates.BID_ABANDONED,
- sent=True,
- wait_for=60,
- )
-
- js_0 = read_json_api(1800)
- js_1 = read_json_api(1801)
- assert js_0["num_swapping"] == 0 and js_0["num_watched_outputs"] == 0
- assert js_1["num_swapping"] == 0 and js_1["num_watched_outputs"] == 0
-
- def test_06_self_bid(self):
- logging.info("---------- Test same client, BTC to NMC")
- swap_clients = self.swap_clients
-
- js_0_before = read_json_api(1800)
-
- offer_id = swap_clients[0].postOffer(
- Coins.NMC,
- Coins.BTC,
- 10 * COIN,
- 10 * COIN,
- 10 * COIN,
- SwapTypes.SELLER_FIRST,
- TxLockTypes.ABS_LOCK_TIME,
- )
-
- wait_for_offer(delay_event, swap_clients[0], offer_id)
- offer = swap_clients[0].getOffer(offer_id)
- bid_id = swap_clients[0].postBid(offer_id, offer.amount_from)
-
- wait_for_bid(delay_event, swap_clients[0], bid_id)
- swap_clients[0].acceptBid(bid_id)
-
- wait_for_bid_tx_state(
- delay_event,
- swap_clients[0],
- bid_id,
- TxStates.TX_REDEEMED,
- TxStates.TX_REDEEMED,
- wait_for=60,
- )
- wait_for_bid(
- delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=60
- )
-
- js_0 = read_json_api(1800)
- assert js_0["num_swapping"] == 0 and js_0["num_watched_outputs"] == 0
- assert (
- js_0["num_recv_bids"] == js_0_before["num_recv_bids"] + 1
- and js_0["num_sent_bids"] == js_0_before["num_sent_bids"] + 1
- )
-
- def test_07_error(self):
- logging.info("---------- Test error, BTC to NMC, set fee above bid value")
- swap_clients = self.swap_clients
-
- offer_id = swap_clients[0].postOffer(
- Coins.NMC,
- Coins.BTC,
- 0.001 * COIN,
- 1.0 * COIN,
- 0.001 * COIN,
- SwapTypes.SELLER_FIRST,
- TxLockTypes.ABS_LOCK_TIME,
- )
-
- wait_for_offer(delay_event, swap_clients[0], offer_id)
- offer = swap_clients[0].getOffer(offer_id)
- bid_id = swap_clients[0].postBid(offer_id, offer.amount_from)
-
- wait_for_bid(delay_event, swap_clients[0], bid_id)
- swap_clients[0].acceptBid(bid_id)
+ @classmethod
+ def coins_loop(cls):
+ super(TestNMC, cls).coins_loop()
+ ci0 = cls.swap_clients[0].ci(cls.test_coin)
try:
- swap_clients[0].getChainClientSettings(Coins.BTC)["override_feerate"] = 10.0
- swap_clients[0].getChainClientSettings(Coins.NMC)["override_feerate"] = 10.0
- wait_for_bid(
- delay_event, swap_clients[0], bid_id, BidStates.BID_ERROR, wait_for=60
- )
- swap_clients[0].abandonBid(bid_id)
- finally:
- del swap_clients[0].getChainClientSettings(Coins.BTC)["override_feerate"]
- del swap_clients[0].getChainClientSettings(Coins.NMC)["override_feerate"]
+ if cls.nmc_addr is not None:
+ ci0.rpc_wallet("generatetoaddress", [1, cls.nmc_addr])
+ except Exception as e:
+ logging.warning(f"coins_loop generate {e}")
- def pass_99_delay(self):
- global stop_test
- logging.info("Delay")
- for i in range(60 * 5):
- if stop_test:
- break
- time.sleep(1)
- print("delay", i)
- stop_test = True
+ @classmethod
+ def prepareExtraDataDir(cls, i: int) -> None:
+ if not cls.restore_instance:
+ prepareNMCDataDir(cfg.TEST_DATADIRS, i)
+
+ cls.nmc_daemons.append(
+ startDaemon(
+ os.path.join(cfg.TEST_DATADIRS, "nmc_" + str(i)),
+ NAMECOIN_BINDIR,
+ NAMECOIND,
+ )
+ )
+ logging.info("Started {} {}".format(NAMECOIND, cls.nmc_daemons[-1].handle.pid))
+
+ nmc_rpc = make_rpc_func(i, base_rpc_port=NMC_BASE_RPC_PORT)
+ waitForRPC(
+ nmc_rpc,
+ test_delay_event,
+ rpc_command="getnetworkinfo",
+ max_tries=12,
+ )
+ waitForRPC(nmc_rpc, test_delay_event, rpc_command="getblockchaininfo")
+ if len(nmc_rpc("listwallets")) < 1:
+ nmc_rpc(
+ "createwallet",
+ ["wallet.dat", False, True, "", False, NMC_USE_DESCRIPTORS],
+ )
+ if NMC_USE_DESCRIPTORS:
+ nmc_rpc(
+ "createwallet",
+ ["bsx_watch", True, True, "", False, True],
+ )
+
+ @classmethod
+ def addPIDInfo(cls, sc, i):
+ sc.setDaemonPID(Coins.DCR, cls.nmc_daemons[i].handle.pid)
+
+ @classmethod
+ def addCoinSettings(cls, settings, datadir, node_id):
+ settings["chainclients"]["namecoin"] = {
+ "connection_type": "rpc",
+ "manage_daemon": False,
+ "rpcport": NMC_BASE_RPC_PORT + node_id,
+ "rpcuser": "test" + str(node_id),
+ "rpcpassword": "test_pass" + str(node_id),
+ "datadir": os.path.join(datadir, "nmc_" + str(node_id)),
+ "bindir": NAMECOIN_BINDIR,
+ "use_csv": True,
+ "use_segwit": True,
+ "blocks_confirmed": 1,
+ "use_descriptors": NMC_USE_DESCRIPTORS,
+ }
+ if NMC_USE_DESCRIPTORS:
+ settings["chainclients"]["namecoin"]["watch_wallet_name"] = "bsx_watch"
+
+ @classmethod
+ def prepareExtraCoins(cls):
+ ci0 = cls.swap_clients[0].ci(cls.test_coin)
+ if not cls.restore_instance:
+ for sc in cls.swap_clients:
+ ci = sc.ci(cls.test_coin)
+ ci.initialiseWallet(ci.getNewRandomKey())
+ cls.nmc_addr = ci0.rpc_wallet("getnewaddress", ["mining_addr", "bech32"])
+ else:
+ addrs = ci0.rpc_wallet(
+ "getaddressesbylabel",
+ [
+ "mining_addr",
+ ],
+ )
+ cls.nmc_addr = addrs.keys()[0]
+
+ num_blocks: int = 500
+ if ci0.rpc("getblockcount") < num_blocks:
+ logging.info(f"Mining {num_blocks} Namecoin blocks to {cls.nmc_addr}")
+ ci0.rpc("generatetoaddress", [num_blocks, cls.nmc_addr])
+ logging.info("NMC blocks: {}".format(ci0.rpc("getblockcount")))
+
+ def test_007_hdwallet(self):
+ logging.info("---------- Test {} hdwallet".format(self.test_coin_from.name))
+
+ test_seed = "8e54a313e6df8918df6d758fafdbf127a115175fdd2238d0e908dd8093c9ac3b"
+ test_wif = (
+ self.swap_clients[0]
+ .ci(self.test_coin_from)
+ .encodeKey(bytes.fromhex(test_seed))
+ )
+ new_wallet_name = random.randbytes(10).hex()
+ self.callnoderpc(
+ "createwallet",
+ [new_wallet_name, False, False, "", False, NMC_USE_DESCRIPTORS],
+ )
+ self.callnoderpc("sethdseed", [True, test_wif], wallet=new_wallet_name)
+ addr = self.callnoderpc(
+ "getnewaddress", ["add test", "bech32"], wallet=new_wallet_name
+ )
+ self.callnoderpc("unloadwallet", [new_wallet_name])
+ assert addr == "ncrt1qps7hnjd866e9ynxadgseprkc2l56m00dxkl7pk"
+
+ def test_012_p2sh_p2wsh(self):
+ # Fee rate
+ pass
+
+ def test_02_sh_part_coin(self):
+ self.prepare_balance(self.test_coin, 200.0, 1801, 1800)
+ run_test_success_path(self, Coins.PART, self.test_coin)
+
+ def test_03_sh_coin_part(self):
+ run_test_success_path(self, self.test_coin, Coins.PART)
+
+ def test_04_sh_part_coin_bad_ptx(self):
+ self.prepare_balance(self.test_coin, 200.0, 1801, 1800)
+ run_test_bad_ptx(self, Coins.PART, self.test_coin)
+
+ def test_05_sh_coin_part_bad_ptx(self):
+ self.prepare_balance(self.test_coin, 200.0, 1801, 1800)
+ run_test_bad_ptx(self, self.test_coin, Coins.PART)
+
+ def test_06_sh_part_coin_itx_refund(self):
+ run_test_itx_refund(self, Coins.PART, self.test_coin)
+
+ def test_07_sh_coin_part_itx_refund(self):
+ self.prepare_balance(self.test_coin, 200.0, 1801, 1800)
+ run_test_itx_refund(self, self.test_coin, Coins.PART)
+
+ def test_01_b_full_swap_reverse(self):
+ self.prepare_balance(self.test_coin, 100.0, 1801, 1800)
+ self.do_test_01_full_swap(Coins.XMR, self.test_coin_from)
if __name__ == "__main__":
diff --git a/tests/basicswap/extended/test_xmr_persistent.py b/tests/basicswap/extended/test_xmr_persistent.py
index 60eb064..321db9d 100644
--- a/tests/basicswap/extended/test_xmr_persistent.py
+++ b/tests/basicswap/extended/test_xmr_persistent.py
@@ -60,6 +60,7 @@ from tests.basicswap.common_xmr import (
prepare_nodes,
XMR_BASE_RPC_PORT,
DOGE_BASE_RPC_PORT,
+ NMC_BASE_RPC_PORT,
)
from basicswap.interface.dcr.rpc import callrpc as callrpc_dcr
import basicswap.bin.run as runSystem
@@ -73,12 +74,13 @@ UI_PORT = 12700 + PORT_OFS
PARTICL_RPC_PORT_BASE = int(os.getenv("PARTICL_RPC_PORT_BASE", BASE_RPC_PORT))
BITCOIN_RPC_PORT_BASE = int(os.getenv("BITCOIN_RPC_PORT_BASE", BTC_BASE_RPC_PORT))
LITECOIN_RPC_PORT_BASE = int(os.getenv("LITECOIN_RPC_PORT_BASE", LTC_BASE_RPC_PORT))
-DOGECOIN_RPC_PORT_BASE = int(os.getenv("DOGECOIN_RPC_PORT_BASE", DOGE_BASE_RPC_PORT))
+DECRED_WALLET_RPC_PORT_BASE = int(os.getenv("DECRED_WALLET_RPC_PORT_BASE", 9210))
+NAMECOIN_RPC_PORT_BASE = int(os.getenv("NAMECOIN_RPC_PORT_BASE", NMC_BASE_RPC_PORT))
+XMR_BASE_RPC_PORT = int(os.getenv("XMR_BASE_RPC_PORT", XMR_BASE_RPC_PORT))
BITCOINCASH_RPC_PORT_BASE = int(
os.getenv("BITCOINCASH_RPC_PORT_BASE", BCH_BASE_RPC_PORT)
)
-DECRED_WALLET_RPC_PORT_BASE = int(os.getenv("DECRED_WALLET_RPC_PORT_BASE", 9210))
-XMR_BASE_RPC_PORT = int(os.getenv("XMR_BASE_RPC_PORT", XMR_BASE_RPC_PORT))
+DOGECOIN_RPC_PORT_BASE = int(os.getenv("DOGECOIN_RPC_PORT_BASE", DOGE_BASE_RPC_PORT))
TEST_COINS_LIST = os.getenv("TEST_COINS_LIST", "bitcoin,monero")
NUM_NODES = int(os.getenv("NUM_NODES", 3))
@@ -130,6 +132,17 @@ def calldcrrpc(
return callrpc_dcr(base_rpc_port + node_id, auth, method, params)
+def callnmcrpc(
+ node_id,
+ method,
+ params=[],
+ wallet="wallet.dat",
+ base_rpc_port=NAMECOIN_RPC_PORT_BASE + PORT_OFS,
+):
+ auth = "test_nmc_{0}:test_nmc_pwd_{0}".format(node_id)
+ return callrpc(base_rpc_port + node_id, auth, method, params, wallet)
+
+
def callbchrpc(
node_id,
method,
@@ -163,6 +176,8 @@ def updateThread(cls):
callbchrpc(0, "generatetoaddress", [1, cls.bch_addr])
if cls.doge_addr is not None:
calldogerpc(0, "generatetoaddress", [1, cls.doge_addr])
+ if cls.nmc_addr is not None:
+ callnmcrpc(0, "generatetoaddress", [1, cls.nmc_addr])
except Exception as e:
print("updateThread error", str(e))
cls.delay_event.wait(random.randrange(cls.update_min, cls.update_max))
@@ -388,6 +403,18 @@ def start_processes(self):
0, "generatetoaddress", [num_blocks - have_blocks, self.doge_addr]
)
+ if "namecoin" in TEST_COINS_LIST:
+ self.nmc_addr = callnmcrpc(0, "getnewaddress", ["mining_addr", "bech32"])
+ num_blocks: int = 500
+ have_blocks: int = callnmcrpc(0, "getblockcount")
+ if have_blocks < num_blocks:
+ logging.info(
+ f"Mining {num_blocks - have_blocks} Namecoin blocks to {self.nmc_addr}"
+ )
+ callnmcrpc(
+ 0, "generatetoaddress", [num_blocks - have_blocks, self.nmc_addr]
+ )
+
if RESET_TEST:
# Lower output split threshold for more stakeable outputs
for i in range(NUM_NODES):
@@ -444,6 +471,7 @@ class BaseTestWithPrepare(unittest.TestCase):
dcr_addr = "SsYbXyjkKAEXXcGdFgr4u4bo4L8RkCxwQpH"
dcr_acc = None
doge_addr = None
+ nmc_addr = None
initialised = False
diff --git a/tests/basicswap/test_btc_xmr.py b/tests/basicswap/test_btc_xmr.py
index 866fbed..a79c5a8 100644
--- a/tests/basicswap/test_btc_xmr.py
+++ b/tests/basicswap/test_btc_xmr.py
@@ -26,6 +26,9 @@ from basicswap.db import (
from basicswap.util import (
make_int,
)
+from basicswap.util.address import (
+ decodeAddress,
+)
from basicswap.util.extkey import ExtKeyPair
from basicswap.interface.base import Curves
from tests.basicswap.util import (
@@ -59,7 +62,6 @@ from basicswap.contrib.test_framework.script import (
from .test_xmr import BaseTest, test_delay_event, callnoderpc
logger = logging.getLogger()
-
test_seed = "8e54a313e6df8918df6d758fafdbf127a115175fdd2238d0e908dd8093c9ac3b"
@@ -183,7 +185,7 @@ class TestFunctions(BaseTest):
bid0 = read_json_api(1800 + id_offerer, f"bids/{bid_id.hex()}")
bid1 = read_json_api(1800 + id_bidder, f"bids/{bid_id.hex()}")
- tolerance = 1
+ tolerance = 2
assert bid0["ticker_from"] == ci_from.ticker()
assert bid1["ticker_from"] == ci_from.ticker()
assert bid0["ticker_to"] == ci_to.ticker()
@@ -666,7 +668,7 @@ class TestFunctions(BaseTest):
balance_from_before: float = self.getBalance(jsw, coin_from)
self.prepare_balance(
coin_to,
- balance_from_before + 1,
+ balance_from_before * 3,
1800 + id_bidder,
1801 if coin_to in (Coins.XMR,) else 1800,
)
@@ -718,6 +720,7 @@ class TestFunctions(BaseTest):
assert False, "Should fail"
amt_swap -= ci_from.make_int(1)
+ rate_swap = ci_to.make_int(1.0, r=1)
offer_id = swap_clients[id_offerer].postOffer(
coin_from,
coin_to,
@@ -770,6 +773,8 @@ class TestFunctions(BaseTest):
class BasicSwapTest(TestFunctions):
+ test_fee_rate: int = 1000 # sats/kvB
+
@classmethod
def setUpClass(cls):
super(BasicSwapTest, cls).setUpClass()
@@ -1178,6 +1183,10 @@ class BasicSwapTest(TestFunctions):
logging.info("---------- Test {} hdwallet".format(self.test_coin_from.name))
ci = self.swap_clients[0].ci(self.test_coin_from)
+ if hasattr(ci, "_use_descriptors") and ci._use_descriptors:
+ logging.warning("Skipping test")
+ return
+
test_wif = (
self.swap_clients[0]
.ci(self.test_coin_from)
@@ -1236,12 +1245,7 @@ class BasicSwapTest(TestFunctions):
swap_client = self.swap_clients[0]
ci = swap_client.ci(self.test_coin_from)
- addr_1 = ci.rpc_wallet(
- "getnewaddress",
- [
- "gettxout test 1",
- ],
- )
+ addr_1 = ci.getNewAddress(True, "gettxout test 1")
txid = ci.rpc_wallet("sendtoaddress", [addr_1, 1.0])
assert len(txid) == 64
@@ -1266,12 +1270,7 @@ class BasicSwapTest(TestFunctions):
else:
assert addr_1 in txout["scriptPubKey"]["addresses"]
# Spend
- addr_2 = ci.rpc_wallet(
- "getnewaddress",
- [
- "gettxout test 2",
- ],
- )
+ addr_2 = ci.getNewAddress(True, "gettxout test 2")
tx_funded = ci.rpc(
"createrawtransaction",
[[{"txid": utxo["txid"], "vout": utxo["vout"]}], {addr_2: 0.99}],
@@ -1297,12 +1296,7 @@ class BasicSwapTest(TestFunctions):
logging.info("---------- Test {} scantxoutset".format(self.test_coin_from.name))
ci = self.swap_clients[0].ci(self.test_coin_from)
- addr_1 = ci.rpc_wallet(
- "getnewaddress",
- [
- "scantxoutset test",
- ],
- )
+ addr_1 = ci.getNewAddress(True, "scantxoutset test")
txid = ci.rpc_wallet("sendtoaddress", [addr_1, 1.0])
assert len(txid) == 64
@@ -1323,10 +1317,7 @@ class BasicSwapTest(TestFunctions):
# Record unspents before createSCLockTx as the used ones will be locked
unspents = ci.rpc_wallet("listunspent")
-
- # fee_rate is in sats/kvB
- fee_rate: int = 1000
-
+ lockedunspents_before = ci.rpc_wallet("listlockunspent")
a = ci.getNewRandomKey()
b = ci.getNewRandomKey()
@@ -1335,17 +1326,26 @@ class BasicSwapTest(TestFunctions):
lock_tx_script = pi.genScriptLockTxScript(ci, A, B)
lock_tx = ci.createSCLockTx(amount, lock_tx_script)
- lock_tx = ci.fundSCLockTx(lock_tx, fee_rate)
+ lock_tx = ci.fundSCLockTx(lock_tx, self.test_fee_rate)
lock_tx = ci.signTxWithWallet(lock_tx)
+ # Check that inputs were locked
+ lockedunspents = ci.rpc_wallet("listlockunspent")
+ assert len(lockedunspents) > len(lockedunspents_before)
unspents_after = ci.rpc_wallet("listunspent")
- assert len(unspents) > len(unspents_after)
+ for utxo in unspents_after:
+ for locked_utxo in lockedunspents:
+ if (
+ locked_utxo["txid"] == utxo["txid"]
+ and locked_utxo["vout"] == utxo["vout"]
+ ):
+ raise ValueError("Locked utxo in listunspent")
tx_decoded = ci.rpc("decoderawtransaction", [lock_tx.hex()])
txid = tx_decoded["txid"]
vsize = tx_decoded["vsize"]
- expect_fee_int = round(fee_rate * vsize / 1000)
+ expect_fee_int = round(self.test_fee_rate * vsize / 1000)
out_value: int = 0
for txo in tx_decoded["vout"]:
@@ -1372,7 +1372,7 @@ class BasicSwapTest(TestFunctions):
pkh_out = ci.decodeAddress(addr_out)
fee_info = {}
lock_spend_tx = ci.createSCLockSpendTx(
- lock_tx, lock_tx_script, pkh_out, fee_rate, fee_info=fee_info
+ lock_tx, lock_tx_script, pkh_out, self.test_fee_rate, fee_info=fee_info
)
vsize_estimated: int = fee_info["vsize"]
@@ -1400,11 +1400,11 @@ class BasicSwapTest(TestFunctions):
v = ci.getNewRandomKey()
s = ci.getNewRandomKey()
S = ci.getPubkey(s)
- lock_tx_b_txid = ci.publishBLockTx(v, S, amount, fee_rate)
+ lock_tx_b_txid = ci.publishBLockTx(v, S, amount, self.test_fee_rate)
addr_out = ci.getNewAddress(True)
lock_tx_b_spend_txid = ci.spendBLockTx(
- lock_tx_b_txid, addr_out, v, s, amount, fee_rate, 0
+ lock_tx_b_txid, addr_out, v, s, amount, self.test_fee_rate, 0
)
lock_tx_b_spend = ci.getTransaction(lock_tx_b_spend_txid)
if lock_tx_b_spend is None:
@@ -1635,7 +1635,9 @@ class BasicSwapTest(TestFunctions):
wallet=new_wallet_name,
)
- addr = self.callnoderpc("getnewaddress", wallet=new_wallet_name)
+ addr = self.callnoderpc(
+ "getnewaddress", ["test descriptors"], wallet=new_wallet_name
+ )
addr_info = self.callnoderpc(
"getaddressinfo",
[
@@ -1645,7 +1647,8 @@ class BasicSwapTest(TestFunctions):
)
assert addr_info["hdmasterfingerprint"] == "a55b7ea9"
assert addr_info["hdkeypath"] == "m/0h/0h/0h"
- assert addr == "bcrt1qps7hnjd866e9ynxadgseprkc2l56m00dvwargr"
+ if self.test_coin_from == Coins.BTC:
+ assert addr == "bcrt1qps7hnjd866e9ynxadgseprkc2l56m00dvwargr"
addr_change = self.callnoderpc("getrawchangeaddress", wallet=new_wallet_name)
addr_info = self.callnoderpc(
@@ -1657,7 +1660,8 @@ class BasicSwapTest(TestFunctions):
)
assert addr_info["hdmasterfingerprint"] == "a55b7ea9"
assert addr_info["hdkeypath"] == "m/0h/1h/0h"
- assert addr_change == "bcrt1qdl9ryxkqjltv42lhfnqgdjf9tagxsjpp2xak9a"
+ if self.test_coin_from == Coins.BTC:
+ assert addr_change == "bcrt1qdl9ryxkqjltv42lhfnqgdjf9tagxsjpp2xak9a"
desc_watch = descsum_create(f"addr({addr})")
self.callnoderpc(
@@ -1683,7 +1687,56 @@ class BasicSwapTest(TestFunctions):
# Test that addresses can be generated beyond range in listdescriptors
for i in range(2000):
- self.callnoderpc("getnewaddress", wallet=new_wallet_name)
+ self.callnoderpc(
+ "getnewaddress",
+ [
+ f"t{i}",
+ ],
+ wallet=new_wallet_name,
+ )
+
+ # https://github.com/bitcoin/bitcoin/issues/10542
+ # https://github.com/bitcoin/bitcoin/issues/26046
+ sign_for_address: str = self.callnoderpc(
+ "getnewaddress",
+ [
+ "sign address",
+ ],
+ wallet=new_wallet_name,
+ )
+ priv_keys = self.callnoderpc("listdescriptors", [True], wallet=new_wallet_name)
+ addr_info = self.callnoderpc(
+ "getaddressinfo", [sign_for_address], wallet=new_wallet_name
+ )
+ hdkeypath = addr_info["hdkeypath"]
+
+ sign_for_address_key = None
+ for descriptor in priv_keys["descriptors"]:
+ if descriptor["active"] is False or descriptor["internal"] is True:
+ continue
+ desc = descriptor["desc"]
+ assert desc.startswith("wpkh(")
+ ext_key = desc[5:].split(")")[0].split("/", 1)[0]
+ ext_key_data = decodeAddress(ext_key)[4:]
+ ci_part = self.swap_clients[0].ci(Coins.PART)
+ ext_key_data_part = ci_part.encode_secret_extkey(ext_key_data)
+ rv = ci_part.rpc_wallet("extkey", ["info", ext_key_data_part, hdkeypath])
+ extkey_derived = rv["key_info"]["result"]
+ ext_key_data = decodeAddress(extkey_derived)[4:]
+ ek = ExtKeyPair()
+ ek.decode(ext_key_data)
+ addr = ci.encodeSegwitAddress(ci.getAddressHashFromKey(ek._key))
+ assert addr == sign_for_address
+ sign_for_address_key = ci.encodeKey(ek._key)
+ break
+ assert sign_for_address_key is not None
+ sign_message: str = "Would be better if dumpprivkey or signmessage worked"
+ sig = self.callnoderpc(
+ "signmessagewithprivkey",
+ [sign_for_address_key, sign_message],
+ wallet=new_wallet_name,
+ )
+ assert ci.verifyMessage(sign_for_address, sign_message, sig)
self.callnoderpc("unloadwallet", [new_wallet_name])
self.callnoderpc("unloadwallet", [new_watch_wallet_name])
| | |