coins: Add LTC MWEB wallet
This commit is contained in:
parent
7547587d4e
commit
38fa498b0b
@ -1,3 +1,3 @@
|
|||||||
name = "basicswap"
|
name = "basicswap"
|
||||||
|
|
||||||
__version__ = "0.12.3"
|
__version__ = "0.12.4"
|
||||||
|
@ -256,6 +256,7 @@ class BasicSwap(BaseApp):
|
|||||||
self._is_locked = None
|
self._is_locked = None
|
||||||
|
|
||||||
# TODO: Set dynamically
|
# TODO: Set dynamically
|
||||||
|
self.balance_only_coins = (Coins.LTC_MWEB, )
|
||||||
self.scriptless_coins = (Coins.XMR, Coins.PART_ANON, Coins.FIRO)
|
self.scriptless_coins = (Coins.XMR, Coins.PART_ANON, Coins.FIRO)
|
||||||
self.adaptor_swap_only_coins = self.scriptless_coins + (Coins.PART_BLIND, )
|
self.adaptor_swap_only_coins = self.scriptless_coins + (Coins.PART_BLIND, )
|
||||||
self.coins_without_segwit = (Coins.PIVX, Coins.DASH, Coins.NMC)
|
self.coins_without_segwit = (Coins.PIVX, Coins.DASH, Coins.NMC)
|
||||||
@ -480,6 +481,9 @@ class BasicSwap(BaseApp):
|
|||||||
self.coin_clients[Coins.PART_ANON] = self.coin_clients[coin]
|
self.coin_clients[Coins.PART_ANON] = self.coin_clients[coin]
|
||||||
self.coin_clients[Coins.PART_BLIND] = self.coin_clients[coin]
|
self.coin_clients[Coins.PART_BLIND] = self.coin_clients[coin]
|
||||||
|
|
||||||
|
if coin == Coins.LTC:
|
||||||
|
self.coin_clients[Coins.LTC_MWEB] = self.coin_clients[coin]
|
||||||
|
|
||||||
if self.coin_clients[coin]['connection_type'] == 'rpc':
|
if self.coin_clients[coin]['connection_type'] == 'rpc':
|
||||||
if coin == Coins.XMR:
|
if coin == Coins.XMR:
|
||||||
if chain_client_settings.get('automatically_select_daemon', False):
|
if chain_client_settings.get('automatically_select_daemon', False):
|
||||||
@ -510,8 +514,8 @@ class BasicSwap(BaseApp):
|
|||||||
if current_daemon_url in remote_daemon_urls:
|
if current_daemon_url in remote_daemon_urls:
|
||||||
self.log.info(f'Trying last used url {rpchost}:{rpcport}.')
|
self.log.info(f'Trying last used url {rpchost}:{rpcport}.')
|
||||||
try:
|
try:
|
||||||
rpc_cb2 = make_xmr_rpc2_func(rpcport, daemon_login, rpchost)
|
rpc2 = make_xmr_rpc2_func(rpcport, daemon_login, rpchost)
|
||||||
test = rpc_cb2('get_height', timeout=20)['height']
|
test = rpc2('get_height', timeout=20)['height']
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log.warning(f'Failed to set XMR remote daemon to {rpchost}:{rpcport}, {e}')
|
self.log.warning(f'Failed to set XMR remote daemon to {rpchost}:{rpcport}, {e}')
|
||||||
@ -520,8 +524,8 @@ class BasicSwap(BaseApp):
|
|||||||
self.log.info(f'Trying url {url}.')
|
self.log.info(f'Trying url {url}.')
|
||||||
try:
|
try:
|
||||||
rpchost, rpcport = url.rsplit(':', 1)
|
rpchost, rpcport = url.rsplit(':', 1)
|
||||||
rpc_cb2 = make_xmr_rpc2_func(rpcport, daemon_login, rpchost)
|
rpc2 = make_xmr_rpc2_func(rpcport, daemon_login, rpchost)
|
||||||
test = rpc_cb2('get_height', timeout=20)['height']
|
test = rpc2('get_height', timeout=20)['height']
|
||||||
coin_settings['rpchost'] = rpchost
|
coin_settings['rpchost'] = rpchost
|
||||||
coin_settings['rpcport'] = rpcport
|
coin_settings['rpcport'] = rpcport
|
||||||
data = {
|
data = {
|
||||||
@ -544,6 +548,9 @@ class BasicSwap(BaseApp):
|
|||||||
if coin == Coins.PART_BLIND:
|
if coin == Coins.PART_BLIND:
|
||||||
use_coinid = Coins.PART
|
use_coinid = Coins.PART
|
||||||
interface_ind = 'interface_blind'
|
interface_ind = 'interface_blind'
|
||||||
|
if coin == Coins.LTC_MWEB:
|
||||||
|
use_coinid = Coins.LTC
|
||||||
|
interface_ind = 'interface_mweb'
|
||||||
|
|
||||||
if use_coinid not in self.coin_clients:
|
if use_coinid not in self.coin_clients:
|
||||||
raise ValueError('Unknown coinid {}'.format(int(coin)))
|
raise ValueError('Unknown coinid {}'.format(int(coin)))
|
||||||
@ -558,6 +565,9 @@ class BasicSwap(BaseApp):
|
|||||||
if coin == Coins.PART_BLIND:
|
if coin == Coins.PART_BLIND:
|
||||||
use_coinid = Coins.PART
|
use_coinid = Coins.PART
|
||||||
interface_ind = 'interface_blind'
|
interface_ind = 'interface_blind'
|
||||||
|
if coin == Coins.LTC_MWEB:
|
||||||
|
use_coinid = Coins.LTC
|
||||||
|
interface_ind = 'interface_mweb'
|
||||||
|
|
||||||
if use_coinid not in self.coin_clients:
|
if use_coinid not in self.coin_clients:
|
||||||
raise ValueError('Unknown coinid {}'.format(int(coin)))
|
raise ValueError('Unknown coinid {}'.format(int(coin)))
|
||||||
@ -573,13 +583,18 @@ class BasicSwap(BaseApp):
|
|||||||
|
|
||||||
def createInterface(self, coin):
|
def createInterface(self, coin):
|
||||||
if coin == Coins.PART:
|
if coin == Coins.PART:
|
||||||
return PARTInterface(self.coin_clients[coin], self.chain, self)
|
interface = PARTInterface(self.coin_clients[coin], self.chain, self)
|
||||||
|
self.coin_clients[coin]['interface_anon'] = PARTInterfaceAnon(self.coin_clients[coin], self.chain, self)
|
||||||
|
self.coin_clients[coin]['interface_blind'] = PARTInterfaceBlind(self.coin_clients[coin], self.chain, self)
|
||||||
|
return interface
|
||||||
elif coin == Coins.BTC:
|
elif coin == Coins.BTC:
|
||||||
from .interface.btc import BTCInterface
|
from .interface.btc import BTCInterface
|
||||||
return BTCInterface(self.coin_clients[coin], self.chain, self)
|
return BTCInterface(self.coin_clients[coin], self.chain, self)
|
||||||
elif coin == Coins.LTC:
|
elif coin == Coins.LTC:
|
||||||
from .interface.ltc import LTCInterface
|
from .interface.ltc import LTCInterface, LTCInterfaceMWEB
|
||||||
return LTCInterface(self.coin_clients[coin], self.chain, self)
|
interface = LTCInterface(self.coin_clients[coin], self.chain, self)
|
||||||
|
self.coin_clients[coin]['interface_mweb'] = LTCInterfaceMWEB(self.coin_clients[coin], self.chain, self)
|
||||||
|
return interface
|
||||||
elif coin == Coins.NMC:
|
elif coin == Coins.NMC:
|
||||||
from .interface.nmc import NMCInterface
|
from .interface.nmc import NMCInterface
|
||||||
return NMCInterface(self.coin_clients[coin], self.chain, self)
|
return NMCInterface(self.coin_clients[coin], self.chain, self)
|
||||||
@ -662,9 +677,6 @@ class BasicSwap(BaseApp):
|
|||||||
def createCoinInterface(self, coin):
|
def createCoinInterface(self, coin):
|
||||||
if self.coin_clients[coin]['connection_type'] == 'rpc':
|
if self.coin_clients[coin]['connection_type'] == 'rpc':
|
||||||
self.coin_clients[coin]['interface'] = self.createInterface(coin)
|
self.coin_clients[coin]['interface'] = self.createInterface(coin)
|
||||||
if coin == Coins.PART:
|
|
||||||
self.coin_clients[coin]['interface_anon'] = PARTInterfaceAnon(self.coin_clients[coin], self.chain, self)
|
|
||||||
self.coin_clients[coin]['interface_blind'] = PARTInterfaceBlind(self.coin_clients[coin], self.chain, self)
|
|
||||||
elif self.coin_clients[coin]['connection_type'] == 'passthrough':
|
elif self.coin_clients[coin]['connection_type'] == 'passthrough':
|
||||||
self.coin_clients[coin]['interface'] = self.createPassthroughInterface(coin)
|
self.coin_clients[coin]['interface'] = self.createPassthroughInterface(coin)
|
||||||
|
|
||||||
@ -685,13 +697,11 @@ class BasicSwap(BaseApp):
|
|||||||
self.createCoinInterface(c)
|
self.createCoinInterface(c)
|
||||||
|
|
||||||
if self.coin_clients[c]['connection_type'] == 'rpc':
|
if self.coin_clients[c]['connection_type'] == 'rpc':
|
||||||
if c in (Coins.BTC, ):
|
|
||||||
self.waitForDaemonRPC(c, with_wallet=False)
|
|
||||||
if len(self.callcoinrpc(c, 'listwallets')) >= 1:
|
|
||||||
self.waitForDaemonRPC(c)
|
|
||||||
else:
|
|
||||||
self.waitForDaemonRPC(c)
|
|
||||||
ci = self.ci(c)
|
ci = self.ci(c)
|
||||||
|
self.waitForDaemonRPC(c, with_wallet=False)
|
||||||
|
if c not in (Coins.XMR,) and ci.checkWallets() >= 1:
|
||||||
|
self.waitForDaemonRPC(c)
|
||||||
|
|
||||||
core_version = ci.getDaemonVersion()
|
core_version = ci.getDaemonVersion()
|
||||||
self.log.info('%s Core version %d', ci.coin_name(), core_version)
|
self.log.info('%s Core version %d', ci.coin_name(), core_version)
|
||||||
self.coin_clients[c]['core_version'] = core_version
|
self.coin_clients[c]['core_version'] = core_version
|
||||||
@ -721,6 +731,11 @@ class BasicSwap(BaseApp):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log.warning('Can\'t open XMR wallet, could be locked.')
|
self.log.warning('Can\'t open XMR wallet, could be locked.')
|
||||||
continue
|
continue
|
||||||
|
elif c == Coins.LTC:
|
||||||
|
ci_mweb = self.ci(Coins.LTC_MWEB)
|
||||||
|
is_encrypted, _ = self.getLockedState()
|
||||||
|
if not is_encrypted and not ci_mweb.has_mweb_wallet():
|
||||||
|
ci_mweb.init_wallet()
|
||||||
|
|
||||||
self.checkWalletSeed(c)
|
self.checkWalletSeed(c)
|
||||||
|
|
||||||
@ -850,6 +865,16 @@ class BasicSwap(BaseApp):
|
|||||||
if self.coin_clients[c]['connection_type'] == 'rpc':
|
if self.coin_clients[c]['connection_type'] == 'rpc':
|
||||||
yield c
|
yield c
|
||||||
|
|
||||||
|
def getListOfWalletCoins(self):
|
||||||
|
coins_list = copy.deepcopy(self.activeCoins())
|
||||||
|
# Always unlock Particl first
|
||||||
|
if Coins.PART in coins_list:
|
||||||
|
coins_list.pop(Coins.PART)
|
||||||
|
coins_list = [Coins.PART,] + coins_list
|
||||||
|
if Coins.LTC in coins_list:
|
||||||
|
coins_list.append(Coins.LTC_MWEB)
|
||||||
|
return coins_list
|
||||||
|
|
||||||
def changeWalletPasswords(self, old_password: str, new_password: str, coin=None) -> None:
|
def changeWalletPasswords(self, old_password: str, new_password: str, coin=None) -> None:
|
||||||
# Only the main wallet password is changed for monero, avoid issues by preventing until active swaps are complete
|
# Only the main wallet password is changed for monero, avoid issues by preventing until active swaps are complete
|
||||||
if len(self.swaps_in_progress) > 0:
|
if len(self.swaps_in_progress) > 0:
|
||||||
@ -861,8 +886,10 @@ class BasicSwap(BaseApp):
|
|||||||
if len(new_password) < 4:
|
if len(new_password) < 4:
|
||||||
raise ValueError('New password is too short')
|
raise ValueError('New password is too short')
|
||||||
|
|
||||||
|
coins_list = self.getListOfWalletCoins()
|
||||||
|
|
||||||
# Unlock wallets to ensure they all have the same password.
|
# Unlock wallets to ensure they all have the same password.
|
||||||
for c in self.activeCoins():
|
for c in coins_list:
|
||||||
if coin and c != coin:
|
if coin and c != coin:
|
||||||
continue
|
continue
|
||||||
ci = self.ci(c)
|
ci = self.ci(c)
|
||||||
@ -871,7 +898,7 @@ class BasicSwap(BaseApp):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise ValueError('Failed to unlock {}'.format(ci.coin_name()))
|
raise ValueError('Failed to unlock {}'.format(ci.coin_name()))
|
||||||
|
|
||||||
for c in self.activeCoins():
|
for c in coins_list:
|
||||||
if coin and c != coin:
|
if coin and c != coin:
|
||||||
continue
|
continue
|
||||||
self.ci(c).changeWalletPassword(old_password, new_password)
|
self.ci(c).changeWalletPassword(old_password, new_password)
|
||||||
@ -882,7 +909,7 @@ class BasicSwap(BaseApp):
|
|||||||
|
|
||||||
def unlockWallets(self, password: str, coin=None) -> None:
|
def unlockWallets(self, password: str, coin=None) -> None:
|
||||||
self._read_zmq_queue = False
|
self._read_zmq_queue = False
|
||||||
for c in self.activeCoins():
|
for c in self.getListOfWalletCoins():
|
||||||
if coin and c != coin:
|
if coin and c != coin:
|
||||||
continue
|
continue
|
||||||
self.ci(c).unlockWallet(password)
|
self.ci(c).unlockWallet(password)
|
||||||
@ -896,7 +923,7 @@ class BasicSwap(BaseApp):
|
|||||||
self._read_zmq_queue = False
|
self._read_zmq_queue = False
|
||||||
self.swaps_in_progress.clear()
|
self.swaps_in_progress.clear()
|
||||||
|
|
||||||
for c in self.activeCoins():
|
for c in self.getListOfWalletCoins():
|
||||||
if coin and c != coin:
|
if coin and c != coin:
|
||||||
continue
|
continue
|
||||||
self.ci(c).lockWallet()
|
self.ci(c).lockWallet()
|
||||||
@ -923,7 +950,6 @@ class BasicSwap(BaseApp):
|
|||||||
|
|
||||||
root_key = self.getWalletKey(coin_type, 1)
|
root_key = self.getWalletKey(coin_type, 1)
|
||||||
root_hash = ci.getSeedHash(root_key)
|
root_hash = ci.getSeedHash(root_key)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ci.initialiseWallet(root_key)
|
ci.initialiseWallet(root_key)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -931,6 +957,8 @@ class BasicSwap(BaseApp):
|
|||||||
self.log.error('initialiseWallet failed: {}'.format(str(e)))
|
self.log.error('initialiseWallet failed: {}'.format(str(e)))
|
||||||
if raise_errors:
|
if raise_errors:
|
||||||
raise e
|
raise e
|
||||||
|
if self.debug:
|
||||||
|
self.log.error(traceback.format_exc())
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -1167,6 +1195,11 @@ class BasicSwap(BaseApp):
|
|||||||
return coin_from in self.scriptless_coins + self.coins_without_segwit
|
return coin_from in self.scriptless_coins + self.coins_without_segwit
|
||||||
|
|
||||||
def validateSwapType(self, coin_from, coin_to, swap_type):
|
def validateSwapType(self, coin_from, coin_to, swap_type):
|
||||||
|
|
||||||
|
for coin in (coin_from, coin_to):
|
||||||
|
if coin in self.balance_only_coins:
|
||||||
|
raise ValueError('Invalid coin: {}'.format(coin.name))
|
||||||
|
|
||||||
if swap_type == SwapTypes.XMR_SWAP:
|
if swap_type == SwapTypes.XMR_SWAP:
|
||||||
reverse_bid: bool = self.is_reverse_ads_bid(coin_from)
|
reverse_bid: bool = self.is_reverse_ads_bid(coin_from)
|
||||||
itx_coin = coin_to if reverse_bid else coin_from
|
itx_coin = coin_to if reverse_bid else coin_from
|
||||||
@ -1812,6 +1845,14 @@ class BasicSwap(BaseApp):
|
|||||||
self.log.debug('In txn: {}'.format(txid))
|
self.log.debug('In txn: {}'.format(txid))
|
||||||
return txid
|
return txid
|
||||||
|
|
||||||
|
def withdrawLTC(self, type_from, value, addr_to, subfee):
|
||||||
|
ci = self.ci(Coins.LTC)
|
||||||
|
self.log.info('withdrawLTC %s %s to %s %s', value, ci.ticker(), addr_to, ' subfee' if subfee else '')
|
||||||
|
|
||||||
|
txid = ci.withdrawCoin(value, type_from, addr_to, subfee)
|
||||||
|
self.log.debug('In txn: {}'.format(txid))
|
||||||
|
return txid
|
||||||
|
|
||||||
def withdrawParticl(self, type_from, type_to, value, addr_to, subfee):
|
def withdrawParticl(self, type_from, type_to, value, addr_to, subfee):
|
||||||
self.log.info('withdrawParticl %s %s to %s %s %s', value, type_from, type_to, addr_to, ' subfee' if subfee else '')
|
self.log.info('withdrawParticl %s %s to %s %s %s', value, type_from, type_to, addr_to, ' subfee' if subfee else '')
|
||||||
|
|
||||||
@ -1827,7 +1868,7 @@ class BasicSwap(BaseApp):
|
|||||||
|
|
||||||
def cacheNewAddressForCoin(self, coin_type):
|
def cacheNewAddressForCoin(self, coin_type):
|
||||||
self.log.debug('cacheNewAddressForCoin %s', coin_type)
|
self.log.debug('cacheNewAddressForCoin %s', coin_type)
|
||||||
key_str = 'receive_addr_' + chainparams[coin_type]['name']
|
key_str = 'receive_addr_' + self.ci(coin_type).coin_name().lower()
|
||||||
addr = self.getReceiveAddressForCoin(coin_type)
|
addr = self.getReceiveAddressForCoin(coin_type)
|
||||||
self.setStringKV(key_str, addr)
|
self.setStringKV(key_str, addr)
|
||||||
return addr
|
return addr
|
||||||
@ -1864,7 +1905,7 @@ class BasicSwap(BaseApp):
|
|||||||
if expect_seedid is None:
|
if expect_seedid is None:
|
||||||
self.log.warning('Can\'t find expected wallet seed id for coin {}'.format(ci.coin_name()))
|
self.log.warning('Can\'t find expected wallet seed id for coin {}'.format(ci.coin_name()))
|
||||||
return False
|
return False
|
||||||
if c == Coins.BTC and len(ci.rpc_callback('listwallets')) < 1:
|
if c == Coins.BTC and len(ci.rpc('listwallets')) < 1:
|
||||||
self.log.warning('Missing wallet for coin {}'.format(ci.coin_name()))
|
self.log.warning('Missing wallet for coin {}'.format(ci.coin_name()))
|
||||||
return False
|
return False
|
||||||
if ci.checkExpectedSeed(expect_seedid):
|
if ci.checkExpectedSeed(expect_seedid):
|
||||||
@ -1893,7 +1934,8 @@ class BasicSwap(BaseApp):
|
|||||||
self.log.debug('getCachedAddressForCoin %s', coin_type)
|
self.log.debug('getCachedAddressForCoin %s', coin_type)
|
||||||
# TODO: auto refresh after used
|
# TODO: auto refresh after used
|
||||||
|
|
||||||
key_str = 'receive_addr_' + chainparams[coin_type]['name']
|
ci = self.ci(coin_type)
|
||||||
|
key_str = 'receive_addr_' + ci.coin_name().lower()
|
||||||
session = self.openSession()
|
session = self.openSession()
|
||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
@ -1908,9 +1950,22 @@ class BasicSwap(BaseApp):
|
|||||||
self.closeSession(session)
|
self.closeSession(session)
|
||||||
return addr
|
return addr
|
||||||
|
|
||||||
|
def cacheNewStealthAddressForCoin(self, coin_type):
|
||||||
|
self.log.debug('cacheNewStealthAddressForCoin %s', coin_type)
|
||||||
|
|
||||||
|
if coin_type == Coins.LTC_MWEB:
|
||||||
|
coin_type = Coins.LTC
|
||||||
|
ci = self.ci(coin_type)
|
||||||
|
key_str = 'stealth_addr_' + ci.coin_name().lower()
|
||||||
|
addr = ci.getNewStealthAddress()
|
||||||
|
self.setStringKV(key_str, addr)
|
||||||
|
return addr
|
||||||
|
|
||||||
def getCachedStealthAddressForCoin(self, coin_type):
|
def getCachedStealthAddressForCoin(self, coin_type):
|
||||||
self.log.debug('getCachedStealthAddressForCoin %s', coin_type)
|
self.log.debug('getCachedStealthAddressForCoin %s', coin_type)
|
||||||
|
|
||||||
|
if coin_type == Coins.LTC_MWEB:
|
||||||
|
coin_type = Coins.LTC
|
||||||
ci = self.ci(coin_type)
|
ci = self.ci(coin_type)
|
||||||
key_str = 'stealth_addr_' + ci.coin_name().lower()
|
key_str = 'stealth_addr_' + ci.coin_name().lower()
|
||||||
session = self.openSession()
|
session = self.openSession()
|
||||||
@ -2559,7 +2614,7 @@ class BasicSwap(BaseApp):
|
|||||||
|
|
||||||
address_out = self.getReceiveAddressFromPool(coin_from, offer_id, TxTypes.XMR_SWAP_A_LOCK)
|
address_out = self.getReceiveAddressFromPool(coin_from, offer_id, TxTypes.XMR_SWAP_A_LOCK)
|
||||||
if coin_from == Coins.PART_BLIND:
|
if coin_from == Coins.PART_BLIND:
|
||||||
addrinfo = ci_from.rpc_callback('getaddressinfo', [address_out])
|
addrinfo = ci_from.rpc('getaddressinfo', [address_out])
|
||||||
msg_buf.dest_af = bytes.fromhex(addrinfo['pubkey'])
|
msg_buf.dest_af = bytes.fromhex(addrinfo['pubkey'])
|
||||||
else:
|
else:
|
||||||
msg_buf.dest_af = ci_from.decodeAddress(address_out)
|
msg_buf.dest_af = ci_from.decodeAddress(address_out)
|
||||||
@ -2870,7 +2925,7 @@ class BasicSwap(BaseApp):
|
|||||||
|
|
||||||
address_out = self.getReceiveAddressFromPool(coin_from, bid.offer_id, TxTypes.XMR_SWAP_A_LOCK)
|
address_out = self.getReceiveAddressFromPool(coin_from, bid.offer_id, TxTypes.XMR_SWAP_A_LOCK)
|
||||||
if coin_from == Coins.PART_BLIND:
|
if coin_from == Coins.PART_BLIND:
|
||||||
addrinfo = ci_from.rpc_callback('getaddressinfo', [address_out])
|
addrinfo = ci_from.rpc('getaddressinfo', [address_out])
|
||||||
xmr_swap.dest_af = bytes.fromhex(addrinfo['pubkey'])
|
xmr_swap.dest_af = bytes.fromhex(addrinfo['pubkey'])
|
||||||
else:
|
else:
|
||||||
xmr_swap.dest_af = ci_from.decodeAddress(address_out)
|
xmr_swap.dest_af = ci_from.decodeAddress(address_out)
|
||||||
@ -3339,7 +3394,8 @@ class BasicSwap(BaseApp):
|
|||||||
bid.participate_tx.chain_height = participate_txn_height
|
bid.participate_tx.chain_height = participate_txn_height
|
||||||
|
|
||||||
# Start checking for spends of participate_txn before fully confirmed
|
# Start checking for spends of participate_txn before fully confirmed
|
||||||
self.log.debug('Watching %s chain for spend of output %s %d', chainparams[coin_type]['name'], txid_hex, vout)
|
ci = self.ci(coin_type)
|
||||||
|
self.log.debug('Watching %s chain for spend of output %s %d', ci.coin_name().lower(), txid_hex, vout)
|
||||||
self.addWatchedOutput(coin_type, bid_id, txid_hex, vout, BidStates.SWAP_PARTICIPATING)
|
self.addWatchedOutput(coin_type, bid_id, txid_hex, vout, BidStates.SWAP_PARTICIPATING)
|
||||||
|
|
||||||
def participateTxnConfirmed(self, bid_id: bytes, bid, offer) -> None:
|
def participateTxnConfirmed(self, bid_id: bytes, bid, offer) -> None:
|
||||||
@ -4151,7 +4207,7 @@ class BasicSwap(BaseApp):
|
|||||||
last_height_checked += 1
|
last_height_checked += 1
|
||||||
if c['last_height_checked'] != last_height_checked:
|
if c['last_height_checked'] != last_height_checked:
|
||||||
c['last_height_checked'] = last_height_checked
|
c['last_height_checked'] = last_height_checked
|
||||||
self.setIntKV('last_height_checked_' + chainparams[coin_type]['name'], last_height_checked)
|
self.setIntKV('last_height_checked_' + ci.coin_name().lower(), last_height_checked)
|
||||||
|
|
||||||
def expireMessages(self) -> None:
|
def expireMessages(self) -> None:
|
||||||
if self._is_locked is True:
|
if self._is_locked is True:
|
||||||
@ -6413,6 +6469,11 @@ class BasicSwap(BaseApp):
|
|||||||
rv['main_address'] = self.getCachedMainWalletAddress(ci)
|
rv['main_address'] = self.getCachedMainWalletAddress(ci)
|
||||||
elif coin == Coins.NAV:
|
elif coin == Coins.NAV:
|
||||||
rv['immature'] = walletinfo['immature_balance']
|
rv['immature'] = walletinfo['immature_balance']
|
||||||
|
elif coin == Coins.LTC:
|
||||||
|
rv['mweb_address'] = self.getCachedStealthAddressForCoin(Coins.LTC_MWEB)
|
||||||
|
rv['mweb_balance'] = walletinfo['mweb_balance']
|
||||||
|
rv['mweb_pending'] = walletinfo['mweb_unconfirmed'] + walletinfo['mweb_immature']
|
||||||
|
rv['mweb_pending'] = walletinfo['mweb_unconfirmed'] + walletinfo['mweb_immature']
|
||||||
|
|
||||||
return rv
|
return rv
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -6505,10 +6566,17 @@ class BasicSwap(BaseApp):
|
|||||||
wallet_data['lastupdated'] = row[3]
|
wallet_data['lastupdated'] = row[3]
|
||||||
wallet_data['updating'] = self._updating_wallets_info.get(coin_id, False)
|
wallet_data['updating'] = self._updating_wallets_info.get(coin_id, False)
|
||||||
|
|
||||||
# Ensure the latest deposit address is displayed
|
# Ensure the latest addresses are displayed
|
||||||
q = session.execute('SELECT value FROM kv_string WHERE key = "receive_addr_{}"'.format(chainparams[coin_id]['name']))
|
q = session.execute('SELECT key, value FROM kv_string WHERE key = "receive_addr_{0}" OR key = "stealth_addr_{0}"'.format(chainparams[coin_id]['name']))
|
||||||
for row in q:
|
for row in q:
|
||||||
wallet_data['deposit_address'] = row[0]
|
|
||||||
|
if row[0].startswith('stealth'):
|
||||||
|
if coin_id == Coins.LTC:
|
||||||
|
wallet_data['mweb_address'] = row[1]
|
||||||
|
else:
|
||||||
|
wallet_data['stealth_address'] = row[1]
|
||||||
|
else:
|
||||||
|
wallet_data['deposit_address'] = row[1]
|
||||||
|
|
||||||
if coin_id in rv:
|
if coin_id in rv:
|
||||||
rv[coin_id].update(wallet_data)
|
rv[coin_id].update(wallet_data)
|
||||||
|
@ -32,6 +32,7 @@ class Coins(IntEnum):
|
|||||||
DASH = 12
|
DASH = 12
|
||||||
FIRO = 13
|
FIRO = 13
|
||||||
NAV = 14
|
NAV = 14
|
||||||
|
LTC_MWEB = 15
|
||||||
|
|
||||||
|
|
||||||
chainparams = {
|
chainparams = {
|
||||||
|
@ -280,6 +280,8 @@ class HttpHandler(BaseHTTPRequestHandler):
|
|||||||
coin_id = int(get_data_entry(form_data, 'coin_type'))
|
coin_id = int(get_data_entry(form_data, 'coin_type'))
|
||||||
if coin_id in (-2, -3, -4):
|
if coin_id in (-2, -3, -4):
|
||||||
coin_type = Coins(Coins.XMR)
|
coin_type = Coins(Coins.XMR)
|
||||||
|
elif coin_id in (-5,):
|
||||||
|
coin_type = Coins(Coins.LTC)
|
||||||
else:
|
else:
|
||||||
coin_type = Coins(coin_id)
|
coin_type = Coins(coin_id)
|
||||||
except Exception:
|
except Exception:
|
||||||
@ -295,20 +297,23 @@ class HttpHandler(BaseHTTPRequestHandler):
|
|||||||
method = arr[0]
|
method = arr[0]
|
||||||
params = json.loads(arr[1]) if len(arr) > 1 else []
|
params = json.loads(arr[1]) if len(arr) > 1 else []
|
||||||
if coin_id == -4:
|
if coin_id == -4:
|
||||||
rv = ci.rpc_wallet_cb(method, params)
|
rv = ci.rpc_wallet(method, params)
|
||||||
elif coin_id == -3:
|
elif coin_id == -3:
|
||||||
rv = ci.rpc_cb(method, params)
|
rv = ci.rpc(method, params)
|
||||||
elif coin_id == -2:
|
elif coin_id == -2:
|
||||||
if params == []:
|
if params == []:
|
||||||
params = None
|
params = None
|
||||||
rv = ci.rpc_cb2(method, params)
|
rv = ci.rpc2(method, params)
|
||||||
else:
|
else:
|
||||||
raise ValueError('Unknown XMR RPC variant')
|
raise ValueError('Unknown XMR RPC variant')
|
||||||
result = json.dumps(rv, indent=4)
|
result = json.dumps(rv, indent=4)
|
||||||
else:
|
else:
|
||||||
if call_type == 'http':
|
if call_type == 'http':
|
||||||
method, params = parse_cmd(cmd, type_map)
|
method, params = parse_cmd(cmd, type_map)
|
||||||
rv = swap_client.ci(coin_type).rpc_callback(method, params)
|
if coin_id == -5:
|
||||||
|
rv = swap_client.ci(coin_type).rpc_wallet_mweb(method, params)
|
||||||
|
else:
|
||||||
|
rv = swap_client.ci(coin_type).rpc_wallet(method, params)
|
||||||
if not isinstance(rv, str):
|
if not isinstance(rv, str):
|
||||||
rv = json.dumps(rv, indent=4)
|
rv = json.dumps(rv, indent=4)
|
||||||
result = cmd + '\n' + rv
|
result = cmd + '\n' + rv
|
||||||
@ -323,6 +328,7 @@ class HttpHandler(BaseHTTPRequestHandler):
|
|||||||
|
|
||||||
coins = listAvailableCoins(swap_client, with_variants=False)
|
coins = listAvailableCoins(swap_client, with_variants=False)
|
||||||
coins = [c for c in coins if c[0] != Coins.XMR]
|
coins = [c for c in coins if c[0] != Coins.XMR]
|
||||||
|
coins.append((-5, 'Litecoin MWEB Wallet'))
|
||||||
coins.append((-2, 'Monero'))
|
coins.append((-2, 'Monero'))
|
||||||
coins.append((-3, 'Monero JSON'))
|
coins.append((-3, 'Monero JSON'))
|
||||||
coins.append((-4, 'Monero Wallet'))
|
coins.append((-4, 'Monero Wallet'))
|
||||||
|
@ -195,7 +195,9 @@ class BTCInterface(CoinInterface):
|
|||||||
self._rpc_host = coin_settings.get('rpchost', '127.0.0.1')
|
self._rpc_host = coin_settings.get('rpchost', '127.0.0.1')
|
||||||
self._rpcport = coin_settings['rpcport']
|
self._rpcport = coin_settings['rpcport']
|
||||||
self._rpcauth = coin_settings['rpcauth']
|
self._rpcauth = coin_settings['rpcauth']
|
||||||
self.rpc_callback = make_rpc_func(self._rpcport, self._rpcauth, host=self._rpc_host)
|
self.rpc = make_rpc_func(self._rpcport, self._rpcauth, host=self._rpc_host)
|
||||||
|
self._rpc_wallet = 'wallet.dat'
|
||||||
|
self.rpc_wallet = make_rpc_func(self._rpcport, self._rpcauth, host=self._rpc_host, wallet=self._rpc_wallet)
|
||||||
self.blocks_confirmed = coin_settings['blocks_confirmed']
|
self.blocks_confirmed = coin_settings['blocks_confirmed']
|
||||||
self.setConfTarget(coin_settings['conf_target'])
|
self.setConfTarget(coin_settings['conf_target'])
|
||||||
self._use_segwit = coin_settings['use_segwit']
|
self._use_segwit = coin_settings['use_segwit']
|
||||||
@ -204,6 +206,23 @@ class BTCInterface(CoinInterface):
|
|||||||
self._log = self._sc.log if self._sc and self._sc.log else logging
|
self._log = self._sc.log if self._sc and self._sc.log else logging
|
||||||
self._expect_seedid_hex = None
|
self._expect_seedid_hex = None
|
||||||
|
|
||||||
|
def checkWallets(self) -> int:
|
||||||
|
wallets = self.rpc('listwallets')
|
||||||
|
|
||||||
|
# Wallet name is "" for some LTC and PART installs on older cores
|
||||||
|
if self._rpc_wallet not in wallets and len(wallets) > 0:
|
||||||
|
self._log.debug('Changing {} wallet name.'.format(self.ticker()))
|
||||||
|
for wallet_name in wallets:
|
||||||
|
# Skip over other expected wallets
|
||||||
|
if wallet_name in ('mweb', ):
|
||||||
|
continue
|
||||||
|
self._rpc_wallet = wallet_name
|
||||||
|
self._log.info('Switched {} wallet name to {}.'.format(self.ticker(), self._rpc_wallet))
|
||||||
|
self.rpc_wallet = make_rpc_func(self._rpcport, self._rpcauth, host=self._rpc_host, wallet=self._rpc_wallet)
|
||||||
|
break
|
||||||
|
|
||||||
|
return len(wallets)
|
||||||
|
|
||||||
def using_segwit(self) -> bool:
|
def using_segwit(self) -> bool:
|
||||||
# Using btc native segwit
|
# Using btc native segwit
|
||||||
return self._use_segwit
|
return self._use_segwit
|
||||||
@ -239,34 +258,34 @@ class BTCInterface(CoinInterface):
|
|||||||
self._conf_target = new_conf_target
|
self._conf_target = new_conf_target
|
||||||
|
|
||||||
def testDaemonRPC(self, with_wallet=True) -> None:
|
def testDaemonRPC(self, with_wallet=True) -> None:
|
||||||
self.rpc_callback('getwalletinfo' if with_wallet else 'getblockchaininfo')
|
self.rpc_wallet('getwalletinfo' if with_wallet else 'getblockchaininfo')
|
||||||
|
|
||||||
def getDaemonVersion(self):
|
def getDaemonVersion(self):
|
||||||
return self.rpc_callback('getnetworkinfo')['version']
|
return self.rpc('getnetworkinfo')['version']
|
||||||
|
|
||||||
def getBlockchainInfo(self):
|
def getBlockchainInfo(self):
|
||||||
return self.rpc_callback('getblockchaininfo')
|
return self.rpc('getblockchaininfo')
|
||||||
|
|
||||||
def getChainHeight(self) -> int:
|
def getChainHeight(self) -> int:
|
||||||
return self.rpc_callback('getblockcount')
|
return self.rpc('getblockcount')
|
||||||
|
|
||||||
def getMempoolTx(self, txid):
|
def getMempoolTx(self, txid):
|
||||||
return self.rpc_callback('getrawtransaction', [txid.hex()])
|
return self.rpc('getrawtransaction', [txid.hex()])
|
||||||
|
|
||||||
def getBlockHeaderFromHeight(self, height):
|
def getBlockHeaderFromHeight(self, height):
|
||||||
block_hash = self.rpc_callback('getblockhash', [height])
|
block_hash = self.rpc('getblockhash', [height])
|
||||||
return self.rpc_callback('getblockheader', [block_hash])
|
return self.rpc('getblockheader', [block_hash])
|
||||||
|
|
||||||
def getBlockHeader(self, block_hash):
|
def getBlockHeader(self, block_hash):
|
||||||
return self.rpc_callback('getblockheader', [block_hash])
|
return self.rpc('getblockheader', [block_hash])
|
||||||
|
|
||||||
def getBlockHeaderAt(self, time: int, block_after=False):
|
def getBlockHeaderAt(self, time: int, block_after=False):
|
||||||
blockchaininfo = self.rpc_callback('getblockchaininfo')
|
blockchaininfo = self.rpc('getblockchaininfo')
|
||||||
last_block_header = self.rpc_callback('getblockheader', [blockchaininfo['bestblockhash']])
|
last_block_header = self.rpc('getblockheader', [blockchaininfo['bestblockhash']])
|
||||||
|
|
||||||
max_tries = 5000
|
max_tries = 5000
|
||||||
for i in range(max_tries):
|
for i in range(max_tries):
|
||||||
prev_block_header = self.rpc_callback('getblock', [last_block_header['previousblockhash']])
|
prev_block_header = self.rpc('getblock', [last_block_header['previousblockhash']])
|
||||||
if prev_block_header['time'] <= time:
|
if prev_block_header['time'] <= time:
|
||||||
return last_block_header if block_after else prev_block_header
|
return last_block_header if block_after else prev_block_header
|
||||||
|
|
||||||
@ -275,11 +294,10 @@ class BTCInterface(CoinInterface):
|
|||||||
|
|
||||||
def initialiseWallet(self, key_bytes: bytes) -> None:
|
def initialiseWallet(self, key_bytes: bytes) -> None:
|
||||||
key_wif = self.encodeKey(key_bytes)
|
key_wif = self.encodeKey(key_bytes)
|
||||||
|
self.rpc_wallet('sethdseed', [True, key_wif])
|
||||||
self.rpc_callback('sethdseed', [True, key_wif])
|
|
||||||
|
|
||||||
def getWalletInfo(self):
|
def getWalletInfo(self):
|
||||||
rv = self.rpc_callback('getwalletinfo')
|
rv = self.rpc_wallet('getwalletinfo')
|
||||||
rv['encrypted'] = 'unlocked_until' in rv
|
rv['encrypted'] = 'unlocked_until' in rv
|
||||||
rv['locked'] = rv.get('unlocked_until', 1) <= 0
|
rv['locked'] = rv.get('unlocked_until', 1) <= 0
|
||||||
return rv
|
return rv
|
||||||
@ -288,7 +306,7 @@ class BTCInterface(CoinInterface):
|
|||||||
return self._restore_height
|
return self._restore_height
|
||||||
|
|
||||||
def getWalletRestoreHeight(self) -> int:
|
def getWalletRestoreHeight(self) -> int:
|
||||||
start_time = self.rpc_callback('getwalletinfo')['keypoololdest']
|
start_time = self.rpc_wallet('getwalletinfo')['keypoololdest']
|
||||||
|
|
||||||
blockchaininfo = self.getBlockchainInfo()
|
blockchaininfo = self.getBlockchainInfo()
|
||||||
best_block = blockchaininfo['bestblockhash']
|
best_block = blockchaininfo['bestblockhash']
|
||||||
@ -312,7 +330,7 @@ class BTCInterface(CoinInterface):
|
|||||||
raise ValueError('{} wallet restore height not found.'.format(self.coin_name()))
|
raise ValueError('{} wallet restore height not found.'.format(self.coin_name()))
|
||||||
|
|
||||||
def getWalletSeedID(self) -> str:
|
def getWalletSeedID(self) -> str:
|
||||||
wi = self.rpc_callback('getwalletinfo')
|
wi = self.rpc_wallet('getwalletinfo')
|
||||||
return 'Not found' if 'hdseedid' not in wi else wi['hdseedid']
|
return 'Not found' if 'hdseedid' not in wi else wi['hdseedid']
|
||||||
|
|
||||||
def checkExpectedSeed(self, expect_seedid) -> bool:
|
def checkExpectedSeed(self, expect_seedid) -> bool:
|
||||||
@ -323,11 +341,11 @@ class BTCInterface(CoinInterface):
|
|||||||
args = [label]
|
args = [label]
|
||||||
if use_segwit:
|
if use_segwit:
|
||||||
args.append('bech32')
|
args.append('bech32')
|
||||||
return self.rpc_callback('getnewaddress', args)
|
return self.rpc_wallet('getnewaddress', args)
|
||||||
|
|
||||||
def isValidAddress(self, address: str) -> bool:
|
def isValidAddress(self, address: str) -> bool:
|
||||||
try:
|
try:
|
||||||
rv = self.rpc_callback('validateaddress', [address])
|
rv = self.rpc_wallet('validateaddress', [address])
|
||||||
if rv['isvalid'] is True:
|
if rv['isvalid'] is True:
|
||||||
return True
|
return True
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
@ -347,13 +365,13 @@ class BTCInterface(CoinInterface):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def isAddressMine(self, address: str, or_watch_only: bool = False) -> bool:
|
def isAddressMine(self, address: str, or_watch_only: bool = False) -> bool:
|
||||||
addr_info = self.rpc_callback('getaddressinfo', [address])
|
addr_info = self.rpc_wallet('getaddressinfo', [address])
|
||||||
if not or_watch_only:
|
if not or_watch_only:
|
||||||
return addr_info['ismine']
|
return addr_info['ismine']
|
||||||
return addr_info['ismine'] or addr_info['iswatchonly']
|
return addr_info['ismine'] or addr_info['iswatchonly']
|
||||||
|
|
||||||
def checkAddressMine(self, address: str) -> None:
|
def checkAddressMine(self, address: str) -> None:
|
||||||
addr_info = self.rpc_callback('getaddressinfo', [address])
|
addr_info = self.rpc_wallet('getaddressinfo', [address])
|
||||||
ensure(addr_info['ismine'], 'ismine is false')
|
ensure(addr_info['ismine'], 'ismine is false')
|
||||||
if self.sc._restrict_unknown_seed_wallets:
|
if self.sc._restrict_unknown_seed_wallets:
|
||||||
ensure(addr_info['hdseedid'] == self._expect_seedid_hex, 'unexpected seedid')
|
ensure(addr_info['hdseedid'] == self._expect_seedid_hex, 'unexpected seedid')
|
||||||
@ -369,16 +387,16 @@ class BTCInterface(CoinInterface):
|
|||||||
|
|
||||||
def try_get_fee_rate(self, conf_target):
|
def try_get_fee_rate(self, conf_target):
|
||||||
try:
|
try:
|
||||||
fee_rate = self.rpc_callback('estimatesmartfee', [conf_target])['feerate']
|
fee_rate = self.rpc_wallet('estimatesmartfee', [conf_target])['feerate']
|
||||||
assert (fee_rate > 0.0), 'Non positive feerate'
|
assert (fee_rate > 0.0), 'Non positive feerate'
|
||||||
return fee_rate, 'estimatesmartfee'
|
return fee_rate, 'estimatesmartfee'
|
||||||
except Exception:
|
except Exception:
|
||||||
try:
|
try:
|
||||||
fee_rate = self.rpc_callback('getwalletinfo')['paytxfee']
|
fee_rate = self.rpc_wallet('getwalletinfo')['paytxfee']
|
||||||
assert (fee_rate > 0.0), 'Non positive feerate'
|
assert (fee_rate > 0.0), 'Non positive feerate'
|
||||||
return fee_rate, 'paytxfee'
|
return fee_rate, 'paytxfee'
|
||||||
except Exception:
|
except Exception:
|
||||||
return self.rpc_callback('getnetworkinfo')['relayfee'], 'relayfee'
|
return self.rpc('getnetworkinfo')['relayfee'], 'relayfee'
|
||||||
|
|
||||||
fee_rate, rate_src = try_get_fee_rate(self, conf_target)
|
fee_rate, rate_src = try_get_fee_rate(self, conf_target)
|
||||||
if min_relay_fee and min_relay_fee > fee_rate:
|
if min_relay_fee and min_relay_fee > fee_rate:
|
||||||
@ -734,7 +752,7 @@ class BTCInterface(CoinInterface):
|
|||||||
add_bytes = 0
|
add_bytes = 0
|
||||||
add_witness_bytes = getCompactSizeLen(len(tx.vin))
|
add_witness_bytes = getCompactSizeLen(len(tx.vin))
|
||||||
for pi in tx.vin:
|
for pi in tx.vin:
|
||||||
ptx = self.rpc_callback('getrawtransaction', [i2h(pi.prevout.hash), True])
|
ptx = self.rpc('getrawtransaction', [i2h(pi.prevout.hash), True])
|
||||||
prevout = ptx['vout'][pi.prevout.n]
|
prevout = ptx['vout'][pi.prevout.n]
|
||||||
inputs_value += make_int(prevout['value'])
|
inputs_value += make_int(prevout['value'])
|
||||||
|
|
||||||
@ -942,13 +960,13 @@ class BTCInterface(CoinInterface):
|
|||||||
'lockUnspents': True,
|
'lockUnspents': True,
|
||||||
'feeRate': feerate_str,
|
'feeRate': feerate_str,
|
||||||
}
|
}
|
||||||
rv = self.rpc_callback('fundrawtransaction', [tx.hex(), options])
|
rv = self.rpc_wallet('fundrawtransaction', [tx.hex(), options])
|
||||||
return bytes.fromhex(rv['hex'])
|
return bytes.fromhex(rv['hex'])
|
||||||
|
|
||||||
def listInputs(self, tx_bytes):
|
def listInputs(self, tx_bytes):
|
||||||
tx = self.loadTx(tx_bytes)
|
tx = self.loadTx(tx_bytes)
|
||||||
|
|
||||||
all_locked = self.rpc_callback('listlockunspent')
|
all_locked = self.rpc_wallet('listlockunspent')
|
||||||
inputs = []
|
inputs = []
|
||||||
for pi in tx.vin:
|
for pi in tx.vin:
|
||||||
txid_hex = i2h(pi.prevout.hash)
|
txid_hex = i2h(pi.prevout.hash)
|
||||||
@ -962,19 +980,19 @@ class BTCInterface(CoinInterface):
|
|||||||
inputs = []
|
inputs = []
|
||||||
for pi in tx.vin:
|
for pi in tx.vin:
|
||||||
inputs.append({'txid': i2h(pi.prevout.hash), 'vout': pi.prevout.n})
|
inputs.append({'txid': i2h(pi.prevout.hash), 'vout': pi.prevout.n})
|
||||||
self.rpc_callback('lockunspent', [True, inputs])
|
self.rpc('lockunspent', [True, inputs])
|
||||||
|
|
||||||
def signTxWithWallet(self, tx: bytes) -> bytes:
|
def signTxWithWallet(self, tx: bytes) -> bytes:
|
||||||
rv = self.rpc_callback('signrawtransactionwithwallet', [tx.hex()])
|
rv = self.rpc_wallet('signrawtransactionwithwallet', [tx.hex()])
|
||||||
return bytes.fromhex(rv['hex'])
|
return bytes.fromhex(rv['hex'])
|
||||||
|
|
||||||
def signTxWithKey(self, tx: bytes, key: bytes) -> bytes:
|
def signTxWithKey(self, tx: bytes, key: bytes) -> bytes:
|
||||||
key_wif = self.encodeKey(key)
|
key_wif = self.encodeKey(key)
|
||||||
rv = self.rpc_callback('signrawtransactionwithkey', [tx.hex(), [key_wif, ]])
|
rv = self.rpc('signrawtransactionwithkey', [tx.hex(), [key_wif, ]])
|
||||||
return bytes.fromhex(rv['hex'])
|
return bytes.fromhex(rv['hex'])
|
||||||
|
|
||||||
def publishTx(self, tx: bytes):
|
def publishTx(self, tx: bytes):
|
||||||
return self.rpc_callback('sendrawtransaction', [tx.hex()])
|
return self.rpc('sendrawtransaction', [tx.hex()])
|
||||||
|
|
||||||
def encodeTx(self, tx) -> bytes:
|
def encodeTx(self, tx) -> bytes:
|
||||||
return tx.serialize()
|
return tx.serialize()
|
||||||
@ -1018,18 +1036,18 @@ class BTCInterface(CoinInterface):
|
|||||||
return self.getScriptForPubkeyHash(self.getPubkeyHash(K))
|
return self.getScriptForPubkeyHash(self.getPubkeyHash(K))
|
||||||
|
|
||||||
def scanTxOutset(self, dest):
|
def scanTxOutset(self, dest):
|
||||||
return self.rpc_callback('scantxoutset', ['start', ['raw({})'.format(dest.hex())]])
|
return self.rpc('scantxoutset', ['start', ['raw({})'.format(dest.hex())]])
|
||||||
|
|
||||||
def getTransaction(self, txid: bytes):
|
def getTransaction(self, txid: bytes):
|
||||||
try:
|
try:
|
||||||
return bytes.fromhex(self.rpc_callback('getrawtransaction', [txid.hex()]))
|
return bytes.fromhex(self.rpc('getrawtransaction', [txid.hex()]))
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
# TODO: filter errors
|
# TODO: filter errors
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def getWalletTransaction(self, txid: bytes):
|
def getWalletTransaction(self, txid: bytes):
|
||||||
try:
|
try:
|
||||||
return bytes.fromhex(self.rpc_callback('gettransaction', [txid.hex()]))
|
return bytes.fromhex(self.rpc('gettransaction', [txid.hex()]))
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
# TODO: filter errors
|
# TODO: filter errors
|
||||||
return None
|
return None
|
||||||
@ -1115,7 +1133,7 @@ class BTCInterface(CoinInterface):
|
|||||||
|
|
||||||
def spendBLockTx(self, chain_b_lock_txid: bytes, address_to: str, kbv: bytes, kbs: bytes, cb_swap_value: int, b_fee: int, restore_height: int) -> bytes:
|
def spendBLockTx(self, chain_b_lock_txid: bytes, address_to: str, kbv: bytes, kbs: bytes, cb_swap_value: int, b_fee: int, restore_height: int) -> bytes:
|
||||||
self._log.info('spendBLockTx %s:\n', chain_b_lock_txid.hex())
|
self._log.info('spendBLockTx %s:\n', chain_b_lock_txid.hex())
|
||||||
wtx = self.rpc_callback('gettransaction', [chain_b_lock_txid.hex(), ])
|
wtx = self.rpc_wallet('gettransaction', [chain_b_lock_txid.hex(), ])
|
||||||
lock_tx = self.loadTx(bytes.fromhex(wtx['hex']))
|
lock_tx = self.loadTx(bytes.fromhex(wtx['hex']))
|
||||||
|
|
||||||
Kbs = self.getPubkey(kbs)
|
Kbs = self.getPubkey(kbs)
|
||||||
@ -1144,10 +1162,10 @@ class BTCInterface(CoinInterface):
|
|||||||
return bytes.fromhex(self.publishTx(b_lock_spend_tx))
|
return bytes.fromhex(self.publishTx(b_lock_spend_tx))
|
||||||
|
|
||||||
def importWatchOnlyAddress(self, address: str, label: str):
|
def importWatchOnlyAddress(self, address: str, label: str):
|
||||||
self.rpc_callback('importaddress', [address, label, False])
|
self.rpc_wallet('importaddress', [address, label, False])
|
||||||
|
|
||||||
def isWatchOnlyAddress(self, address: str):
|
def isWatchOnlyAddress(self, address: str):
|
||||||
addr_info = self.rpc_callback('getaddressinfo', [address])
|
addr_info = self.rpc_wallet('getaddressinfo', [address])
|
||||||
return addr_info['iswatchonly']
|
return addr_info['iswatchonly']
|
||||||
|
|
||||||
def getSCLockScriptAddress(self, lock_script):
|
def getSCLockScriptAddress(self, lock_script):
|
||||||
@ -1161,11 +1179,11 @@ class BTCInterface(CoinInterface):
|
|||||||
self.importWatchOnlyAddress(dest_address, 'bid')
|
self.importWatchOnlyAddress(dest_address, 'bid')
|
||||||
self._log.info('Imported watch-only addr: {}'.format(dest_address))
|
self._log.info('Imported watch-only addr: {}'.format(dest_address))
|
||||||
self._log.info('Rescanning {} chain from height: {}'.format(self.coin_name(), rescan_from))
|
self._log.info('Rescanning {} chain from height: {}'.format(self.coin_name(), rescan_from))
|
||||||
self.rpc_callback('rescanblockchain', [rescan_from])
|
self.rpc_wallet('rescanblockchain', [rescan_from])
|
||||||
|
|
||||||
return_txid = True if txid is None else False
|
return_txid = True if txid is None else False
|
||||||
if txid is None:
|
if txid is None:
|
||||||
txns = self.rpc_callback('listunspent', [0, 9999999, [dest_address, ]])
|
txns = self.rpc_wallet('listunspent', [0, 9999999, [dest_address, ]])
|
||||||
|
|
||||||
for tx in txns:
|
for tx in txns:
|
||||||
if self.make_int(tx['amount']) == bid_amount:
|
if self.make_int(tx['amount']) == bid_amount:
|
||||||
@ -1176,11 +1194,11 @@ class BTCInterface(CoinInterface):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
tx = self.rpc_callback('gettransaction', [txid.hex()])
|
tx = self.rpc_wallet('gettransaction', [txid.hex()])
|
||||||
|
|
||||||
block_height = 0
|
block_height = 0
|
||||||
if 'blockhash' in tx:
|
if 'blockhash' in tx:
|
||||||
block_header = self.rpc_callback('getblockheader', [tx['blockhash']])
|
block_header = self.rpc('getblockheader', [tx['blockhash']])
|
||||||
block_height = block_header['height']
|
block_height = block_header['height']
|
||||||
|
|
||||||
rv = {
|
rv = {
|
||||||
@ -1192,7 +1210,7 @@ class BTCInterface(CoinInterface):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
if find_index:
|
if find_index:
|
||||||
tx_obj = self.rpc_callback('decoderawtransaction', [tx['hex']])
|
tx_obj = self.rpc('decoderawtransaction', [tx['hex']])
|
||||||
rv['index'] = find_vout_for_address_from_txobj(tx_obj, dest_address)
|
rv['index'] = find_vout_for_address_from_txobj(tx_obj, dest_address)
|
||||||
|
|
||||||
if return_txid:
|
if return_txid:
|
||||||
@ -1202,7 +1220,7 @@ class BTCInterface(CoinInterface):
|
|||||||
|
|
||||||
def getOutput(self, txid, dest_script, expect_value, xmr_swap=None):
|
def getOutput(self, txid, dest_script, expect_value, xmr_swap=None):
|
||||||
# TODO: Use getrawtransaction if txindex is active
|
# TODO: Use getrawtransaction if txindex is active
|
||||||
utxos = self.rpc_callback('scantxoutset', ['start', ['raw({})'.format(dest_script.hex())]])
|
utxos = self.rpc('scantxoutset', ['start', ['raw({})'.format(dest_script.hex())]])
|
||||||
if 'height' in utxos: # chain_height not returned by v18 codebase
|
if 'height' in utxos: # chain_height not returned by v18 codebase
|
||||||
chain_height = utxos['height']
|
chain_height = utxos['height']
|
||||||
else:
|
else:
|
||||||
@ -1225,7 +1243,7 @@ class BTCInterface(CoinInterface):
|
|||||||
|
|
||||||
def withdrawCoin(self, value, addr_to, subfee):
|
def withdrawCoin(self, value, addr_to, subfee):
|
||||||
params = [addr_to, value, '', '', subfee, True, self._conf_target]
|
params = [addr_to, value, '', '', subfee, True, self._conf_target]
|
||||||
return self.rpc_callback('sendtoaddress', params)
|
return self.rpc_wallet('sendtoaddress', params)
|
||||||
|
|
||||||
def signCompact(self, k, message):
|
def signCompact(self, k, message):
|
||||||
message_hash = hashlib.sha256(bytes(message, 'utf-8')).digest()
|
message_hash = hashlib.sha256(bytes(message, 'utf-8')).digest()
|
||||||
@ -1318,10 +1336,10 @@ class BTCInterface(CoinInterface):
|
|||||||
return length
|
return length
|
||||||
|
|
||||||
def describeTx(self, tx_hex: str):
|
def describeTx(self, tx_hex: str):
|
||||||
return self.rpc_callback('decoderawtransaction', [tx_hex])
|
return self.rpc('decoderawtransaction', [tx_hex])
|
||||||
|
|
||||||
def getSpendableBalance(self) -> int:
|
def getSpendableBalance(self) -> int:
|
||||||
return self.make_int(self.rpc_callback('getbalances')['mine']['trusted'])
|
return self.make_int(self.rpc_wallet('getbalances')['mine']['trusted'])
|
||||||
|
|
||||||
def createUTXO(self, value_sats: int):
|
def createUTXO(self, value_sats: int):
|
||||||
# Create a new address and send value_sats to it
|
# Create a new address and send value_sats to it
|
||||||
@ -1334,7 +1352,7 @@ class BTCInterface(CoinInterface):
|
|||||||
return self.withdrawCoin(self.format_amount(value_sats), address, False), address
|
return self.withdrawCoin(self.format_amount(value_sats), address, False), address
|
||||||
|
|
||||||
def createRawFundedTransaction(self, addr_to: str, amount: int, sub_fee: bool = False, lock_unspents: bool = True) -> str:
|
def createRawFundedTransaction(self, addr_to: str, amount: int, sub_fee: bool = False, lock_unspents: bool = True) -> str:
|
||||||
txn = self.rpc_callback('createrawtransaction', [[], {addr_to: self.format_amount(amount)}])
|
txn = self.rpc('createrawtransaction', [[], {addr_to: self.format_amount(amount)}])
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
'lockUnspents': lock_unspents,
|
'lockUnspents': lock_unspents,
|
||||||
@ -1342,18 +1360,18 @@ class BTCInterface(CoinInterface):
|
|||||||
}
|
}
|
||||||
if sub_fee:
|
if sub_fee:
|
||||||
options['subtractFeeFromOutputs'] = [0,]
|
options['subtractFeeFromOutputs'] = [0,]
|
||||||
return self.rpc_callback('fundrawtransaction', [txn, options])['hex']
|
return self.rpc_wallet('fundrawtransaction', [txn, options])['hex']
|
||||||
|
|
||||||
def createRawSignedTransaction(self, addr_to, amount) -> str:
|
def createRawSignedTransaction(self, addr_to, amount) -> str:
|
||||||
txn_funded = self.createRawFundedTransaction(addr_to, amount)
|
txn_funded = self.createRawFundedTransaction(addr_to, amount)
|
||||||
return self.rpc_callback('signrawtransactionwithwallet', [txn_funded])['hex']
|
return self.rpc_wallet('signrawtransactionwithwallet', [txn_funded])['hex']
|
||||||
|
|
||||||
def getBlockWithTxns(self, block_hash: str):
|
def getBlockWithTxns(self, block_hash: str):
|
||||||
return self.rpc_callback('getblock', [block_hash, 2])
|
return self.rpc('getblock', [block_hash, 2])
|
||||||
|
|
||||||
def getUnspentsByAddr(self):
|
def getUnspentsByAddr(self):
|
||||||
unspent_addr = dict()
|
unspent_addr = dict()
|
||||||
unspent = self.rpc_callback('listunspent')
|
unspent = self.rpc_wallet('listunspent')
|
||||||
for u in unspent:
|
for u in unspent:
|
||||||
if u['spendable'] is not True:
|
if u['spendable'] is not True:
|
||||||
continue
|
continue
|
||||||
@ -1361,11 +1379,11 @@ class BTCInterface(CoinInterface):
|
|||||||
return unspent_addr
|
return unspent_addr
|
||||||
|
|
||||||
def getUTXOBalance(self, address: str):
|
def getUTXOBalance(self, address: str):
|
||||||
num_blocks = self.rpc_callback('getblockcount')
|
num_blocks = self.rpc('getblockcount')
|
||||||
|
|
||||||
sum_unspent = 0
|
sum_unspent = 0
|
||||||
self._log.debug('[rm] scantxoutset start') # scantxoutset is slow
|
self._log.debug('[rm] scantxoutset start') # scantxoutset is slow
|
||||||
ro = self.rpc_callback('scantxoutset', ['start', ['addr({})'.format(address)]]) # TODO: Use combo(address) where possible
|
ro = self.rpc('scantxoutset', ['start', ['addr({})'.format(address)]]) # TODO: Use combo(address) where possible
|
||||||
self._log.debug('[rm] scantxoutset end')
|
self._log.debug('[rm] scantxoutset end')
|
||||||
for o in ro['unspents']:
|
for o in ro['unspents']:
|
||||||
sum_unspent += self.make_int(o['amount'])
|
sum_unspent += self.make_int(o['amount'])
|
||||||
@ -1391,7 +1409,7 @@ class BTCInterface(CoinInterface):
|
|||||||
sign_for_addr = self.pkh_to_address(pkh)
|
sign_for_addr = self.pkh_to_address(pkh)
|
||||||
self._log.debug('sign_for_addr converted %s', sign_for_addr)
|
self._log.debug('sign_for_addr converted %s', sign_for_addr)
|
||||||
|
|
||||||
signature = self.rpc_callback('signmessage', [sign_for_addr, sign_for_addr + '_swap_proof_' + extra_commit_bytes.hex()])
|
signature = self.rpc_wallet('signmessage', [sign_for_addr, sign_for_addr + '_swap_proof_' + extra_commit_bytes.hex()])
|
||||||
|
|
||||||
prove_utxos = [] # TODO: Send specific utxos
|
prove_utxos = [] # TODO: Send specific utxos
|
||||||
return (sign_for_addr, signature, prove_utxos)
|
return (sign_for_addr, signature, prove_utxos)
|
||||||
@ -1416,17 +1434,17 @@ class BTCInterface(CoinInterface):
|
|||||||
return self.getUTXOBalance(address)
|
return self.getUTXOBalance(address)
|
||||||
|
|
||||||
def isWalletEncrypted(self) -> bool:
|
def isWalletEncrypted(self) -> bool:
|
||||||
wallet_info = self.rpc_callback('getwalletinfo')
|
wallet_info = self.rpc_wallet('getwalletinfo')
|
||||||
return 'unlocked_until' in wallet_info
|
return 'unlocked_until' in wallet_info
|
||||||
|
|
||||||
def isWalletLocked(self) -> bool:
|
def isWalletLocked(self) -> bool:
|
||||||
wallet_info = self.rpc_callback('getwalletinfo')
|
wallet_info = self.rpc_wallet('getwalletinfo')
|
||||||
if 'unlocked_until' in wallet_info and wallet_info['unlocked_until'] <= 0:
|
if 'unlocked_until' in wallet_info and wallet_info['unlocked_until'] <= 0:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def isWalletEncryptedLocked(self):
|
def isWalletEncryptedLocked(self):
|
||||||
wallet_info = self.rpc_callback('getwalletinfo')
|
wallet_info = self.rpc_wallet('getwalletinfo')
|
||||||
encrypted = 'unlocked_until' in wallet_info
|
encrypted = 'unlocked_until' in wallet_info
|
||||||
locked = encrypted and wallet_info['unlocked_until'] <= 0
|
locked = encrypted and wallet_info['unlocked_until'] <= 0
|
||||||
return encrypted, locked
|
return encrypted, locked
|
||||||
@ -1436,8 +1454,8 @@ class BTCInterface(CoinInterface):
|
|||||||
if old_password == '':
|
if old_password == '':
|
||||||
if self.isWalletEncrypted():
|
if self.isWalletEncrypted():
|
||||||
raise ValueError('Old password must be set')
|
raise ValueError('Old password must be set')
|
||||||
return self.rpc_callback('encryptwallet', [new_password])
|
return self.rpc_wallet('encryptwallet', [new_password])
|
||||||
self.rpc_callback('walletpassphrasechange', [old_password, new_password])
|
self.rpc_wallet('walletpassphrasechange', [old_password, new_password])
|
||||||
|
|
||||||
def unlockWallet(self, password: str):
|
def unlockWallet(self, password: str):
|
||||||
if password == '':
|
if password == '':
|
||||||
@ -1447,21 +1465,20 @@ class BTCInterface(CoinInterface):
|
|||||||
if self.coin_type() == Coins.BTC:
|
if self.coin_type() == Coins.BTC:
|
||||||
# Recreate wallet if none found
|
# Recreate wallet if none found
|
||||||
# Required when encrypting an existing btc wallet, workaround is to delete the btc wallet and recreate
|
# Required when encrypting an existing btc wallet, workaround is to delete the btc wallet and recreate
|
||||||
wallets = self.rpc_callback('listwallets')
|
wallets = self.rpc('listwallets')
|
||||||
if len(wallets) < 1:
|
if len(wallets) < 1:
|
||||||
self._log.info('Creating wallet.dat for {}.'.format(self.coin_name()))
|
self._log.info('Creating wallet.dat for {}.'.format(self.coin_name()))
|
||||||
# wallet_name, disable_private_keys, blank, passphrase, avoid_reuse, descriptors
|
# wallet_name, disable_private_keys, blank, passphrase, avoid_reuse, descriptors
|
||||||
self.rpc_callback('createwallet', ['wallet.dat', False, True, '', False, False])
|
self.rpc('createwallet', ['wallet.dat', False, True, '', False, False])
|
||||||
self.rpc_callback('encryptwallet', [password])
|
self.rpc_wallet('encryptwallet', [password])
|
||||||
|
|
||||||
# Max timeout value, ~3 years
|
# Max timeout value, ~3 years
|
||||||
self.rpc_callback('walletpassphrase', [password, 100000000])
|
self.rpc_wallet('walletpassphrase', [password, 100000000])
|
||||||
|
|
||||||
self._sc.checkWalletSeed(self.coin_type())
|
self._sc.checkWalletSeed(self.coin_type())
|
||||||
|
|
||||||
def lockWallet(self):
|
def lockWallet(self):
|
||||||
self._log.info('lockWallet - {}'.format(self.ticker()))
|
self._log.info('lockWallet - {}'.format(self.ticker()))
|
||||||
self.rpc_callback('walletlock')
|
self.rpc_wallet('walletlock')
|
||||||
|
|
||||||
def get_p2sh_script_pubkey(self, script: bytearray) -> bytearray:
|
def get_p2sh_script_pubkey(self, script: bytearray) -> bytearray:
|
||||||
script_hash = hash160(script)
|
script_hash = hash160(script)
|
||||||
@ -1474,7 +1491,7 @@ class BTCInterface(CoinInterface):
|
|||||||
def findTxnByHash(self, txid_hex: str):
|
def findTxnByHash(self, txid_hex: str):
|
||||||
# Only works for wallet txns
|
# Only works for wallet txns
|
||||||
try:
|
try:
|
||||||
rv = self.rpc_callback('gettransaction', [txid_hex])
|
rv = self.rpc_wallet('gettransaction', [txid_hex])
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
self._log.debug('findTxnByHash getrawtransaction failed: {}'.format(txid_hex))
|
self._log.debug('findTxnByHash getrawtransaction failed: {}'.format(txid_hex))
|
||||||
return None
|
return None
|
||||||
|
@ -32,7 +32,7 @@ class DASHInterface(BTCInterface):
|
|||||||
words = self.seedToMnemonic(key)
|
words = self.seedToMnemonic(key)
|
||||||
|
|
||||||
mnemonic_passphrase = ''
|
mnemonic_passphrase = ''
|
||||||
self.rpc_callback('upgradetohd', [words, mnemonic_passphrase, self._wallet_passphrase])
|
self.rpc_wallet('upgradetohd', [words, mnemonic_passphrase, self._wallet_passphrase])
|
||||||
self._have_checked_seed = False
|
self._have_checked_seed = False
|
||||||
if self._wallet_passphrase != '':
|
if self._wallet_passphrase != '':
|
||||||
self.unlockWallet(self._wallet_passphrase)
|
self.unlockWallet(self._wallet_passphrase)
|
||||||
@ -42,7 +42,7 @@ class DASHInterface(BTCInterface):
|
|||||||
|
|
||||||
def checkExpectedSeed(self, key_hash: str):
|
def checkExpectedSeed(self, key_hash: str):
|
||||||
try:
|
try:
|
||||||
rv = self.rpc_callback('dumphdinfo')
|
rv = self.rpc_wallet('dumphdinfo')
|
||||||
entropy = Mnemonic('english').to_entropy(rv['mnemonic'].split(' '))
|
entropy = Mnemonic('english').to_entropy(rv['mnemonic'].split(' '))
|
||||||
entropy_hash = self.getAddressHashFromKey(entropy)[::-1].hex()
|
entropy_hash = self.getAddressHashFromKey(entropy)[::-1].hex()
|
||||||
self._have_checked_seed = True
|
self._have_checked_seed = True
|
||||||
@ -53,10 +53,10 @@ class DASHInterface(BTCInterface):
|
|||||||
|
|
||||||
def withdrawCoin(self, value, addr_to, subfee):
|
def withdrawCoin(self, value, addr_to, subfee):
|
||||||
params = [addr_to, value, '', '', subfee, False, False, self._conf_target]
|
params = [addr_to, value, '', '', subfee, False, False, self._conf_target]
|
||||||
return self.rpc_callback('sendtoaddress', params)
|
return self.rpc_wallet('sendtoaddress', params)
|
||||||
|
|
||||||
def getSpendableBalance(self) -> int:
|
def getSpendableBalance(self) -> int:
|
||||||
return self.make_int(self.rpc_callback('getwalletinfo')['balance'])
|
return self.make_int(self.rpc_wallet('getwalletinfo')['balance'])
|
||||||
|
|
||||||
def getScriptForPubkeyHash(self, pkh: bytes) -> bytearray:
|
def getScriptForPubkeyHash(self, pkh: bytes) -> bytearray:
|
||||||
# Return P2PKH
|
# Return P2PKH
|
||||||
@ -72,7 +72,7 @@ class DASHInterface(BTCInterface):
|
|||||||
def findTxnByHash(self, txid_hex: str):
|
def findTxnByHash(self, txid_hex: str):
|
||||||
# Only works for wallet txns
|
# Only works for wallet txns
|
||||||
try:
|
try:
|
||||||
rv = self.rpc_callback('gettransaction', [txid_hex])
|
rv = self.rpc_wallet('gettransaction', [txid_hex])
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
self._log.debug('findTxnByHash getrawtransaction failed: {}'.format(txid_hex))
|
self._log.debug('findTxnByHash getrawtransaction failed: {}'.format(txid_hex))
|
||||||
return None
|
return None
|
||||||
|
@ -13,6 +13,7 @@ from basicswap.util import (
|
|||||||
i2b,
|
i2b,
|
||||||
ensure,
|
ensure,
|
||||||
)
|
)
|
||||||
|
from basicswap.rpc import make_rpc_func
|
||||||
from basicswap.util.crypto import hash160
|
from basicswap.util.crypto import hash160
|
||||||
from basicswap.util.address import decodeAddress
|
from basicswap.util.address import decodeAddress
|
||||||
from basicswap.chainparams import Coins
|
from basicswap.chainparams import Coins
|
||||||
@ -36,6 +37,14 @@ class FIROInterface(BTCInterface):
|
|||||||
def coin_type():
|
def coin_type():
|
||||||
return Coins.FIRO
|
return Coins.FIRO
|
||||||
|
|
||||||
|
def __init__(self, coin_settings, network, swap_client=None):
|
||||||
|
super(FIROInterface, self).__init__(coin_settings, network, swap_client)
|
||||||
|
# No multiwallet support
|
||||||
|
self.rpc_wallet = make_rpc_func(self._rpcport, self._rpcauth, host=self._rpc_host)
|
||||||
|
|
||||||
|
def checkWallets(self) -> int:
|
||||||
|
return 1
|
||||||
|
|
||||||
def getExchangeName(self, exchange_name):
|
def getExchangeName(self, exchange_name):
|
||||||
return 'zcoin'
|
return 'zcoin'
|
||||||
|
|
||||||
@ -44,9 +53,9 @@ class FIROInterface(BTCInterface):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def getNewAddress(self, use_segwit, label='swap_receive'):
|
def getNewAddress(self, use_segwit, label='swap_receive'):
|
||||||
return self.rpc_callback('getnewaddress', [label])
|
return self.rpc('getnewaddress', [label])
|
||||||
# addr_plain = self.rpc_callback('getnewaddress', [label])
|
# addr_plain = self.rpc('getnewaddress', [label])
|
||||||
# return self.rpc_callback('addwitnessaddress', [addr_plain])
|
# return self.rpc('addwitnessaddress', [addr_plain])
|
||||||
|
|
||||||
def decodeAddress(self, address):
|
def decodeAddress(self, address):
|
||||||
return decodeAddress(address)[1:]
|
return decodeAddress(address)[1:]
|
||||||
@ -58,11 +67,11 @@ class FIROInterface(BTCInterface):
|
|||||||
raise ValueError('TODO')
|
raise ValueError('TODO')
|
||||||
|
|
||||||
def isWatchOnlyAddress(self, address):
|
def isWatchOnlyAddress(self, address):
|
||||||
addr_info = self.rpc_callback('validateaddress', [address])
|
addr_info = self.rpc('validateaddress', [address])
|
||||||
return addr_info['iswatchonly']
|
return addr_info['iswatchonly']
|
||||||
|
|
||||||
def isAddressMine(self, address: str, or_watch_only: bool = False) -> bool:
|
def isAddressMine(self, address: str, or_watch_only: bool = False) -> bool:
|
||||||
addr_info = self.rpc_callback('validateaddress', [address])
|
addr_info = self.rpc('validateaddress', [address])
|
||||||
if not or_watch_only:
|
if not or_watch_only:
|
||||||
return addr_info['ismine']
|
return addr_info['ismine']
|
||||||
return addr_info['ismine'] or addr_info['iswatchonly']
|
return addr_info['ismine'] or addr_info['iswatchonly']
|
||||||
@ -73,8 +82,8 @@ class FIROInterface(BTCInterface):
|
|||||||
|
|
||||||
if not self.isAddressMine(address, or_watch_only=True):
|
if not self.isAddressMine(address, or_watch_only=True):
|
||||||
# Expects P2WSH nested in BIP16_P2SH
|
# Expects P2WSH nested in BIP16_P2SH
|
||||||
ro = self.rpc_callback('importaddress', [lock_tx_dest.hex(), 'bid lock', False, True])
|
ro = self.rpc('importaddress', [lock_tx_dest.hex(), 'bid lock', False, True])
|
||||||
addr_info = self.rpc_callback('validateaddress', [address])
|
addr_info = self.rpc('validateaddress', [address])
|
||||||
|
|
||||||
return address
|
return address
|
||||||
|
|
||||||
@ -89,7 +98,7 @@ class FIROInterface(BTCInterface):
|
|||||||
|
|
||||||
return_txid = True if txid is None else False
|
return_txid = True if txid is None else False
|
||||||
if txid is None:
|
if txid is None:
|
||||||
txns = self.rpc_callback('listunspent', [0, 9999999, [dest_address, ]])
|
txns = self.rpc('listunspent', [0, 9999999, [dest_address, ]])
|
||||||
|
|
||||||
for tx in txns:
|
for tx in txns:
|
||||||
if self.make_int(tx['amount']) == bid_amount:
|
if self.make_int(tx['amount']) == bid_amount:
|
||||||
@ -100,11 +109,11 @@ class FIROInterface(BTCInterface):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
tx = self.rpc_callback('gettransaction', [txid.hex()])
|
tx = self.rpc('gettransaction', [txid.hex()])
|
||||||
|
|
||||||
block_height = 0
|
block_height = 0
|
||||||
if 'blockhash' in tx:
|
if 'blockhash' in tx:
|
||||||
block_header = self.rpc_callback('getblockheader', [tx['blockhash']])
|
block_header = self.rpc('getblockheader', [tx['blockhash']])
|
||||||
block_height = block_header['height']
|
block_height = block_header['height']
|
||||||
|
|
||||||
rv = {
|
rv = {
|
||||||
@ -116,7 +125,7 @@ class FIROInterface(BTCInterface):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
if find_index:
|
if find_index:
|
||||||
tx_obj = self.rpc_callback('decoderawtransaction', [tx['hex']])
|
tx_obj = self.rpc('decoderawtransaction', [tx['hex']])
|
||||||
rv['index'] = find_vout_for_address_from_txobj(tx_obj, dest_address)
|
rv['index'] = find_vout_for_address_from_txobj(tx_obj, dest_address)
|
||||||
|
|
||||||
if return_txid:
|
if return_txid:
|
||||||
@ -135,11 +144,11 @@ class FIROInterface(BTCInterface):
|
|||||||
return self.fundTx(tx_bytes, feerate)
|
return self.fundTx(tx_bytes, feerate)
|
||||||
|
|
||||||
def signTxWithWallet(self, tx):
|
def signTxWithWallet(self, tx):
|
||||||
rv = self.rpc_callback('signrawtransaction', [tx.hex()])
|
rv = self.rpc('signrawtransaction', [tx.hex()])
|
||||||
return bytes.fromhex(rv['hex'])
|
return bytes.fromhex(rv['hex'])
|
||||||
|
|
||||||
def createRawFundedTransaction(self, addr_to: str, amount: int, sub_fee: bool = False, lock_unspents: bool = True) -> str:
|
def createRawFundedTransaction(self, addr_to: str, amount: int, sub_fee: bool = False, lock_unspents: bool = True) -> str:
|
||||||
txn = self.rpc_callback('createrawtransaction', [[], {addr_to: self.format_amount(amount)}])
|
txn = self.rpc('createrawtransaction', [[], {addr_to: self.format_amount(amount)}])
|
||||||
fee_rate, fee_src = self.get_fee_rate(self._conf_target)
|
fee_rate, fee_src = self.get_fee_rate(self._conf_target)
|
||||||
self._log.debug(f'Fee rate: {fee_rate}, source: {fee_src}, block target: {self._conf_target}')
|
self._log.debug(f'Fee rate: {fee_rate}, source: {fee_src}, block target: {self._conf_target}')
|
||||||
options = {
|
options = {
|
||||||
@ -148,11 +157,11 @@ class FIROInterface(BTCInterface):
|
|||||||
}
|
}
|
||||||
if sub_fee:
|
if sub_fee:
|
||||||
options['subtractFeeFromOutputs'] = [0,]
|
options['subtractFeeFromOutputs'] = [0,]
|
||||||
return self.rpc_callback('fundrawtransaction', [txn, options])['hex']
|
return self.rpc('fundrawtransaction', [txn, options])['hex']
|
||||||
|
|
||||||
def createRawSignedTransaction(self, addr_to, amount) -> str:
|
def createRawSignedTransaction(self, addr_to, amount) -> str:
|
||||||
txn_funded = self.createRawFundedTransaction(addr_to, amount)
|
txn_funded = self.createRawFundedTransaction(addr_to, amount)
|
||||||
return self.rpc_callback('signrawtransaction', [txn_funded])['hex']
|
return self.rpc('signrawtransaction', [txn_funded])['hex']
|
||||||
|
|
||||||
def getScriptForPubkeyHash(self, pkh: bytes) -> bytearray:
|
def getScriptForPubkeyHash(self, pkh: bytes) -> bytearray:
|
||||||
# Return P2PKH
|
# Return P2PKH
|
||||||
@ -180,13 +189,13 @@ class FIROInterface(BTCInterface):
|
|||||||
|
|
||||||
def withdrawCoin(self, value, addr_to, subfee):
|
def withdrawCoin(self, value, addr_to, subfee):
|
||||||
params = [addr_to, value, '', '', subfee]
|
params = [addr_to, value, '', '', subfee]
|
||||||
return self.rpc_callback('sendtoaddress', params)
|
return self.rpc('sendtoaddress', params)
|
||||||
|
|
||||||
def getWalletSeedID(self):
|
def getWalletSeedID(self):
|
||||||
return self.rpc_callback('getwalletinfo')['hdmasterkeyid']
|
return self.rpc('getwalletinfo')['hdmasterkeyid']
|
||||||
|
|
||||||
def getSpendableBalance(self) -> int:
|
def getSpendableBalance(self) -> int:
|
||||||
return self.make_int(self.rpc_callback('getwalletinfo')['balance'])
|
return self.make_int(self.rpc('getwalletinfo')['balance'])
|
||||||
|
|
||||||
def getBLockSpendTxFee(self, tx, fee_rate: int) -> int:
|
def getBLockSpendTxFee(self, tx, fee_rate: int) -> int:
|
||||||
add_bytes = 107
|
add_bytes = 107
|
||||||
@ -197,13 +206,13 @@ class FIROInterface(BTCInterface):
|
|||||||
|
|
||||||
def signTxWithKey(self, tx: bytes, key: bytes) -> bytes:
|
def signTxWithKey(self, tx: bytes, key: bytes) -> bytes:
|
||||||
key_wif = self.encodeKey(key)
|
key_wif = self.encodeKey(key)
|
||||||
rv = self.rpc_callback('signrawtransaction', [tx.hex(), [], [key_wif, ]])
|
rv = self.rpc('signrawtransaction', [tx.hex(), [], [key_wif, ]])
|
||||||
return bytes.fromhex(rv['hex'])
|
return bytes.fromhex(rv['hex'])
|
||||||
|
|
||||||
def findTxnByHash(self, txid_hex: str):
|
def findTxnByHash(self, txid_hex: str):
|
||||||
# Only works for wallet txns
|
# Only works for wallet txns
|
||||||
try:
|
try:
|
||||||
rv = self.rpc_callback('gettransaction', [txid_hex])
|
rv = self.rpc('gettransaction', [txid_hex])
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
self._log.debug('findTxnByHash getrawtransaction failed: {}'.format(txid_hex))
|
self._log.debug('findTxnByHash getrawtransaction failed: {}'.format(txid_hex))
|
||||||
return None
|
return None
|
||||||
@ -216,7 +225,7 @@ class FIROInterface(BTCInterface):
|
|||||||
# TODO: Lock unspent and use same output/s to fund bid
|
# TODO: Lock unspent and use same output/s to fund bid
|
||||||
|
|
||||||
unspents_by_addr = dict()
|
unspents_by_addr = dict()
|
||||||
unspents = self.rpc_callback('listunspent')
|
unspents = self.rpc('listunspent')
|
||||||
for u in unspents:
|
for u in unspents:
|
||||||
if u['spendable'] is not True:
|
if u['spendable'] is not True:
|
||||||
continue
|
continue
|
||||||
@ -276,7 +285,7 @@ class FIROInterface(BTCInterface):
|
|||||||
sign_for_addr = self.pkh_to_address(pkh)
|
sign_for_addr = self.pkh_to_address(pkh)
|
||||||
self._log.debug('sign_for_addr converted %s', sign_for_addr)
|
self._log.debug('sign_for_addr converted %s', sign_for_addr)
|
||||||
|
|
||||||
signature = self.rpc_callback('signmessage', [sign_for_addr, sign_for_addr + '_swap_proof_' + utxos_hash.hex() + extra_commit_bytes.hex()])
|
signature = self.rpc('signmessage', [sign_for_addr, sign_for_addr + '_swap_proof_' + utxos_hash.hex() + extra_commit_bytes.hex()])
|
||||||
|
|
||||||
return (sign_for_addr, signature, prove_utxos)
|
return (sign_for_addr, signature, prove_utxos)
|
||||||
|
|
||||||
@ -296,7 +305,7 @@ class FIROInterface(BTCInterface):
|
|||||||
|
|
||||||
sum_value: int = 0
|
sum_value: int = 0
|
||||||
for outpoint in utxos:
|
for outpoint in utxos:
|
||||||
txout = self.rpc_callback('gettxout', [outpoint[0].hex(), outpoint[1]])
|
txout = self.rpc('gettxout', [outpoint[0].hex(), outpoint[1]])
|
||||||
sum_value += self.make_int(txout['value'])
|
sum_value += self.make_int(txout['value'])
|
||||||
|
|
||||||
return sum_value
|
return sum_value
|
||||||
@ -307,15 +316,15 @@ class FIROInterface(BTCInterface):
|
|||||||
chain_blocks: int = self.getChainHeight()
|
chain_blocks: int = self.getChainHeight()
|
||||||
|
|
||||||
current_height: int = chain_blocks
|
current_height: int = chain_blocks
|
||||||
block_hash = self.rpc_callback('getblockhash', [current_height])
|
block_hash = self.rpc('getblockhash', [current_height])
|
||||||
|
|
||||||
script_hash: bytes = self.decodeAddress(addr_find)
|
script_hash: bytes = self.decodeAddress(addr_find)
|
||||||
find_scriptPubKey = self.getDestForScriptHash(script_hash)
|
find_scriptPubKey = self.getDestForScriptHash(script_hash)
|
||||||
|
|
||||||
while current_height > height_start:
|
while current_height > height_start:
|
||||||
block_hash = self.rpc_callback('getblockhash', [current_height])
|
block_hash = self.rpc('getblockhash', [current_height])
|
||||||
|
|
||||||
block = self.rpc_callback('getblock', [block_hash, False])
|
block = self.rpc('getblock', [block_hash, False])
|
||||||
decoded_block = CBlock()
|
decoded_block = CBlock()
|
||||||
decoded_block = FromHex(decoded_block, block)
|
decoded_block = FromHex(decoded_block, block)
|
||||||
for tx in decoded_block.vtx:
|
for tx in decoded_block.vtx:
|
||||||
@ -325,22 +334,22 @@ class FIROInterface(BTCInterface):
|
|||||||
txid = i2b(tx.sha256)
|
txid = i2b(tx.sha256)
|
||||||
self._log.info('Found output to addr: {} in tx {} in block {}'.format(addr_find, txid.hex(), block_hash))
|
self._log.info('Found output to addr: {} in tx {} in block {}'.format(addr_find, txid.hex(), block_hash))
|
||||||
self._log.info('rescanblockchain hack invalidateblock {}'.format(block_hash))
|
self._log.info('rescanblockchain hack invalidateblock {}'.format(block_hash))
|
||||||
self.rpc_callback('invalidateblock', [block_hash])
|
self.rpc('invalidateblock', [block_hash])
|
||||||
self.rpc_callback('reconsiderblock', [block_hash])
|
self.rpc('reconsiderblock', [block_hash])
|
||||||
return
|
return
|
||||||
current_height -= 1
|
current_height -= 1
|
||||||
|
|
||||||
def getBlockWithTxns(self, block_hash):
|
def getBlockWithTxns(self, block_hash):
|
||||||
# TODO: Bypass decoderawtransaction and getblockheader
|
# TODO: Bypass decoderawtransaction and getblockheader
|
||||||
block = self.rpc_callback('getblock', [block_hash, False])
|
block = self.rpc('getblock', [block_hash, False])
|
||||||
block_header = self.rpc_callback('getblockheader', [block_hash])
|
block_header = self.rpc('getblockheader', [block_hash])
|
||||||
decoded_block = CBlock()
|
decoded_block = CBlock()
|
||||||
decoded_block = FromHex(decoded_block, block)
|
decoded_block = FromHex(decoded_block, block)
|
||||||
|
|
||||||
tx_rv = []
|
tx_rv = []
|
||||||
for tx in decoded_block.vtx:
|
for tx in decoded_block.vtx:
|
||||||
tx_hex = tx.serialize_with_witness().hex()
|
tx_hex = tx.serialize_with_witness().hex()
|
||||||
tx_dec = self.rpc_callback('decoderawtransaction', [tx_hex])
|
tx_dec = self.rpc('decoderawtransaction', [tx_hex])
|
||||||
if 'hex' not in tx_dec:
|
if 'hex' not in tx_dec:
|
||||||
tx_dec['hex'] = tx_hex
|
tx_dec['hex'] = tx_hex
|
||||||
|
|
||||||
|
@ -1,15 +1,117 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# Copyright (c) 2020 tecnovert
|
# Copyright (c) 2020-2023 tecnovert
|
||||||
# Distributed under the MIT software license, see the accompanying
|
# Distributed under the MIT software license, see the accompanying
|
||||||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
from .btc import BTCInterface
|
from .btc import BTCInterface
|
||||||
from basicswap.chainparams import Coins
|
from basicswap.rpc import make_rpc_func
|
||||||
|
from basicswap.chainparams import Coins, chainparams
|
||||||
|
|
||||||
|
|
||||||
class LTCInterface(BTCInterface):
|
class LTCInterface(BTCInterface):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def coin_type():
|
def coin_type():
|
||||||
return Coins.LTC
|
return Coins.LTC
|
||||||
|
|
||||||
|
def __init__(self, coin_settings, network, swap_client=None):
|
||||||
|
super(LTCInterface, self).__init__(coin_settings, network, swap_client)
|
||||||
|
self._rpc_wallet_mweb = 'mweb'
|
||||||
|
self.rpc_wallet_mweb = make_rpc_func(self._rpcport, self._rpcauth, host=self._rpc_host, wallet=self._rpc_wallet_mweb)
|
||||||
|
|
||||||
|
def getNewMwebAddress(self, use_segwit=False, label='swap_receive') -> str:
|
||||||
|
return self.rpc_wallet_mweb('getnewaddress', [label, 'mweb'])
|
||||||
|
|
||||||
|
def getNewStealthAddress(self, label=''):
|
||||||
|
return self.getNewMwebAddress(False, label)
|
||||||
|
|
||||||
|
def withdrawCoin(self, value, type_from: str, addr_to: str, subfee: bool) -> str:
|
||||||
|
params = [addr_to, value, '', '', subfee, True, self._conf_target]
|
||||||
|
if type_from == 'mweb':
|
||||||
|
return self.rpc_wallet_mweb('sendtoaddress', params)
|
||||||
|
return self.rpc_wallet('sendtoaddress', params)
|
||||||
|
|
||||||
|
def getWalletInfo(self):
|
||||||
|
rv = self.rpc_wallet('getwalletinfo')
|
||||||
|
rv['encrypted'] = 'unlocked_until' in rv
|
||||||
|
rv['locked'] = rv.get('unlocked_until', 1) <= 0
|
||||||
|
|
||||||
|
mweb_info = self.rpc_wallet_mweb('getwalletinfo')
|
||||||
|
rv['mweb_balance'] = mweb_info['balance']
|
||||||
|
rv['mweb_unconfirmed'] = mweb_info['unconfirmed_balance']
|
||||||
|
rv['mweb_immature'] = mweb_info['immature_balance']
|
||||||
|
return rv
|
||||||
|
|
||||||
|
|
||||||
|
class LTCInterfaceMWEB(LTCInterface):
|
||||||
|
@staticmethod
|
||||||
|
def coin_type():
|
||||||
|
return Coins.LTC_MWEB
|
||||||
|
|
||||||
|
def __init__(self, coin_settings, network, swap_client=None):
|
||||||
|
super(LTCInterfaceMWEB, self).__init__(coin_settings, network, swap_client)
|
||||||
|
self._rpc_wallet = 'mweb'
|
||||||
|
self.rpc_wallet = make_rpc_func(self._rpcport, self._rpcauth, host=self._rpc_host, wallet=self._rpc_wallet)
|
||||||
|
|
||||||
|
def chainparams(self):
|
||||||
|
return chainparams[Coins.LTC]
|
||||||
|
|
||||||
|
def chainparams_network(self):
|
||||||
|
return chainparams[Coins.LTC][self._network]
|
||||||
|
|
||||||
|
def coin_name(self) -> str:
|
||||||
|
coin_chainparams = chainparams[Coins.LTC]
|
||||||
|
if coin_chainparams.get('use_ticker_as_name', False):
|
||||||
|
return coin_chainparams['ticker'] + ' MWEB'
|
||||||
|
return coin_chainparams['name'].capitalize() + ' MWEB'
|
||||||
|
|
||||||
|
def ticker(self) -> str:
|
||||||
|
ticker = chainparams[Coins.LTC]['ticker']
|
||||||
|
if self._network == 'testnet':
|
||||||
|
ticker = 't' + ticker
|
||||||
|
elif self._network == 'regtest':
|
||||||
|
ticker = 'rt' + ticker
|
||||||
|
return ticker + '_MWEB'
|
||||||
|
|
||||||
|
def getNewAddress(self, use_segwit=False, label='swap_receive') -> str:
|
||||||
|
return self.getNewMwebAddress()
|
||||||
|
|
||||||
|
def has_mweb_wallet(self) -> bool:
|
||||||
|
return 'mweb' in self.rpc('listwallets')
|
||||||
|
|
||||||
|
def init_wallet(self, password=None):
|
||||||
|
# If system is encrypted mweb wallet will be created at first unlock
|
||||||
|
|
||||||
|
self._log.info('init_wallet - {}'.format(self.ticker()))
|
||||||
|
|
||||||
|
self._log.info('Creating mweb wallet for {}.'.format(self.coin_name()))
|
||||||
|
# wallet_name, disable_private_keys, blank, passphrase, avoid_reuse, descriptors, load_on_startup
|
||||||
|
self.rpc('createwallet', ['mweb', False, True, password, False, False, True])
|
||||||
|
|
||||||
|
if password is not None:
|
||||||
|
# Max timeout value, ~3 years
|
||||||
|
self.rpc_wallet('walletpassphrase', [password, 100000000])
|
||||||
|
|
||||||
|
if self.getWalletSeedID() == 'Not found':
|
||||||
|
self._sc.initialiseWallet(self.coin_type())
|
||||||
|
|
||||||
|
# Workaround to trigger mweb_spk_man->LoadMWEBKeychain()
|
||||||
|
self.rpc('unloadwallet', ['mweb'])
|
||||||
|
self.rpc('loadwallet', ['mweb'])
|
||||||
|
if password is not None:
|
||||||
|
self.rpc_wallet('walletpassphrase', [password, 100000000])
|
||||||
|
self.rpc_wallet('keypoolrefill')
|
||||||
|
|
||||||
|
def unlockWallet(self, password: str):
|
||||||
|
if password == '':
|
||||||
|
return
|
||||||
|
self._log.info('unlockWallet - {}'.format(self.ticker()))
|
||||||
|
|
||||||
|
if not self.has_mweb_wallet():
|
||||||
|
self.init_wallet(password)
|
||||||
|
else:
|
||||||
|
# Max timeout value, ~3 years
|
||||||
|
self.rpc_wallet('walletpassphrase', [password, 100000000])
|
||||||
|
|
||||||
|
self._sc.checkWalletSeed(self.coin_type())
|
||||||
|
@ -14,6 +14,7 @@ from coincurve.keys import (
|
|||||||
PrivateKey,
|
PrivateKey,
|
||||||
)
|
)
|
||||||
from .btc import BTCInterface, find_vout_for_address_from_txobj, findOutput
|
from .btc import BTCInterface, find_vout_for_address_from_txobj, findOutput
|
||||||
|
from basicswap.rpc import make_rpc_func
|
||||||
from basicswap.chainparams import Coins
|
from basicswap.chainparams import Coins
|
||||||
from basicswap.interface.contrib.nav_test_framework.mininode import (
|
from basicswap.interface.contrib.nav_test_framework.mininode import (
|
||||||
CTxIn,
|
CTxIn,
|
||||||
@ -63,6 +64,14 @@ class NAVInterface(BTCInterface):
|
|||||||
def txoType():
|
def txoType():
|
||||||
return CTxOut
|
return CTxOut
|
||||||
|
|
||||||
|
def __init__(self, coin_settings, network, swap_client=None):
|
||||||
|
super(NAVInterface, self).__init__(coin_settings, network, swap_client)
|
||||||
|
# No multiwallet support
|
||||||
|
self.rpc_wallet = make_rpc_func(self._rpcport, self._rpcauth, host=self._rpc_host)
|
||||||
|
|
||||||
|
def checkWallets(self) -> int:
|
||||||
|
return 1
|
||||||
|
|
||||||
def use_p2shp2wsh(self) -> bool:
|
def use_p2shp2wsh(self) -> bool:
|
||||||
# p2sh-p2wsh
|
# p2sh-p2wsh
|
||||||
return True
|
return True
|
||||||
@ -75,24 +84,24 @@ class NAVInterface(BTCInterface):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def getWalletSeedID(self):
|
def getWalletSeedID(self):
|
||||||
return self.rpc_callback('getwalletinfo')['hdmasterkeyid']
|
return self.rpc('getwalletinfo')['hdmasterkeyid']
|
||||||
|
|
||||||
def withdrawCoin(self, value, addr_to: str, subfee: bool):
|
def withdrawCoin(self, value, addr_to: str, subfee: bool):
|
||||||
strdzeel = ''
|
strdzeel = ''
|
||||||
params = [addr_to, value, '', '', strdzeel, subfee]
|
params = [addr_to, value, '', '', strdzeel, subfee]
|
||||||
return self.rpc_callback('sendtoaddress', params)
|
return self.rpc('sendtoaddress', params)
|
||||||
|
|
||||||
def getSpendableBalance(self) -> int:
|
def getSpendableBalance(self) -> int:
|
||||||
return self.make_int(self.rpc_callback('getwalletinfo')['balance'])
|
return self.make_int(self.rpc('getwalletinfo')['balance'])
|
||||||
|
|
||||||
def signTxWithWallet(self, tx: bytes) -> bytes:
|
def signTxWithWallet(self, tx: bytes) -> bytes:
|
||||||
rv = self.rpc_callback('signrawtransaction', [tx.hex()])
|
rv = self.rpc('signrawtransaction', [tx.hex()])
|
||||||
|
|
||||||
return bytes.fromhex(rv['hex'])
|
return bytes.fromhex(rv['hex'])
|
||||||
|
|
||||||
def checkExpectedSeed(self, key_hash: str):
|
def checkExpectedSeed(self, key_hash: str):
|
||||||
try:
|
try:
|
||||||
rv = self.rpc_callback('dumpmnemonic')
|
rv = self.rpc('dumpmnemonic')
|
||||||
entropy = Mnemonic('english').to_entropy(rv.split(' '))
|
entropy = Mnemonic('english').to_entropy(rv.split(' '))
|
||||||
|
|
||||||
entropy_hash = self.getAddressHashFromKey(entropy)[::-1].hex()
|
entropy_hash = self.getAddressHashFromKey(entropy)[::-1].hex()
|
||||||
@ -155,7 +164,7 @@ class NAVInterface(BTCInterface):
|
|||||||
# TODO: Lock unspent and use same output/s to fund bid
|
# TODO: Lock unspent and use same output/s to fund bid
|
||||||
|
|
||||||
unspents_by_addr = dict()
|
unspents_by_addr = dict()
|
||||||
unspents = self.rpc_callback('listunspent')
|
unspents = self.rpc('listunspent')
|
||||||
for u in unspents:
|
for u in unspents:
|
||||||
if u['spendable'] is not True:
|
if u['spendable'] is not True:
|
||||||
continue
|
continue
|
||||||
@ -211,13 +220,13 @@ class NAVInterface(BTCInterface):
|
|||||||
|
|
||||||
if self.using_segwit(): # TODO: Use isSegwitAddress when scantxoutset can use combo
|
if self.using_segwit(): # TODO: Use isSegwitAddress when scantxoutset can use combo
|
||||||
# 'Address does not refer to key' for non p2pkh
|
# 'Address does not refer to key' for non p2pkh
|
||||||
addr_info = self.rpc_callback('validateaddress', [addr, ])
|
addr_info = self.rpc('validateaddress', [addr, ])
|
||||||
if 'isscript' in addr_info and addr_info['isscript'] and 'hex' in addr_info:
|
if 'isscript' in addr_info and addr_info['isscript'] and 'hex' in addr_info:
|
||||||
pkh = bytes.fromhex(addr_info['hex'])[2:]
|
pkh = bytes.fromhex(addr_info['hex'])[2:]
|
||||||
sign_for_addr = self.pkh_to_address(pkh)
|
sign_for_addr = self.pkh_to_address(pkh)
|
||||||
self._log.debug('sign_for_addr converted %s', sign_for_addr)
|
self._log.debug('sign_for_addr converted %s', sign_for_addr)
|
||||||
|
|
||||||
signature = self.rpc_callback('signmessage', [sign_for_addr, sign_for_addr + '_swap_proof_' + utxos_hash.hex() + extra_commit_bytes.hex()])
|
signature = self.rpc('signmessage', [sign_for_addr, sign_for_addr + '_swap_proof_' + utxos_hash.hex() + extra_commit_bytes.hex()])
|
||||||
|
|
||||||
return (sign_for_addr, signature, prove_utxos)
|
return (sign_for_addr, signature, prove_utxos)
|
||||||
|
|
||||||
@ -237,13 +246,13 @@ class NAVInterface(BTCInterface):
|
|||||||
|
|
||||||
sum_value: int = 0
|
sum_value: int = 0
|
||||||
for outpoint in utxos:
|
for outpoint in utxos:
|
||||||
txout = self.rpc_callback('gettxout', [outpoint[0].hex(), outpoint[1]])
|
txout = self.rpc('gettxout', [outpoint[0].hex(), outpoint[1]])
|
||||||
sum_value += self.make_int(txout['value'])
|
sum_value += self.make_int(txout['value'])
|
||||||
|
|
||||||
return sum_value
|
return sum_value
|
||||||
|
|
||||||
def createRawFundedTransaction(self, addr_to: str, amount: int, sub_fee: bool = False, lock_unspents: bool = True) -> str:
|
def createRawFundedTransaction(self, addr_to: str, amount: int, sub_fee: bool = False, lock_unspents: bool = True) -> str:
|
||||||
txn = self.rpc_callback('createrawtransaction', [[], {addr_to: self.format_amount(amount)}])
|
txn = self.rpc('createrawtransaction', [[], {addr_to: self.format_amount(amount)}])
|
||||||
fee_rate, fee_src = self.get_fee_rate(self._conf_target)
|
fee_rate, fee_src = self.get_fee_rate(self._conf_target)
|
||||||
self._log.debug(f'Fee rate: {fee_rate}, source: {fee_src}, block target: {self._conf_target}')
|
self._log.debug(f'Fee rate: {fee_rate}, source: {fee_src}, block target: {self._conf_target}')
|
||||||
if sub_fee:
|
if sub_fee:
|
||||||
@ -254,17 +263,17 @@ class NAVInterface(BTCInterface):
|
|||||||
return self.fundTx(txn, fee_rate, lock_unspents).hex()
|
return self.fundTx(txn, fee_rate, lock_unspents).hex()
|
||||||
|
|
||||||
def isAddressMine(self, address: str, or_watch_only: bool = False) -> bool:
|
def isAddressMine(self, address: str, or_watch_only: bool = False) -> bool:
|
||||||
addr_info = self.rpc_callback('validateaddress', [address])
|
addr_info = self.rpc('validateaddress', [address])
|
||||||
if not or_watch_only:
|
if not or_watch_only:
|
||||||
return addr_info['ismine']
|
return addr_info['ismine']
|
||||||
return addr_info['ismine'] or addr_info['iswatchonly']
|
return addr_info['ismine'] or addr_info['iswatchonly']
|
||||||
|
|
||||||
def createRawSignedTransaction(self, addr_to, amount) -> str:
|
def createRawSignedTransaction(self, addr_to, amount) -> str:
|
||||||
txn_funded = self.createRawFundedTransaction(addr_to, amount)
|
txn_funded = self.createRawFundedTransaction(addr_to, amount)
|
||||||
return self.rpc_callback('signrawtransaction', [txn_funded])['hex']
|
return self.rpc('signrawtransaction', [txn_funded])['hex']
|
||||||
|
|
||||||
def getBlockchainInfo(self):
|
def getBlockchainInfo(self):
|
||||||
rv = self.rpc_callback('getblockchaininfo')
|
rv = self.rpc('getblockchaininfo')
|
||||||
synced = round(rv['verificationprogress'], 3)
|
synced = round(rv['verificationprogress'], 3)
|
||||||
if synced >= 0.997:
|
if synced >= 0.997:
|
||||||
rv['verificationprogress'] = 1.0
|
rv['verificationprogress'] = 1.0
|
||||||
@ -278,7 +287,7 @@ class NAVInterface(BTCInterface):
|
|||||||
return pubkeyToAddress(self.chainparams_network()['script_address'], script)
|
return pubkeyToAddress(self.chainparams_network()['script_address'], script)
|
||||||
|
|
||||||
def find_prevout_info(self, txn_hex: str, txn_script: bytes):
|
def find_prevout_info(self, txn_hex: str, txn_script: bytes):
|
||||||
txjs = self.rpc_callback('decoderawtransaction', [txn_hex])
|
txjs = self.rpc('decoderawtransaction', [txn_hex])
|
||||||
n = getVoutByScriptPubKey(txjs, self.getScriptDest(txn_script).hex())
|
n = getVoutByScriptPubKey(txjs, self.getScriptDest(txn_script).hex())
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -290,9 +299,9 @@ class NAVInterface(BTCInterface):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def getNewAddress(self, use_segwit: bool, label: str = 'swap_receive') -> str:
|
def getNewAddress(self, use_segwit: bool, label: str = 'swap_receive') -> str:
|
||||||
address: str = self.rpc_callback('getnewaddress', [label,])
|
address: str = self.rpc('getnewaddress', [label,])
|
||||||
if use_segwit:
|
if use_segwit:
|
||||||
return self.rpc_callback('addwitnessaddress', [address,])
|
return self.rpc('addwitnessaddress', [address,])
|
||||||
return address
|
return address
|
||||||
|
|
||||||
def createRedeemTxn(self, prevout, output_addr: str, output_value: int, txn_script: bytes) -> str:
|
def createRedeemTxn(self, prevout, output_addr: str, output_value: int, txn_script: bytes) -> str:
|
||||||
@ -385,15 +394,15 @@ class NAVInterface(BTCInterface):
|
|||||||
chain_blocks: int = self.getChainHeight()
|
chain_blocks: int = self.getChainHeight()
|
||||||
|
|
||||||
current_height: int = chain_blocks
|
current_height: int = chain_blocks
|
||||||
block_hash = self.rpc_callback('getblockhash', [current_height])
|
block_hash = self.rpc('getblockhash', [current_height])
|
||||||
|
|
||||||
script_hash: bytes = self.decodeAddress(addr_find)
|
script_hash: bytes = self.decodeAddress(addr_find)
|
||||||
find_scriptPubKey = self.getDestForScriptHash(script_hash)
|
find_scriptPubKey = self.getDestForScriptHash(script_hash)
|
||||||
|
|
||||||
while current_height > height_start:
|
while current_height > height_start:
|
||||||
block_hash = self.rpc_callback('getblockhash', [current_height])
|
block_hash = self.rpc('getblockhash', [current_height])
|
||||||
|
|
||||||
block = self.rpc_callback('getblock', [block_hash, False])
|
block = self.rpc('getblock', [block_hash, False])
|
||||||
decoded_block = CBlock()
|
decoded_block = CBlock()
|
||||||
decoded_block = FromHex(decoded_block, block)
|
decoded_block = FromHex(decoded_block, block)
|
||||||
for tx in decoded_block.vtx:
|
for tx in decoded_block.vtx:
|
||||||
@ -403,8 +412,8 @@ class NAVInterface(BTCInterface):
|
|||||||
txid = i2b(tx.sha256)
|
txid = i2b(tx.sha256)
|
||||||
self._log.info('Found output to addr: {} in tx {} in block {}'.format(addr_find, txid.hex(), block_hash))
|
self._log.info('Found output to addr: {} in tx {} in block {}'.format(addr_find, txid.hex(), block_hash))
|
||||||
self._log.info('rescanblockchain hack invalidateblock {}'.format(block_hash))
|
self._log.info('rescanblockchain hack invalidateblock {}'.format(block_hash))
|
||||||
self.rpc_callback('invalidateblock', [block_hash])
|
self.rpc('invalidateblock', [block_hash])
|
||||||
self.rpc_callback('reconsiderblock', [block_hash])
|
self.rpc('reconsiderblock', [block_hash])
|
||||||
return
|
return
|
||||||
current_height -= 1
|
current_height -= 1
|
||||||
|
|
||||||
@ -419,7 +428,7 @@ class NAVInterface(BTCInterface):
|
|||||||
|
|
||||||
return_txid = True if txid is None else False
|
return_txid = True if txid is None else False
|
||||||
if txid is None:
|
if txid is None:
|
||||||
txns = self.rpc_callback('listunspent', [0, 9999999, [dest_address, ]])
|
txns = self.rpc('listunspent', [0, 9999999, [dest_address, ]])
|
||||||
|
|
||||||
for tx in txns:
|
for tx in txns:
|
||||||
if self.make_int(tx['amount']) == bid_amount:
|
if self.make_int(tx['amount']) == bid_amount:
|
||||||
@ -430,11 +439,11 @@ class NAVInterface(BTCInterface):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
tx = self.rpc_callback('gettransaction', [txid.hex()])
|
tx = self.rpc('gettransaction', [txid.hex()])
|
||||||
|
|
||||||
block_height = 0
|
block_height = 0
|
||||||
if 'blockhash' in tx:
|
if 'blockhash' in tx:
|
||||||
block_header = self.rpc_callback('getblockheader', [tx['blockhash']])
|
block_header = self.rpc('getblockheader', [tx['blockhash']])
|
||||||
block_height = block_header['height']
|
block_height = block_header['height']
|
||||||
|
|
||||||
rv = {
|
rv = {
|
||||||
@ -446,7 +455,7 @@ class NAVInterface(BTCInterface):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
if find_index:
|
if find_index:
|
||||||
tx_obj = self.rpc_callback('decoderawtransaction', [tx['hex']])
|
tx_obj = self.rpc('decoderawtransaction', [tx['hex']])
|
||||||
rv['index'] = find_vout_for_address_from_txobj(tx_obj, dest_address)
|
rv['index'] = find_vout_for_address_from_txobj(tx_obj, dest_address)
|
||||||
|
|
||||||
if return_txid:
|
if return_txid:
|
||||||
@ -456,15 +465,15 @@ class NAVInterface(BTCInterface):
|
|||||||
|
|
||||||
def getBlockWithTxns(self, block_hash):
|
def getBlockWithTxns(self, block_hash):
|
||||||
# TODO: Bypass decoderawtransaction and getblockheader
|
# TODO: Bypass decoderawtransaction and getblockheader
|
||||||
block = self.rpc_callback('getblock', [block_hash, False])
|
block = self.rpc('getblock', [block_hash, False])
|
||||||
block_header = self.rpc_callback('getblockheader', [block_hash])
|
block_header = self.rpc('getblockheader', [block_hash])
|
||||||
decoded_block = CBlock()
|
decoded_block = CBlock()
|
||||||
decoded_block = FromHex(decoded_block, block)
|
decoded_block = FromHex(decoded_block, block)
|
||||||
|
|
||||||
tx_rv = []
|
tx_rv = []
|
||||||
for tx in decoded_block.vtx:
|
for tx in decoded_block.vtx:
|
||||||
tx_hex = tx.serialize_with_witness().hex()
|
tx_hex = tx.serialize_with_witness().hex()
|
||||||
tx_dec = self.rpc_callback('decoderawtransaction', [tx_hex])
|
tx_dec = self.rpc('decoderawtransaction', [tx_hex])
|
||||||
if 'hex' not in tx_dec:
|
if 'hex' not in tx_dec:
|
||||||
tx_dec['hex'] = tx_hex
|
tx_dec['hex'] = tx_hex
|
||||||
|
|
||||||
@ -505,7 +514,7 @@ class NAVInterface(BTCInterface):
|
|||||||
|
|
||||||
def spendBLockTx(self, chain_b_lock_txid: bytes, address_to: str, kbv: bytes, kbs: bytes, cb_swap_value: int, b_fee: int, restore_height: int) -> bytes:
|
def spendBLockTx(self, chain_b_lock_txid: bytes, address_to: str, kbv: bytes, kbs: bytes, cb_swap_value: int, b_fee: int, restore_height: int) -> bytes:
|
||||||
self._log.info('spendBLockTx %s:\n', chain_b_lock_txid.hex())
|
self._log.info('spendBLockTx %s:\n', chain_b_lock_txid.hex())
|
||||||
wtx = self.rpc_callback('gettransaction', [chain_b_lock_txid.hex(), ])
|
wtx = self.rpc('gettransaction', [chain_b_lock_txid.hex(), ])
|
||||||
lock_tx = self.loadTx(bytes.fromhex(wtx['hex']))
|
lock_tx = self.loadTx(bytes.fromhex(wtx['hex']))
|
||||||
|
|
||||||
Kbs = self.getPubkey(kbs)
|
Kbs = self.getPubkey(kbs)
|
||||||
@ -550,7 +559,7 @@ class NAVInterface(BTCInterface):
|
|||||||
def findTxnByHash(self, txid_hex: str):
|
def findTxnByHash(self, txid_hex: str):
|
||||||
# Only works for wallet txns
|
# Only works for wallet txns
|
||||||
try:
|
try:
|
||||||
rv = self.rpc_callback('gettransaction', [txid_hex])
|
rv = self.rpc('gettransaction', [txid_hex])
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
self._log.debug('findTxnByHash getrawtransaction failed: {}'.format(txid_hex))
|
self._log.debug('findTxnByHash getrawtransaction failed: {}'.format(txid_hex))
|
||||||
return None
|
return None
|
||||||
@ -573,10 +582,10 @@ class NAVInterface(BTCInterface):
|
|||||||
'lockUnspents': lock_unspents,
|
'lockUnspents': lock_unspents,
|
||||||
'feeRate': feerate_str,
|
'feeRate': feerate_str,
|
||||||
}
|
}
|
||||||
rv = self.rpc_callback('fundrawtransaction', [tx_hex, options])
|
rv = self.rpc('fundrawtransaction', [tx_hex, options])
|
||||||
|
|
||||||
# Sign transaction then strip witness data to fill scriptsig
|
# Sign transaction then strip witness data to fill scriptsig
|
||||||
rv = self.rpc_callback('signrawtransaction', [rv['hex']])
|
rv = self.rpc('signrawtransaction', [rv['hex']])
|
||||||
|
|
||||||
tx_signed = self.loadTx(bytes.fromhex(rv['hex']))
|
tx_signed = self.loadTx(bytes.fromhex(rv['hex']))
|
||||||
if len(tx_signed.vin) != len(tx_signed.wit.vtxinwit):
|
if len(tx_signed.vin) != len(tx_signed.wit.vtxinwit):
|
||||||
|
@ -19,7 +19,7 @@ class NMCInterface(BTCInterface):
|
|||||||
|
|
||||||
def getLockTxHeight(self, txid, dest_address, bid_amount, rescan_from, find_index=False):
|
def getLockTxHeight(self, txid, dest_address, bid_amount, rescan_from, find_index=False):
|
||||||
self._log.debug('[rm] scantxoutset start') # scantxoutset is slow
|
self._log.debug('[rm] scantxoutset start') # scantxoutset is slow
|
||||||
ro = self.rpc_callback('scantxoutset', ['start', ['addr({})'.format(dest_address)]]) # TODO: Use combo(address) where possible
|
ro = self.rpc('scantxoutset', ['start', ['addr({})'.format(dest_address)]]) # TODO: Use combo(address) where possible
|
||||||
self._log.debug('[rm] scantxoutset end')
|
self._log.debug('[rm] scantxoutset end')
|
||||||
return_txid = True if txid is None else False
|
return_txid = True if txid is None else False
|
||||||
for o in ro['unspents']:
|
for o in ro['unspents']:
|
||||||
|
@ -83,14 +83,14 @@ class PARTInterface(BTCInterface):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def getNewAddress(self, use_segwit, label='swap_receive') -> str:
|
def getNewAddress(self, use_segwit, label='swap_receive') -> str:
|
||||||
return self.rpc_callback('getnewaddress', [label])
|
return self.rpc_wallet('getnewaddress', [label])
|
||||||
|
|
||||||
def getNewStealthAddress(self, label='swap_stealth') -> str:
|
def getNewStealthAddress(self, label='swap_stealth') -> str:
|
||||||
return self.rpc_callback('getnewstealthaddress', [label])
|
return self.rpc_wallet('getnewstealthaddress', [label])
|
||||||
|
|
||||||
def haveSpentIndex(self):
|
def haveSpentIndex(self):
|
||||||
version = self.getDaemonVersion()
|
version = self.getDaemonVersion()
|
||||||
index_info = self.rpc_callback('getinsightinfo' if int(str(version)[:2]) > 19 else 'getindexinfo')
|
index_info = self.rpc('getinsightinfo' if int(str(version)[:2]) > 19 else 'getindexinfo')
|
||||||
return index_info['spentindex']
|
return index_info['spentindex']
|
||||||
|
|
||||||
def initialiseWallet(self, key):
|
def initialiseWallet(self, key):
|
||||||
@ -98,14 +98,14 @@ class PARTInterface(BTCInterface):
|
|||||||
|
|
||||||
def withdrawCoin(self, value, addr_to, subfee):
|
def withdrawCoin(self, value, addr_to, subfee):
|
||||||
params = [addr_to, value, '', '', subfee, '', True, self._conf_target]
|
params = [addr_to, value, '', '', subfee, '', True, self._conf_target]
|
||||||
return self.rpc_callback('sendtoaddress', params)
|
return self.rpc_wallet('sendtoaddress', params)
|
||||||
|
|
||||||
def sendTypeTo(self, type_from, type_to, value, addr_to, subfee):
|
def sendTypeTo(self, type_from, type_to, value, addr_to, subfee):
|
||||||
params = [type_from, type_to,
|
params = [type_from, type_to,
|
||||||
[{'address': addr_to, 'amount': value, 'subfee': subfee}, ],
|
[{'address': addr_to, 'amount': value, 'subfee': subfee}, ],
|
||||||
'', '', self._anon_tx_ring_size, 1, False,
|
'', '', self._anon_tx_ring_size, 1, False,
|
||||||
{'conf_target': self._conf_target}]
|
{'conf_target': self._conf_target}]
|
||||||
return self.rpc_callback('sendtypeto', params)
|
return self.rpc_wallet('sendtypeto', params)
|
||||||
|
|
||||||
def getScriptForPubkeyHash(self, pkh: bytes) -> CScript:
|
def getScriptForPubkeyHash(self, pkh: bytes) -> CScript:
|
||||||
return CScript([OP_DUP, OP_HASH160, pkh, OP_EQUALVERIFY, OP_CHECKSIG])
|
return CScript([OP_DUP, OP_HASH160, pkh, OP_EQUALVERIFY, OP_CHECKSIG])
|
||||||
@ -122,7 +122,7 @@ class PARTInterface(BTCInterface):
|
|||||||
return length
|
return length
|
||||||
|
|
||||||
def getWalletRestoreHeight(self) -> int:
|
def getWalletRestoreHeight(self) -> int:
|
||||||
start_time = self.rpc_callback('getwalletinfo')['keypoololdest']
|
start_time = self.rpc_wallet('getwalletinfo')['keypoololdest']
|
||||||
|
|
||||||
blockchaininfo = self.getBlockchainInfo()
|
blockchaininfo = self.getBlockchainInfo()
|
||||||
best_block = blockchaininfo['bestblockhash']
|
best_block = blockchaininfo['bestblockhash']
|
||||||
@ -132,8 +132,8 @@ class PARTInterface(BTCInterface):
|
|||||||
raise ValueError('{} chain isn\'t synced.'.format(self.coin_name()))
|
raise ValueError('{} chain isn\'t synced.'.format(self.coin_name()))
|
||||||
|
|
||||||
self._log.debug('Finding block at time: {}'.format(start_time))
|
self._log.debug('Finding block at time: {}'.format(start_time))
|
||||||
block_hash = self.rpc_callback('getblockhashafter', [start_time])
|
block_hash = self.rpc('getblockhashafter', [start_time])
|
||||||
block_header = self.rpc_callback('getblockheader', [block_hash])
|
block_header = self.rpc('getblockheader', [block_hash])
|
||||||
return block_header['height']
|
return block_header['height']
|
||||||
|
|
||||||
def getHTLCSpendTxVSize(self, redeem: bool = True) -> int:
|
def getHTLCSpendTxVSize(self, redeem: bool = True) -> int:
|
||||||
@ -171,16 +171,16 @@ class PARTInterfaceBlind(PARTInterface):
|
|||||||
if txo['type'] != 'blind':
|
if txo['type'] != 'blind':
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
blinded_info = self.rpc_callback('rewindrangeproof', [txo['rangeproof'], txo['valueCommitment'], nonce.hex()])
|
blinded_info = self.rpc('rewindrangeproof', [txo['rangeproof'], txo['valueCommitment'], nonce.hex()])
|
||||||
output_n = txo['n']
|
output_n = txo['n']
|
||||||
|
|
||||||
self.rpc_callback('rewindrangeproof', [txo['rangeproof'], txo['valueCommitment'], nonce.hex()])
|
self.rpc('rewindrangeproof', [txo['rangeproof'], txo['valueCommitment'], nonce.hex()])
|
||||||
break
|
break
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self._log.debug('Searching for locked output: {}'.format(str(e)))
|
self._log.debug('Searching for locked output: {}'.format(str(e)))
|
||||||
continue
|
continue
|
||||||
# Should not be possible for commitment not to match
|
# Should not be possible for commitment not to match
|
||||||
v = self.rpc_callback('verifycommitment', [txo['valueCommitment'], blinded_info['blind'], blinded_info['amount']])
|
v = self.rpc('verifycommitment', [txo['valueCommitment'], blinded_info['blind'], blinded_info['amount']])
|
||||||
ensure(v['result'] is True, 'verifycommitment failed')
|
ensure(v['result'] is True, 'verifycommitment failed')
|
||||||
return output_n, blinded_info
|
return output_n, blinded_info
|
||||||
|
|
||||||
@ -195,7 +195,7 @@ class PARTInterfaceBlind(PARTInterface):
|
|||||||
inputs = []
|
inputs = []
|
||||||
outputs = [{'type': 'blind', 'amount': self.format_amount(value), 'address': p2wsh_addr, 'nonce': nonce.hex(), 'data': ephemeral_pubkey.hex()}]
|
outputs = [{'type': 'blind', 'amount': self.format_amount(value), 'address': p2wsh_addr, 'nonce': nonce.hex(), 'data': ephemeral_pubkey.hex()}]
|
||||||
params = [inputs, outputs]
|
params = [inputs, outputs]
|
||||||
rv = self.rpc_callback('createrawparttransaction', params)
|
rv = self.rpc_wallet('createrawparttransaction', params)
|
||||||
|
|
||||||
tx_bytes = bytes.fromhex(rv['hex'])
|
tx_bytes = bytes.fromhex(rv['hex'])
|
||||||
return tx_bytes
|
return tx_bytes
|
||||||
@ -207,11 +207,11 @@ class PARTInterfaceBlind(PARTInterface):
|
|||||||
tx_hex = tx_bytes.hex()
|
tx_hex = tx_bytes.hex()
|
||||||
nonce = self.getScriptLockTxNonce(vkbv)
|
nonce = self.getScriptLockTxNonce(vkbv)
|
||||||
|
|
||||||
tx_obj = self.rpc_callback('decoderawtransaction', [tx_hex])
|
tx_obj = self.rpc('decoderawtransaction', [tx_hex])
|
||||||
|
|
||||||
assert (len(tx_obj['vout']) == 1)
|
assert (len(tx_obj['vout']) == 1)
|
||||||
txo = tx_obj['vout'][0]
|
txo = tx_obj['vout'][0]
|
||||||
blinded_info = self.rpc_callback('rewindrangeproof', [txo['rangeproof'], txo['valueCommitment'], nonce.hex()])
|
blinded_info = self.rpc('rewindrangeproof', [txo['rangeproof'], txo['valueCommitment'], nonce.hex()])
|
||||||
|
|
||||||
outputs_info = {0: {'value': blinded_info['amount'], 'blind': blinded_info['blind'], 'nonce': nonce.hex()}}
|
outputs_info = {0: {'value': blinded_info['amount'], 'blind': blinded_info['blind'], 'nonce': nonce.hex()}}
|
||||||
|
|
||||||
@ -219,11 +219,11 @@ class PARTInterfaceBlind(PARTInterface):
|
|||||||
'lockUnspents': True,
|
'lockUnspents': True,
|
||||||
'feeRate': feerate_str,
|
'feeRate': feerate_str,
|
||||||
}
|
}
|
||||||
rv = self.rpc_callback('fundrawtransactionfrom', ['blind', tx_hex, {}, outputs_info, options])
|
rv = self.rpc('fundrawtransactionfrom', ['blind', tx_hex, {}, outputs_info, options])
|
||||||
return bytes.fromhex(rv['hex'])
|
return bytes.fromhex(rv['hex'])
|
||||||
|
|
||||||
def createSCLockRefundTx(self, tx_lock_bytes, script_lock, Kal, Kaf, lock1_value, csv_val, tx_fee_rate, vkbv):
|
def createSCLockRefundTx(self, tx_lock_bytes, script_lock, Kal, Kaf, lock1_value, csv_val, tx_fee_rate, vkbv):
|
||||||
lock_tx_obj = self.rpc_callback('decoderawtransaction', [tx_lock_bytes.hex()])
|
lock_tx_obj = self.rpc('decoderawtransaction', [tx_lock_bytes.hex()])
|
||||||
assert (self.getTxid(tx_lock_bytes).hex() == lock_tx_obj['txid'])
|
assert (self.getTxid(tx_lock_bytes).hex() == lock_tx_obj['txid'])
|
||||||
# Nonce is derived from vkbv, ephemeral_key isn't used
|
# Nonce is derived from vkbv, ephemeral_key isn't used
|
||||||
ephemeral_key = self.getNewSecretKey()
|
ephemeral_key = self.getNewSecretKey()
|
||||||
@ -244,7 +244,7 @@ class PARTInterfaceBlind(PARTInterface):
|
|||||||
inputs = [{'txid': tx_lock_id, 'vout': spend_n, 'sequence': lock1_value, 'blindingfactor': input_blinded_info['blind']}]
|
inputs = [{'txid': tx_lock_id, 'vout': spend_n, 'sequence': lock1_value, 'blindingfactor': input_blinded_info['blind']}]
|
||||||
outputs = [{'type': 'blind', 'amount': locked_coin, 'address': p2wsh_addr, 'nonce': output_nonce.hex(), 'data': ephemeral_pubkey.hex()}]
|
outputs = [{'type': 'blind', 'amount': locked_coin, 'address': p2wsh_addr, 'nonce': output_nonce.hex(), 'data': ephemeral_pubkey.hex()}]
|
||||||
params = [inputs, outputs]
|
params = [inputs, outputs]
|
||||||
rv = self.rpc_callback('createrawparttransaction', params)
|
rv = self.rpc_wallet('createrawparttransaction', params)
|
||||||
lock_refund_tx_hex = rv['hex']
|
lock_refund_tx_hex = rv['hex']
|
||||||
|
|
||||||
# Set dummy witness data for fee estimation
|
# Set dummy witness data for fee estimation
|
||||||
@ -261,7 +261,7 @@ class PARTInterfaceBlind(PARTInterface):
|
|||||||
'feeRate': self.format_amount(tx_fee_rate),
|
'feeRate': self.format_amount(tx_fee_rate),
|
||||||
'subtractFeeFromOutputs': [0, ]
|
'subtractFeeFromOutputs': [0, ]
|
||||||
}
|
}
|
||||||
rv = self.rpc_callback('fundrawtransactionfrom', ['blind', lock_refund_tx_hex, inputs_info, outputs_info, options])
|
rv = self.rpc_wallet('fundrawtransactionfrom', ['blind', lock_refund_tx_hex, inputs_info, outputs_info, options])
|
||||||
lock_refund_tx_hex = rv['hex']
|
lock_refund_tx_hex = rv['hex']
|
||||||
|
|
||||||
for vout, txo in rv['output_amounts'].items():
|
for vout, txo in rv['output_amounts'].items():
|
||||||
@ -275,7 +275,7 @@ class PARTInterfaceBlind(PARTInterface):
|
|||||||
# The follower will sign the multisig path with a signature encumbered by the leader's coinB spend pubkey
|
# The follower will sign the multisig path with a signature encumbered by the leader's coinB spend pubkey
|
||||||
# If the leader publishes the decrypted signature the leader's coinB spend privatekey will be revealed to the follower
|
# If the leader publishes the decrypted signature the leader's coinB spend privatekey will be revealed to the follower
|
||||||
|
|
||||||
lock_refund_tx_obj = self.rpc_callback('decoderawtransaction', [tx_lock_refund_bytes.hex()])
|
lock_refund_tx_obj = self.rpc('decoderawtransaction', [tx_lock_refund_bytes.hex()])
|
||||||
# Nonce is derived from vkbv
|
# Nonce is derived from vkbv
|
||||||
nonce = self.getScriptLockRefundTxNonce(vkbv)
|
nonce = self.getScriptLockRefundTxNonce(vkbv)
|
||||||
|
|
||||||
@ -285,7 +285,7 @@ class PARTInterfaceBlind(PARTInterface):
|
|||||||
|
|
||||||
tx_lock_refund_id = lock_refund_tx_obj['txid']
|
tx_lock_refund_id = lock_refund_tx_obj['txid']
|
||||||
addr_out = self.pkh_to_address(pkh_refund_to)
|
addr_out = self.pkh_to_address(pkh_refund_to)
|
||||||
addr_info = self.rpc_callback('getaddressinfo', [addr_out])
|
addr_info = self.rpc_wallet('getaddressinfo', [addr_out])
|
||||||
output_pubkey_hex = addr_info['pubkey']
|
output_pubkey_hex = addr_info['pubkey']
|
||||||
|
|
||||||
# Follower won't be able to decode output to check amount, shouldn't matter as fee is public and output is to leader, sum has to balance
|
# Follower won't be able to decode output to check amount, shouldn't matter as fee is public and output is to leader, sum has to balance
|
||||||
@ -293,7 +293,7 @@ class PARTInterfaceBlind(PARTInterface):
|
|||||||
inputs = [{'txid': tx_lock_refund_id, 'vout': spend_n, 'sequence': 0, 'blindingfactor': input_blinded_info['blind']}]
|
inputs = [{'txid': tx_lock_refund_id, 'vout': spend_n, 'sequence': 0, 'blindingfactor': input_blinded_info['blind']}]
|
||||||
outputs = [{'type': 'blind', 'amount': input_blinded_info['amount'], 'address': addr_out, 'pubkey': output_pubkey_hex}]
|
outputs = [{'type': 'blind', 'amount': input_blinded_info['amount'], 'address': addr_out, 'pubkey': output_pubkey_hex}]
|
||||||
params = [inputs, outputs]
|
params = [inputs, outputs]
|
||||||
rv = self.rpc_callback('createrawparttransaction', params)
|
rv = self.rpc_wallet('createrawparttransaction', params)
|
||||||
lock_refund_spend_tx_hex = rv['hex']
|
lock_refund_spend_tx_hex = rv['hex']
|
||||||
|
|
||||||
# Set dummy witness data for fee estimation
|
# Set dummy witness data for fee estimation
|
||||||
@ -311,7 +311,7 @@ class PARTInterfaceBlind(PARTInterface):
|
|||||||
'subtractFeeFromOutputs': [0, ]
|
'subtractFeeFromOutputs': [0, ]
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = self.rpc_callback('fundrawtransactionfrom', ['blind', lock_refund_spend_tx_hex, inputs_info, outputs_info, options])
|
rv = self.rpc_wallet('fundrawtransactionfrom', ['blind', lock_refund_spend_tx_hex, inputs_info, outputs_info, options])
|
||||||
lock_refund_spend_tx_hex = rv['hex']
|
lock_refund_spend_tx_hex = rv['hex']
|
||||||
|
|
||||||
return bytes.fromhex(lock_refund_spend_tx_hex)
|
return bytes.fromhex(lock_refund_spend_tx_hex)
|
||||||
@ -321,7 +321,7 @@ class PARTInterfaceBlind(PARTInterface):
|
|||||||
Kal, Kaf,
|
Kal, Kaf,
|
||||||
feerate,
|
feerate,
|
||||||
check_lock_tx_inputs, vkbv):
|
check_lock_tx_inputs, vkbv):
|
||||||
lock_tx_obj = self.rpc_callback('decoderawtransaction', [tx_bytes.hex()])
|
lock_tx_obj = self.rpc('decoderawtransaction', [tx_bytes.hex()])
|
||||||
lock_txid_hex = lock_tx_obj['txid']
|
lock_txid_hex = lock_tx_obj['txid']
|
||||||
self._log.info('Verifying lock tx: {}.'.format(lock_txid_hex))
|
self._log.info('Verifying lock tx: {}.'.format(lock_txid_hex))
|
||||||
|
|
||||||
@ -363,7 +363,7 @@ class PARTInterfaceBlind(PARTInterface):
|
|||||||
def verifySCLockRefundTx(self, tx_bytes, lock_tx_bytes, script_out,
|
def verifySCLockRefundTx(self, tx_bytes, lock_tx_bytes, script_out,
|
||||||
prevout_id, prevout_n, prevout_seq, prevout_script,
|
prevout_id, prevout_n, prevout_seq, prevout_script,
|
||||||
Kal, Kaf, csv_val_expect, swap_value, feerate, vkbv):
|
Kal, Kaf, csv_val_expect, swap_value, feerate, vkbv):
|
||||||
lock_refund_tx_obj = self.rpc_callback('decoderawtransaction', [tx_bytes.hex()])
|
lock_refund_tx_obj = self.rpc('decoderawtransaction', [tx_bytes.hex()])
|
||||||
lock_refund_txid_hex = lock_refund_tx_obj['txid']
|
lock_refund_txid_hex = lock_refund_tx_obj['txid']
|
||||||
self._log.info('Verifying lock refund tx: {}.'.format(lock_refund_txid_hex))
|
self._log.info('Verifying lock refund tx: {}.'.format(lock_refund_txid_hex))
|
||||||
|
|
||||||
@ -396,10 +396,10 @@ class PARTInterfaceBlind(PARTInterface):
|
|||||||
ensure(C == Kaf, 'Bad script pubkey')
|
ensure(C == Kaf, 'Bad script pubkey')
|
||||||
|
|
||||||
# Check rangeproofs and commitments sum
|
# Check rangeproofs and commitments sum
|
||||||
lock_tx_obj = self.rpc_callback('decoderawtransaction', [lock_tx_bytes.hex()])
|
lock_tx_obj = self.rpc('decoderawtransaction', [lock_tx_bytes.hex()])
|
||||||
prevout = lock_tx_obj['vout'][prevout_n]
|
prevout = lock_tx_obj['vout'][prevout_n]
|
||||||
prevtxns = [{'txid': prevout_id.hex(), 'vout': prevout_n, 'scriptPubKey': prevout['scriptPubKey']['hex'], 'amount_commitment': prevout['valueCommitment']}]
|
prevtxns = [{'txid': prevout_id.hex(), 'vout': prevout_n, 'scriptPubKey': prevout['scriptPubKey']['hex'], 'amount_commitment': prevout['valueCommitment']}]
|
||||||
rv = self.rpc_callback('verifyrawtransaction', [tx_bytes.hex(), prevtxns])
|
rv = self.rpc('verifyrawtransaction', [tx_bytes.hex(), prevtxns])
|
||||||
ensure(rv['outputs_valid'] is True, 'Invalid outputs')
|
ensure(rv['outputs_valid'] is True, 'Invalid outputs')
|
||||||
ensure(rv['inputs_valid'] is True, 'Invalid inputs')
|
ensure(rv['inputs_valid'] is True, 'Invalid inputs')
|
||||||
|
|
||||||
@ -422,7 +422,7 @@ class PARTInterfaceBlind(PARTInterface):
|
|||||||
lock_refund_tx_id, prevout_script,
|
lock_refund_tx_id, prevout_script,
|
||||||
Kal,
|
Kal,
|
||||||
prevout_n, prevout_value, feerate, vkbv):
|
prevout_n, prevout_value, feerate, vkbv):
|
||||||
lock_refund_spend_tx_obj = self.rpc_callback('decoderawtransaction', [tx_bytes.hex()])
|
lock_refund_spend_tx_obj = self.rpc('decoderawtransaction', [tx_bytes.hex()])
|
||||||
lock_refund_spend_txid_hex = lock_refund_spend_tx_obj['txid']
|
lock_refund_spend_txid_hex = lock_refund_spend_tx_obj['txid']
|
||||||
self._log.info('Verifying lock refund spend tx: {}.'.format(lock_refund_spend_txid_hex))
|
self._log.info('Verifying lock refund spend tx: {}.'.format(lock_refund_spend_txid_hex))
|
||||||
|
|
||||||
@ -441,10 +441,10 @@ class PARTInterfaceBlind(PARTInterface):
|
|||||||
# Follower is not concerned with them as they pay to leader
|
# Follower is not concerned with them as they pay to leader
|
||||||
|
|
||||||
# Check rangeproofs and commitments sum
|
# Check rangeproofs and commitments sum
|
||||||
lock_refund_tx_obj = self.rpc_callback('decoderawtransaction', [lock_refund_tx_bytes.hex()])
|
lock_refund_tx_obj = self.rpc('decoderawtransaction', [lock_refund_tx_bytes.hex()])
|
||||||
prevout = lock_refund_tx_obj['vout'][prevout_n]
|
prevout = lock_refund_tx_obj['vout'][prevout_n]
|
||||||
prevtxns = [{'txid': lock_refund_tx_id.hex(), 'vout': prevout_n, 'scriptPubKey': prevout['scriptPubKey']['hex'], 'amount_commitment': prevout['valueCommitment']}]
|
prevtxns = [{'txid': lock_refund_tx_id.hex(), 'vout': prevout_n, 'scriptPubKey': prevout['scriptPubKey']['hex'], 'amount_commitment': prevout['valueCommitment']}]
|
||||||
rv = self.rpc_callback('verifyrawtransaction', [tx_bytes.hex(), prevtxns])
|
rv = self.rpc('verifyrawtransaction', [tx_bytes.hex(), prevtxns])
|
||||||
ensure(rv['outputs_valid'] is True, 'Invalid outputs')
|
ensure(rv['outputs_valid'] is True, 'Invalid outputs')
|
||||||
ensure(rv['inputs_valid'] is True, 'Invalid inputs')
|
ensure(rv['inputs_valid'] is True, 'Invalid inputs')
|
||||||
|
|
||||||
@ -459,28 +459,28 @@ class PARTInterfaceBlind(PARTInterface):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def getLockTxSwapOutputValue(self, bid, xmr_swap):
|
def getLockTxSwapOutputValue(self, bid, xmr_swap):
|
||||||
lock_tx_obj = self.rpc_callback('decoderawtransaction', [xmr_swap.a_lock_tx.hex()])
|
lock_tx_obj = self.rpc('decoderawtransaction', [xmr_swap.a_lock_tx.hex()])
|
||||||
nonce = self.getScriptLockTxNonce(xmr_swap.vkbv)
|
nonce = self.getScriptLockTxNonce(xmr_swap.vkbv)
|
||||||
output_n, _ = self.findOutputByNonce(lock_tx_obj, nonce)
|
output_n, _ = self.findOutputByNonce(lock_tx_obj, nonce)
|
||||||
ensure(output_n is not None, 'Output not found in tx')
|
ensure(output_n is not None, 'Output not found in tx')
|
||||||
return bytes.fromhex(lock_tx_obj['vout'][output_n]['valueCommitment'])
|
return bytes.fromhex(lock_tx_obj['vout'][output_n]['valueCommitment'])
|
||||||
|
|
||||||
def getLockRefundTxSwapOutputValue(self, bid, xmr_swap):
|
def getLockRefundTxSwapOutputValue(self, bid, xmr_swap):
|
||||||
lock_refund_tx_obj = self.rpc_callback('decoderawtransaction', [xmr_swap.a_lock_refund_tx.hex()])
|
lock_refund_tx_obj = self.rpc('decoderawtransaction', [xmr_swap.a_lock_refund_tx.hex()])
|
||||||
nonce = self.getScriptLockRefundTxNonce(xmr_swap.vkbv)
|
nonce = self.getScriptLockRefundTxNonce(xmr_swap.vkbv)
|
||||||
output_n, _ = self.findOutputByNonce(lock_refund_tx_obj, nonce)
|
output_n, _ = self.findOutputByNonce(lock_refund_tx_obj, nonce)
|
||||||
ensure(output_n is not None, 'Output not found in tx')
|
ensure(output_n is not None, 'Output not found in tx')
|
||||||
return bytes.fromhex(lock_refund_tx_obj['vout'][output_n]['valueCommitment'])
|
return bytes.fromhex(lock_refund_tx_obj['vout'][output_n]['valueCommitment'])
|
||||||
|
|
||||||
def getLockRefundTxSwapOutput(self, xmr_swap):
|
def getLockRefundTxSwapOutput(self, xmr_swap):
|
||||||
lock_refund_tx_obj = self.rpc_callback('decoderawtransaction', [xmr_swap.a_lock_refund_tx.hex()])
|
lock_refund_tx_obj = self.rpc('decoderawtransaction', [xmr_swap.a_lock_refund_tx.hex()])
|
||||||
nonce = self.getScriptLockRefundTxNonce(xmr_swap.vkbv)
|
nonce = self.getScriptLockRefundTxNonce(xmr_swap.vkbv)
|
||||||
output_n, _ = self.findOutputByNonce(lock_refund_tx_obj, nonce)
|
output_n, _ = self.findOutputByNonce(lock_refund_tx_obj, nonce)
|
||||||
ensure(output_n is not None, 'Output not found in tx')
|
ensure(output_n is not None, 'Output not found in tx')
|
||||||
return output_n
|
return output_n
|
||||||
|
|
||||||
def createSCLockSpendTx(self, tx_lock_bytes: bytes, script_lock: bytes, pk_dest: bytes, tx_fee_rate: int, vkbv: bytes, fee_info={}) -> bytes:
|
def createSCLockSpendTx(self, tx_lock_bytes: bytes, script_lock: bytes, pk_dest: bytes, tx_fee_rate: int, vkbv: bytes, fee_info={}) -> bytes:
|
||||||
lock_tx_obj = self.rpc_callback('decoderawtransaction', [tx_lock_bytes.hex()])
|
lock_tx_obj = self.rpc('decoderawtransaction', [tx_lock_bytes.hex()])
|
||||||
lock_txid_hex = lock_tx_obj['txid']
|
lock_txid_hex = lock_tx_obj['txid']
|
||||||
|
|
||||||
ensure(lock_tx_obj['version'] == self.txVersion(), 'Bad version')
|
ensure(lock_tx_obj['version'] == self.txVersion(), 'Bad version')
|
||||||
@ -496,7 +496,7 @@ class PARTInterfaceBlind(PARTInterface):
|
|||||||
inputs = [{'txid': lock_txid_hex, 'vout': spend_n, 'sequence': 0, 'blindingfactor': blinded_info['blind']}]
|
inputs = [{'txid': lock_txid_hex, 'vout': spend_n, 'sequence': 0, 'blindingfactor': blinded_info['blind']}]
|
||||||
outputs = [{'type': 'blind', 'amount': blinded_info['amount'], 'address': addr_out, 'pubkey': pk_dest.hex()}]
|
outputs = [{'type': 'blind', 'amount': blinded_info['amount'], 'address': addr_out, 'pubkey': pk_dest.hex()}]
|
||||||
params = [inputs, outputs]
|
params = [inputs, outputs]
|
||||||
rv = self.rpc_callback('createrawparttransaction', params)
|
rv = self.rpc_wallet('createrawparttransaction', params)
|
||||||
lock_spend_tx_hex = rv['hex']
|
lock_spend_tx_hex = rv['hex']
|
||||||
|
|
||||||
# Set dummy witness data for fee estimation
|
# Set dummy witness data for fee estimation
|
||||||
@ -513,9 +513,9 @@ class PARTInterfaceBlind(PARTInterface):
|
|||||||
'subtractFeeFromOutputs': [0, ]
|
'subtractFeeFromOutputs': [0, ]
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = self.rpc_callback('fundrawtransactionfrom', ['blind', lock_spend_tx_hex, inputs_info, outputs_info, options])
|
rv = self.rpc_wallet('fundrawtransactionfrom', ['blind', lock_spend_tx_hex, inputs_info, outputs_info, options])
|
||||||
lock_spend_tx_hex = rv['hex']
|
lock_spend_tx_hex = rv['hex']
|
||||||
lock_spend_tx_obj = self.rpc_callback('decoderawtransaction', [lock_spend_tx_hex])
|
lock_spend_tx_obj = self.rpc('decoderawtransaction', [lock_spend_tx_hex])
|
||||||
pay_fee = make_int(lock_spend_tx_obj['vout'][0]['ct_fee'])
|
pay_fee = make_int(lock_spend_tx_obj['vout'][0]['ct_fee'])
|
||||||
|
|
||||||
# lock_spend_tx_hex does not include the dummy witness stack
|
# lock_spend_tx_hex does not include the dummy witness stack
|
||||||
@ -535,7 +535,7 @@ class PARTInterfaceBlind(PARTInterface):
|
|||||||
def verifySCLockSpendTx(self, tx_bytes,
|
def verifySCLockSpendTx(self, tx_bytes,
|
||||||
lock_tx_bytes, lock_tx_script,
|
lock_tx_bytes, lock_tx_script,
|
||||||
a_pk_f, feerate, vkbv):
|
a_pk_f, feerate, vkbv):
|
||||||
lock_spend_tx_obj = self.rpc_callback('decoderawtransaction', [tx_bytes.hex()])
|
lock_spend_tx_obj = self.rpc('decoderawtransaction', [tx_bytes.hex()])
|
||||||
lock_spend_txid_hex = lock_spend_tx_obj['txid']
|
lock_spend_txid_hex = lock_spend_tx_obj['txid']
|
||||||
self._log.info('Verifying lock spend tx: {}.'.format(lock_spend_txid_hex))
|
self._log.info('Verifying lock spend tx: {}.'.format(lock_spend_txid_hex))
|
||||||
|
|
||||||
@ -543,7 +543,7 @@ class PARTInterfaceBlind(PARTInterface):
|
|||||||
ensure(lock_spend_tx_obj['locktime'] == 0, 'Bad nLockTime')
|
ensure(lock_spend_tx_obj['locktime'] == 0, 'Bad nLockTime')
|
||||||
ensure(len(lock_spend_tx_obj['vin']) == 1, 'tx doesn\'t have one input')
|
ensure(len(lock_spend_tx_obj['vin']) == 1, 'tx doesn\'t have one input')
|
||||||
|
|
||||||
lock_tx_obj = self.rpc_callback('decoderawtransaction', [lock_tx_bytes.hex()])
|
lock_tx_obj = self.rpc('decoderawtransaction', [lock_tx_bytes.hex()])
|
||||||
lock_txid_hex = lock_tx_obj['txid']
|
lock_txid_hex = lock_tx_obj['txid']
|
||||||
|
|
||||||
# Find the output of the lock tx to verify
|
# Find the output of the lock tx to verify
|
||||||
@ -559,7 +559,7 @@ class PARTInterfaceBlind(PARTInterface):
|
|||||||
ensure(len(lock_spend_tx_obj['vout']) == 3, 'tx doesn\'t have three outputs')
|
ensure(len(lock_spend_tx_obj['vout']) == 3, 'tx doesn\'t have three outputs')
|
||||||
|
|
||||||
addr_out = self.pubkey_to_address(a_pk_f)
|
addr_out = self.pubkey_to_address(a_pk_f)
|
||||||
privkey = self.rpc_callback('dumpprivkey', [addr_out])
|
privkey = self.rpc_wallet('dumpprivkey', [addr_out])
|
||||||
|
|
||||||
# Find output:
|
# Find output:
|
||||||
output_blinded_info = None
|
output_blinded_info = None
|
||||||
@ -568,7 +568,7 @@ class PARTInterfaceBlind(PARTInterface):
|
|||||||
if txo['type'] != 'blind':
|
if txo['type'] != 'blind':
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
output_blinded_info = self.rpc_callback('rewindrangeproof', [txo['rangeproof'], txo['valueCommitment'], privkey, txo['data_hex']])
|
output_blinded_info = self.rpc('rewindrangeproof', [txo['rangeproof'], txo['valueCommitment'], privkey, txo['data_hex']])
|
||||||
output_n = txo['n']
|
output_n = txo['n']
|
||||||
break
|
break
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -577,13 +577,13 @@ class PARTInterfaceBlind(PARTInterface):
|
|||||||
ensure(output_n is not None, 'Output not found in tx')
|
ensure(output_n is not None, 'Output not found in tx')
|
||||||
|
|
||||||
# Commitment
|
# Commitment
|
||||||
v = self.rpc_callback('verifycommitment', [lock_spend_tx_obj['vout'][output_n]['valueCommitment'], output_blinded_info['blind'], output_blinded_info['amount']])
|
v = self.rpc('verifycommitment', [lock_spend_tx_obj['vout'][output_n]['valueCommitment'], output_blinded_info['blind'], output_blinded_info['amount']])
|
||||||
ensure(v['result'] is True, 'verifycommitment failed')
|
ensure(v['result'] is True, 'verifycommitment failed')
|
||||||
|
|
||||||
# Check rangeproofs and commitments sum
|
# Check rangeproofs and commitments sum
|
||||||
prevout = lock_tx_obj['vout'][spend_n]
|
prevout = lock_tx_obj['vout'][spend_n]
|
||||||
prevtxns = [{'txid': lock_txid_hex, 'vout': spend_n, 'scriptPubKey': prevout['scriptPubKey']['hex'], 'amount_commitment': prevout['valueCommitment']}]
|
prevtxns = [{'txid': lock_txid_hex, 'vout': spend_n, 'scriptPubKey': prevout['scriptPubKey']['hex'], 'amount_commitment': prevout['valueCommitment']}]
|
||||||
rv = self.rpc_callback('verifyrawtransaction', [tx_bytes.hex(), prevtxns])
|
rv = self.rpc('verifyrawtransaction', [tx_bytes.hex(), prevtxns])
|
||||||
ensure(rv['outputs_valid'] is True, 'Invalid outputs')
|
ensure(rv['outputs_valid'] is True, 'Invalid outputs')
|
||||||
ensure(rv['inputs_valid'] is True, 'Invalid inputs')
|
ensure(rv['inputs_valid'] is True, 'Invalid inputs')
|
||||||
|
|
||||||
@ -607,7 +607,7 @@ class PARTInterfaceBlind(PARTInterface):
|
|||||||
def createSCLockRefundSpendToFTx(self, tx_lock_refund_bytes, script_lock_refund, pkh_dest, tx_fee_rate, vkbv):
|
def createSCLockRefundSpendToFTx(self, tx_lock_refund_bytes, script_lock_refund, pkh_dest, tx_fee_rate, vkbv):
|
||||||
# lock refund swipe tx
|
# lock refund swipe tx
|
||||||
# Sends the coinA locked coin to the follower
|
# Sends the coinA locked coin to the follower
|
||||||
lock_refund_tx_obj = self.rpc_callback('decoderawtransaction', [tx_lock_refund_bytes.hex()])
|
lock_refund_tx_obj = self.rpc('decoderawtransaction', [tx_lock_refund_bytes.hex()])
|
||||||
nonce = self.getScriptLockRefundTxNonce(vkbv)
|
nonce = self.getScriptLockRefundTxNonce(vkbv)
|
||||||
|
|
||||||
# Find the output of the lock refund tx to spend
|
# Find the output of the lock refund tx to spend
|
||||||
@ -616,7 +616,7 @@ class PARTInterfaceBlind(PARTInterface):
|
|||||||
|
|
||||||
tx_lock_refund_id = lock_refund_tx_obj['txid']
|
tx_lock_refund_id = lock_refund_tx_obj['txid']
|
||||||
addr_out = self.pkh_to_address(pkh_dest)
|
addr_out = self.pkh_to_address(pkh_dest)
|
||||||
addr_info = self.rpc_callback('getaddressinfo', [addr_out])
|
addr_info = self.rpc_wallet('getaddressinfo', [addr_out])
|
||||||
output_pubkey_hex = addr_info['pubkey']
|
output_pubkey_hex = addr_info['pubkey']
|
||||||
|
|
||||||
A, B, lock2_value, C = self.extractScriptLockRefundScriptValues(script_lock_refund)
|
A, B, lock2_value, C = self.extractScriptLockRefundScriptValues(script_lock_refund)
|
||||||
@ -626,7 +626,7 @@ class PARTInterfaceBlind(PARTInterface):
|
|||||||
inputs = [{'txid': tx_lock_refund_id, 'vout': spend_n, 'sequence': lock2_value, 'blindingfactor': input_blinded_info['blind']}]
|
inputs = [{'txid': tx_lock_refund_id, 'vout': spend_n, 'sequence': lock2_value, 'blindingfactor': input_blinded_info['blind']}]
|
||||||
outputs = [{'type': 'blind', 'amount': input_blinded_info['amount'], 'address': addr_out, 'pubkey': output_pubkey_hex}]
|
outputs = [{'type': 'blind', 'amount': input_blinded_info['amount'], 'address': addr_out, 'pubkey': output_pubkey_hex}]
|
||||||
params = [inputs, outputs]
|
params = [inputs, outputs]
|
||||||
rv = self.rpc_callback('createrawparttransaction', params)
|
rv = self.rpc_wallet('createrawparttransaction', params)
|
||||||
|
|
||||||
lock_refund_swipe_tx_hex = rv['hex']
|
lock_refund_swipe_tx_hex = rv['hex']
|
||||||
|
|
||||||
@ -645,13 +645,13 @@ class PARTInterfaceBlind(PARTInterface):
|
|||||||
'subtractFeeFromOutputs': [0, ]
|
'subtractFeeFromOutputs': [0, ]
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = self.rpc_callback('fundrawtransactionfrom', ['blind', lock_refund_swipe_tx_hex, inputs_info, outputs_info, options])
|
rv = self.rpc_wallet('fundrawtransactionfrom', ['blind', lock_refund_swipe_tx_hex, inputs_info, outputs_info, options])
|
||||||
lock_refund_swipe_tx_hex = rv['hex']
|
lock_refund_swipe_tx_hex = rv['hex']
|
||||||
|
|
||||||
return bytes.fromhex(lock_refund_swipe_tx_hex)
|
return bytes.fromhex(lock_refund_swipe_tx_hex)
|
||||||
|
|
||||||
def getSpendableBalance(self) -> int:
|
def getSpendableBalance(self) -> int:
|
||||||
return self.make_int(self.rpc_callback('getbalances')['mine']['blind_trusted'])
|
return self.make_int(self.rpc_wallet('getbalances')['mine']['blind_trusted'])
|
||||||
|
|
||||||
def publishBLockTx(self, vkbv: bytes, Kbs: bytes, output_amount: int, feerate: int, delay_for: int = 10, unlock_time: int = 0) -> bytes:
|
def publishBLockTx(self, vkbv: bytes, Kbs: bytes, output_amount: int, feerate: int, delay_for: int = 10, unlock_time: int = 0) -> bytes:
|
||||||
Kbv = self.getPubkey(vkbv)
|
Kbv = self.getPubkey(vkbv)
|
||||||
@ -664,7 +664,7 @@ class PARTInterfaceBlind(PARTInterface):
|
|||||||
'', '', self._anon_tx_ring_size, 1, False,
|
'', '', self._anon_tx_ring_size, 1, False,
|
||||||
{'conf_target': self._conf_target, 'blind_watchonly_visible': True}]
|
{'conf_target': self._conf_target, 'blind_watchonly_visible': True}]
|
||||||
|
|
||||||
txid = self.rpc_callback('sendtypeto', params)
|
txid = self.rpc_wallet('sendtypeto', params)
|
||||||
return bytes.fromhex(txid)
|
return bytes.fromhex(txid)
|
||||||
|
|
||||||
def findTxB(self, kbv, Kbs, cb_swap_value, cb_block_confirmed, restore_height: int, bid_sender: bool):
|
def findTxB(self, kbv, Kbs, cb_swap_value, cb_block_confirmed, restore_height: int, bid_sender: bool):
|
||||||
@ -675,17 +675,17 @@ class PARTInterfaceBlind(PARTInterface):
|
|||||||
if bid_sender:
|
if bid_sender:
|
||||||
cb_swap_value *= -1
|
cb_swap_value *= -1
|
||||||
else:
|
else:
|
||||||
addr_info = self.rpc_callback('getaddressinfo', [sx_addr])
|
addr_info = self.rpc_wallet('getaddressinfo', [sx_addr])
|
||||||
if not addr_info['iswatchonly']:
|
if not addr_info['iswatchonly']:
|
||||||
wif_prefix = self.chainparams_network()['key_prefix']
|
wif_prefix = self.chainparams_network()['key_prefix']
|
||||||
wif_scan_key = toWIF(wif_prefix, kbv)
|
wif_scan_key = toWIF(wif_prefix, kbv)
|
||||||
self.rpc_callback('importstealthaddress', [wif_scan_key, Kbs.hex()])
|
self.rpc_wallet('importstealthaddress', [wif_scan_key, Kbs.hex()])
|
||||||
self._log.info('Imported watch-only sx_addr: {}'.format(sx_addr))
|
self._log.info('Imported watch-only sx_addr: {}'.format(sx_addr))
|
||||||
self._log.info('Rescanning {} chain from height: {}'.format(self.coin_name(), restore_height))
|
self._log.info('Rescanning {} chain from height: {}'.format(self.coin_name(), restore_height))
|
||||||
self.rpc_callback('rescanblockchain', [restore_height])
|
self.rpc_wallet('rescanblockchain', [restore_height])
|
||||||
|
|
||||||
params = [{'include_watchonly': True, 'search': sx_addr}]
|
params = [{'include_watchonly': True, 'search': sx_addr}]
|
||||||
txns = self.rpc_callback('filtertransactions', params)
|
txns = self.rpc_wallet('filtertransactions', params)
|
||||||
|
|
||||||
if len(txns) == 1:
|
if len(txns) == 1:
|
||||||
tx = txns[0]
|
tx = txns[0]
|
||||||
@ -695,7 +695,7 @@ class PARTInterfaceBlind(PARTInterface):
|
|||||||
if make_int(tx['outputs'][0]['amount']) == cb_swap_value:
|
if make_int(tx['outputs'][0]['amount']) == cb_swap_value:
|
||||||
height = 0
|
height = 0
|
||||||
if tx['confirmations'] > 0:
|
if tx['confirmations'] > 0:
|
||||||
chain_height = self.rpc_callback('getblockcount')
|
chain_height = self.rpc('getblockcount')
|
||||||
height = chain_height - (tx['confirmations'] - 1)
|
height = chain_height - (tx['confirmations'] - 1)
|
||||||
return {'txid': tx['txid'], 'amount': cb_swap_value, 'height': height}
|
return {'txid': tx['txid'], 'amount': cb_swap_value, 'height': height}
|
||||||
else:
|
else:
|
||||||
@ -707,20 +707,20 @@ class PARTInterfaceBlind(PARTInterface):
|
|||||||
Kbv = self.getPubkey(kbv)
|
Kbv = self.getPubkey(kbv)
|
||||||
Kbs = self.getPubkey(kbs)
|
Kbs = self.getPubkey(kbs)
|
||||||
sx_addr = self.formatStealthAddress(Kbv, Kbs)
|
sx_addr = self.formatStealthAddress(Kbv, Kbs)
|
||||||
addr_info = self.rpc_callback('getaddressinfo', [sx_addr])
|
addr_info = self.rpc_wallet('getaddressinfo', [sx_addr])
|
||||||
if not addr_info['ismine']:
|
if not addr_info['ismine']:
|
||||||
wif_prefix = self.chainparams_network()['key_prefix']
|
wif_prefix = self.chainparams_network()['key_prefix']
|
||||||
wif_scan_key = toWIF(wif_prefix, kbv)
|
wif_scan_key = toWIF(wif_prefix, kbv)
|
||||||
wif_spend_key = toWIF(wif_prefix, kbs)
|
wif_spend_key = toWIF(wif_prefix, kbs)
|
||||||
self.rpc_callback('importstealthaddress', [wif_scan_key, wif_spend_key])
|
self.rpc_wallet('importstealthaddress', [wif_scan_key, wif_spend_key])
|
||||||
self._log.info('Imported spend key for sx_addr: {}'.format(sx_addr))
|
self._log.info('Imported spend key for sx_addr: {}'.format(sx_addr))
|
||||||
self._log.info('Rescanning {} chain from height: {}'.format(self.coin_name(), restore_height))
|
self._log.info('Rescanning {} chain from height: {}'.format(self.coin_name(), restore_height))
|
||||||
self.rpc_callback('rescanblockchain', [restore_height])
|
self.rpc_wallet('rescanblockchain', [restore_height])
|
||||||
|
|
||||||
# TODO: Remove workaround
|
# TODO: Remove workaround
|
||||||
# utxos = self.rpc_callback('listunspentblind', [1, 9999999, [sx_addr]])
|
# utxos = self.rpc_wallet('listunspentblind', [1, 9999999, [sx_addr]])
|
||||||
utxos = []
|
utxos = []
|
||||||
all_utxos = self.rpc_callback('listunspentblind', [1, 9999999])
|
all_utxos = self.rpc_wallet('listunspentblind', [1, 9999999])
|
||||||
for utxo in all_utxos:
|
for utxo in all_utxos:
|
||||||
if utxo.get('stealth_address', '_') == sx_addr:
|
if utxo.get('stealth_address', '_') == sx_addr:
|
||||||
utxos.append(utxo)
|
utxos.append(utxo)
|
||||||
@ -741,14 +741,14 @@ class PARTInterfaceBlind(PARTInterface):
|
|||||||
[{'address': address_to, 'amount': self.format_amount(cb_swap_value), 'subfee': True}, ],
|
[{'address': address_to, 'amount': self.format_amount(cb_swap_value), 'subfee': True}, ],
|
||||||
'', '', self._anon_tx_ring_size, 1, False,
|
'', '', self._anon_tx_ring_size, 1, False,
|
||||||
{'conf_target': self._conf_target, 'inputs': inputs, 'show_fee': True}]
|
{'conf_target': self._conf_target, 'inputs': inputs, 'show_fee': True}]
|
||||||
rv = self.rpc_callback('sendtypeto', params)
|
rv = self.rpc_wallet('sendtypeto', params)
|
||||||
return bytes.fromhex(rv['txid'])
|
return bytes.fromhex(rv['txid'])
|
||||||
|
|
||||||
def findTxnByHash(self, txid_hex):
|
def findTxnByHash(self, txid_hex):
|
||||||
# txindex is enabled for Particl
|
# txindex is enabled for Particl
|
||||||
|
|
||||||
try:
|
try:
|
||||||
rv = self.rpc_callback('getrawtransaction', [txid_hex, True])
|
rv = self.rpc('getrawtransaction', [txid_hex, True])
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
self._log.debug('findTxnByHash getrawtransaction failed: {}'.format(txid_hex))
|
self._log.debug('findTxnByHash getrawtransaction failed: {}'.format(txid_hex))
|
||||||
return None
|
return None
|
||||||
@ -759,7 +759,7 @@ class PARTInterfaceBlind(PARTInterface):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def createRawFundedTransaction(self, addr_to: str, amount: int, sub_fee: bool = False, lock_unspents: bool = True) -> str:
|
def createRawFundedTransaction(self, addr_to: str, amount: int, sub_fee: bool = False, lock_unspents: bool = True) -> str:
|
||||||
txn = self.rpc_callback('createrawtransaction', [[], {addr_to: self.format_amount(amount)}])
|
txn = self.rpc_wallet('createrawtransaction', [[], {addr_to: self.format_amount(amount)}])
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
'lockUnspents': lock_unspents,
|
'lockUnspents': lock_unspents,
|
||||||
@ -767,7 +767,7 @@ class PARTInterfaceBlind(PARTInterface):
|
|||||||
}
|
}
|
||||||
if sub_fee:
|
if sub_fee:
|
||||||
options['subtractFeeFromOutputs'] = [0,]
|
options['subtractFeeFromOutputs'] = [0,]
|
||||||
return self.rpc_callback('fundrawtransactionfrom', ['blind', txn, options])['hex']
|
return self.rpc_wallet('fundrawtransactionfrom', ['blind', txn, options])['hex']
|
||||||
|
|
||||||
|
|
||||||
class PARTInterfaceAnon(PARTInterface):
|
class PARTInterfaceAnon(PARTInterface):
|
||||||
@ -801,7 +801,7 @@ class PARTInterfaceAnon(PARTInterface):
|
|||||||
'', '', self._anon_tx_ring_size, 1, False,
|
'', '', self._anon_tx_ring_size, 1, False,
|
||||||
{'conf_target': self._conf_target, 'blind_watchonly_visible': True}]
|
{'conf_target': self._conf_target, 'blind_watchonly_visible': True}]
|
||||||
|
|
||||||
txid = self.rpc_callback('sendtypeto', params)
|
txid = self.rpc_wallet('sendtypeto', params)
|
||||||
return bytes.fromhex(txid)
|
return bytes.fromhex(txid)
|
||||||
|
|
||||||
def findTxB(self, kbv, Kbs, cb_swap_value, cb_block_confirmed, restore_height, bid_sender):
|
def findTxB(self, kbv, Kbs, cb_swap_value, cb_block_confirmed, restore_height, bid_sender):
|
||||||
@ -813,17 +813,17 @@ class PARTInterfaceAnon(PARTInterface):
|
|||||||
if bid_sender:
|
if bid_sender:
|
||||||
cb_swap_value *= -1
|
cb_swap_value *= -1
|
||||||
else:
|
else:
|
||||||
addr_info = self.rpc_callback('getaddressinfo', [sx_addr])
|
addr_info = self.rpc_wallet('getaddressinfo', [sx_addr])
|
||||||
if not addr_info['iswatchonly']:
|
if not addr_info['iswatchonly']:
|
||||||
wif_prefix = self.chainparams_network()['key_prefix']
|
wif_prefix = self.chainparams_network()['key_prefix']
|
||||||
wif_scan_key = toWIF(wif_prefix, kbv)
|
wif_scan_key = toWIF(wif_prefix, kbv)
|
||||||
self.rpc_callback('importstealthaddress', [wif_scan_key, Kbs.hex()])
|
self.rpc_wallet('importstealthaddress', [wif_scan_key, Kbs.hex()])
|
||||||
self._log.info('Imported watch-only sx_addr: {}'.format(sx_addr))
|
self._log.info('Imported watch-only sx_addr: {}'.format(sx_addr))
|
||||||
self._log.info('Rescanning {} chain from height: {}'.format(self.coin_name(), restore_height))
|
self._log.info('Rescanning {} chain from height: {}'.format(self.coin_name(), restore_height))
|
||||||
self.rpc_callback('rescanblockchain', [restore_height])
|
self.rpc_wallet('rescanblockchain', [restore_height])
|
||||||
|
|
||||||
params = [{'include_watchonly': True, 'search': sx_addr}]
|
params = [{'include_watchonly': True, 'search': sx_addr}]
|
||||||
txns = self.rpc_callback('filtertransactions', params)
|
txns = self.rpc_wallet('filtertransactions', params)
|
||||||
|
|
||||||
if len(txns) == 1:
|
if len(txns) == 1:
|
||||||
tx = txns[0]
|
tx = txns[0]
|
||||||
@ -833,7 +833,7 @@ class PARTInterfaceAnon(PARTInterface):
|
|||||||
if make_int(tx['outputs'][0]['amount']) == cb_swap_value:
|
if make_int(tx['outputs'][0]['amount']) == cb_swap_value:
|
||||||
height = 0
|
height = 0
|
||||||
if tx['confirmations'] > 0:
|
if tx['confirmations'] > 0:
|
||||||
chain_height = self.rpc_callback('getblockcount')
|
chain_height = self.rpc('getblockcount')
|
||||||
height = chain_height - (tx['confirmations'] - 1)
|
height = chain_height - (tx['confirmations'] - 1)
|
||||||
return {'txid': tx['txid'], 'amount': cb_swap_value, 'height': height}
|
return {'txid': tx['txid'], 'amount': cb_swap_value, 'height': height}
|
||||||
else:
|
else:
|
||||||
@ -845,17 +845,17 @@ class PARTInterfaceAnon(PARTInterface):
|
|||||||
Kbv = self.getPubkey(kbv)
|
Kbv = self.getPubkey(kbv)
|
||||||
Kbs = self.getPubkey(kbs)
|
Kbs = self.getPubkey(kbs)
|
||||||
sx_addr = self.formatStealthAddress(Kbv, Kbs)
|
sx_addr = self.formatStealthAddress(Kbv, Kbs)
|
||||||
addr_info = self.rpc_callback('getaddressinfo', [sx_addr])
|
addr_info = self.rpc_wallet('getaddressinfo', [sx_addr])
|
||||||
if not addr_info['ismine']:
|
if not addr_info['ismine']:
|
||||||
wif_prefix = self.chainparams_network()['key_prefix']
|
wif_prefix = self.chainparams_network()['key_prefix']
|
||||||
wif_scan_key = toWIF(wif_prefix, kbv)
|
wif_scan_key = toWIF(wif_prefix, kbv)
|
||||||
wif_spend_key = toWIF(wif_prefix, kbs)
|
wif_spend_key = toWIF(wif_prefix, kbs)
|
||||||
self.rpc_callback('importstealthaddress', [wif_scan_key, wif_spend_key])
|
self.rpc_wallet('importstealthaddress', [wif_scan_key, wif_spend_key])
|
||||||
self._log.info('Imported spend key for sx_addr: {}'.format(sx_addr))
|
self._log.info('Imported spend key for sx_addr: {}'.format(sx_addr))
|
||||||
self._log.info('Rescanning {} chain from height: {}'.format(self.coin_name(), restore_height))
|
self._log.info('Rescanning {} chain from height: {}'.format(self.coin_name(), restore_height))
|
||||||
self.rpc_callback('rescanblockchain', [restore_height])
|
self.rpc_wallet('rescanblockchain', [restore_height])
|
||||||
|
|
||||||
autxos = self.rpc_callback('listunspentanon', [1, 9999999, [sx_addr]])
|
autxos = self.rpc_wallet('listunspentanon', [1, 9999999, [sx_addr]])
|
||||||
|
|
||||||
if len(autxos) < 1:
|
if len(autxos) < 1:
|
||||||
raise TemporaryError('No spendable outputs')
|
raise TemporaryError('No spendable outputs')
|
||||||
@ -874,14 +874,14 @@ class PARTInterfaceAnon(PARTInterface):
|
|||||||
[{'address': address_to, 'amount': self.format_amount(cb_swap_value), 'subfee': True}, ],
|
[{'address': address_to, 'amount': self.format_amount(cb_swap_value), 'subfee': True}, ],
|
||||||
'', '', self._anon_tx_ring_size, 1, False,
|
'', '', self._anon_tx_ring_size, 1, False,
|
||||||
{'conf_target': self._conf_target, 'inputs': inputs, 'show_fee': True}]
|
{'conf_target': self._conf_target, 'inputs': inputs, 'show_fee': True}]
|
||||||
rv = self.rpc_callback('sendtypeto', params)
|
rv = self.rpc_wallet('sendtypeto', params)
|
||||||
return bytes.fromhex(rv['txid'])
|
return bytes.fromhex(rv['txid'])
|
||||||
|
|
||||||
def findTxnByHash(self, txid_hex: str):
|
def findTxnByHash(self, txid_hex: str):
|
||||||
# txindex is enabled for Particl
|
# txindex is enabled for Particl
|
||||||
|
|
||||||
try:
|
try:
|
||||||
rv = self.rpc_callback('getrawtransaction', [txid_hex, True])
|
rv = self.rpc('getrawtransaction', [txid_hex, True])
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
self._log.debug('findTxnByHash getrawtransaction failed: {}'.format(txid_hex))
|
self._log.debug('findTxnByHash getrawtransaction failed: {}'.format(txid_hex))
|
||||||
return None
|
return None
|
||||||
@ -892,4 +892,4 @@ class PARTInterfaceAnon(PARTInterface):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def getSpendableBalance(self) -> int:
|
def getSpendableBalance(self) -> int:
|
||||||
return self.make_int(self.rpc_callback('getbalances')['mine']['anon_trusted'])
|
return self.make_int(self.rpc_wallet('getbalances')['mine']['anon_trusted'])
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
from .btc import BTCInterface
|
from .btc import BTCInterface
|
||||||
|
from basicswap.rpc import make_rpc_func
|
||||||
from basicswap.chainparams import Coins
|
from basicswap.chainparams import Coins
|
||||||
from basicswap.util.address import decodeAddress
|
from basicswap.util.address import decodeAddress
|
||||||
from .contrib.pivx_test_framework.messages import (
|
from .contrib.pivx_test_framework.messages import (
|
||||||
@ -29,12 +30,20 @@ class PIVXInterface(BTCInterface):
|
|||||||
def coin_type():
|
def coin_type():
|
||||||
return Coins.PIVX
|
return Coins.PIVX
|
||||||
|
|
||||||
|
def __init__(self, coin_settings, network, swap_client=None):
|
||||||
|
super(PIVXInterface, self).__init__(coin_settings, network, swap_client)
|
||||||
|
# No multiwallet support
|
||||||
|
self.rpc_wallet = make_rpc_func(self._rpcport, self._rpcauth, host=self._rpc_host)
|
||||||
|
|
||||||
|
def checkWallets(self) -> int:
|
||||||
|
return 1
|
||||||
|
|
||||||
def signTxWithWallet(self, tx):
|
def signTxWithWallet(self, tx):
|
||||||
rv = self.rpc_callback('signrawtransaction', [tx.hex()])
|
rv = self.rpc('signrawtransaction', [tx.hex()])
|
||||||
return bytes.fromhex(rv['hex'])
|
return bytes.fromhex(rv['hex'])
|
||||||
|
|
||||||
def createRawFundedTransaction(self, addr_to: str, amount: int, sub_fee: bool = False, lock_unspents: bool = True) -> str:
|
def createRawFundedTransaction(self, addr_to: str, amount: int, sub_fee: bool = False, lock_unspents: bool = True) -> str:
|
||||||
txn = self.rpc_callback('createrawtransaction', [[], {addr_to: self.format_amount(amount)}])
|
txn = self.rpc('createrawtransaction', [[], {addr_to: self.format_amount(amount)}])
|
||||||
fee_rate, fee_src = self.get_fee_rate(self._conf_target)
|
fee_rate, fee_src = self.get_fee_rate(self._conf_target)
|
||||||
self._log.debug(f'Fee rate: {fee_rate}, source: {fee_src}, block target: {self._conf_target}')
|
self._log.debug(f'Fee rate: {fee_rate}, source: {fee_src}, block target: {self._conf_target}')
|
||||||
options = {
|
options = {
|
||||||
@ -43,25 +52,25 @@ class PIVXInterface(BTCInterface):
|
|||||||
}
|
}
|
||||||
if sub_fee:
|
if sub_fee:
|
||||||
options['subtractFeeFromOutputs'] = [0,]
|
options['subtractFeeFromOutputs'] = [0,]
|
||||||
return self.rpc_callback('fundrawtransaction', [txn, options])['hex']
|
return self.rpc('fundrawtransaction', [txn, options])['hex']
|
||||||
|
|
||||||
def createRawSignedTransaction(self, addr_to, amount) -> str:
|
def createRawSignedTransaction(self, addr_to, amount) -> str:
|
||||||
txn_funded = self.createRawFundedTransaction(addr_to, amount)
|
txn_funded = self.createRawFundedTransaction(addr_to, amount)
|
||||||
return self.rpc_callback('signrawtransaction', [txn_funded])['hex']
|
return self.rpc('signrawtransaction', [txn_funded])['hex']
|
||||||
|
|
||||||
def decodeAddress(self, address):
|
def decodeAddress(self, address):
|
||||||
return decodeAddress(address)[1:]
|
return decodeAddress(address)[1:]
|
||||||
|
|
||||||
def getBlockWithTxns(self, block_hash):
|
def getBlockWithTxns(self, block_hash):
|
||||||
# TODO: Bypass decoderawtransaction and getblockheader
|
# TODO: Bypass decoderawtransaction and getblockheader
|
||||||
block = self.rpc_callback('getblock', [block_hash, False])
|
block = self.rpc('getblock', [block_hash, False])
|
||||||
block_header = self.rpc_callback('getblockheader', [block_hash])
|
block_header = self.rpc('getblockheader', [block_hash])
|
||||||
decoded_block = CBlock()
|
decoded_block = CBlock()
|
||||||
decoded_block = FromHex(decoded_block, block)
|
decoded_block = FromHex(decoded_block, block)
|
||||||
|
|
||||||
tx_rv = []
|
tx_rv = []
|
||||||
for tx in decoded_block.vtx:
|
for tx in decoded_block.vtx:
|
||||||
tx_dec = self.rpc_callback('decoderawtransaction', [ToHex(tx)])
|
tx_dec = self.rpc('decoderawtransaction', [ToHex(tx)])
|
||||||
tx_rv.append(tx_dec)
|
tx_rv.append(tx_dec)
|
||||||
|
|
||||||
block_rv = {
|
block_rv = {
|
||||||
@ -77,10 +86,10 @@ class PIVXInterface(BTCInterface):
|
|||||||
|
|
||||||
def withdrawCoin(self, value, addr_to, subfee):
|
def withdrawCoin(self, value, addr_to, subfee):
|
||||||
params = [addr_to, value, '', '', subfee]
|
params = [addr_to, value, '', '', subfee]
|
||||||
return self.rpc_callback('sendtoaddress', params)
|
return self.rpc('sendtoaddress', params)
|
||||||
|
|
||||||
def getSpendableBalance(self) -> int:
|
def getSpendableBalance(self) -> int:
|
||||||
return self.make_int(self.rpc_callback('getwalletinfo')['balance'])
|
return self.make_int(self.rpc('getwalletinfo')['balance'])
|
||||||
|
|
||||||
def loadTx(self, tx_bytes):
|
def loadTx(self, tx_bytes):
|
||||||
# Load tx from bytes to internal representation
|
# Load tx from bytes to internal representation
|
||||||
@ -101,13 +110,13 @@ class PIVXInterface(BTCInterface):
|
|||||||
|
|
||||||
def signTxWithKey(self, tx: bytes, key: bytes) -> bytes:
|
def signTxWithKey(self, tx: bytes, key: bytes) -> bytes:
|
||||||
key_wif = self.encodeKey(key)
|
key_wif = self.encodeKey(key)
|
||||||
rv = self.rpc_callback('signrawtransaction', [tx.hex(), [], [key_wif, ]])
|
rv = self.rpc('signrawtransaction', [tx.hex(), [], [key_wif, ]])
|
||||||
return bytes.fromhex(rv['hex'])
|
return bytes.fromhex(rv['hex'])
|
||||||
|
|
||||||
def findTxnByHash(self, txid_hex: str):
|
def findTxnByHash(self, txid_hex: str):
|
||||||
# Only works for wallet txns
|
# Only works for wallet txns
|
||||||
try:
|
try:
|
||||||
rv = self.rpc_callback('gettransaction', [txid_hex])
|
rv = self.rpc('gettransaction', [txid_hex])
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
self._log.debug('findTxnByHash getrawtransaction failed: {}'.format(txid_hex))
|
self._log.debug('findTxnByHash getrawtransaction failed: {}'.format(txid_hex))
|
||||||
return None
|
return None
|
||||||
|
@ -83,9 +83,9 @@ class XMRInterface(CoinInterface):
|
|||||||
daemon_login = None
|
daemon_login = None
|
||||||
if coin_settings.get('rpcuser', '') != '':
|
if coin_settings.get('rpcuser', '') != '':
|
||||||
daemon_login = (coin_settings.get('rpcuser', ''), coin_settings.get('rpcpassword', ''))
|
daemon_login = (coin_settings.get('rpcuser', ''), coin_settings.get('rpcpassword', ''))
|
||||||
self.rpc_cb = make_xmr_rpc_func(coin_settings['rpcport'], daemon_login, host=coin_settings.get('rpchost', '127.0.0.1'))
|
self.rpc = make_xmr_rpc_func(coin_settings['rpcport'], daemon_login, host=coin_settings.get('rpchost', '127.0.0.1'))
|
||||||
self.rpc_cb2 = make_xmr_rpc2_func(coin_settings['rpcport'], daemon_login, host=coin_settings.get('rpchost', '127.0.0.1')) # non-json endpoint
|
self.rpc2 = make_xmr_rpc2_func(coin_settings['rpcport'], daemon_login, host=coin_settings.get('rpchost', '127.0.0.1')) # non-json endpoint
|
||||||
self.rpc_wallet_cb = make_xmr_rpc_func(coin_settings['walletrpcport'], coin_settings['walletrpcauth'], host=coin_settings.get('walletrpchost', '127.0.0.1'))
|
self.rpc_wallet = make_xmr_rpc_func(coin_settings['walletrpcport'], coin_settings['walletrpcauth'], host=coin_settings.get('walletrpchost', '127.0.0.1'))
|
||||||
|
|
||||||
self.blocks_confirmed = coin_settings['blocks_confirmed']
|
self.blocks_confirmed = coin_settings['blocks_confirmed']
|
||||||
self._restore_height = coin_settings.get('restore_height', 0)
|
self._restore_height = coin_settings.get('restore_height', 0)
|
||||||
@ -95,6 +95,9 @@ class XMRInterface(CoinInterface):
|
|||||||
self._wallet_password = None
|
self._wallet_password = None
|
||||||
self._have_checked_seed = False
|
self._have_checked_seed = False
|
||||||
|
|
||||||
|
def checkWallets(self) -> int:
|
||||||
|
return 1
|
||||||
|
|
||||||
def setFeePriority(self, new_priority):
|
def setFeePriority(self, new_priority):
|
||||||
ensure(new_priority >= 0 and new_priority < 4, 'Invalid fee_priority value')
|
ensure(new_priority >= 0 and new_priority < 4, 'Invalid fee_priority value')
|
||||||
self._fee_priority = new_priority
|
self._fee_priority = new_priority
|
||||||
@ -105,7 +108,7 @@ class XMRInterface(CoinInterface):
|
|||||||
def createWallet(self, params):
|
def createWallet(self, params):
|
||||||
if self._wallet_password is not None:
|
if self._wallet_password is not None:
|
||||||
params['password'] = self._wallet_password
|
params['password'] = self._wallet_password
|
||||||
rv = self.rpc_wallet_cb('generate_from_keys', params)
|
rv = self.rpc_wallet('generate_from_keys', params)
|
||||||
self._log.info('generate_from_keys %s', dumpj(rv))
|
self._log.info('generate_from_keys %s', dumpj(rv))
|
||||||
|
|
||||||
def openWallet(self, filename):
|
def openWallet(self, filename):
|
||||||
@ -115,10 +118,10 @@ class XMRInterface(CoinInterface):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
# Can't reopen the same wallet in windows, !is_keys_file_locked()
|
# Can't reopen the same wallet in windows, !is_keys_file_locked()
|
||||||
self.rpc_wallet_cb('close_wallet')
|
self.rpc_wallet('close_wallet')
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
self.rpc_wallet_cb('open_wallet', params)
|
self.rpc_wallet('open_wallet', params)
|
||||||
|
|
||||||
def initialiseWallet(self, key_view, key_spend, restore_height=None):
|
def initialiseWallet(self, key_view, key_spend, restore_height=None):
|
||||||
with self._mx_wallet:
|
with self._mx_wallet:
|
||||||
@ -147,14 +150,14 @@ class XMRInterface(CoinInterface):
|
|||||||
with self._mx_wallet:
|
with self._mx_wallet:
|
||||||
self.openWallet(self._wallet_filename)
|
self.openWallet(self._wallet_filename)
|
||||||
|
|
||||||
def testDaemonRPC(self, with_wallet=True):
|
def testDaemonRPC(self, with_wallet=True) -> None:
|
||||||
self.rpc_wallet_cb('get_languages')
|
self.rpc_wallet('get_languages')
|
||||||
|
|
||||||
def getDaemonVersion(self):
|
def getDaemonVersion(self):
|
||||||
return self.rpc_wallet_cb('get_version')['version']
|
return self.rpc_wallet('get_version')['version']
|
||||||
|
|
||||||
def getBlockchainInfo(self):
|
def getBlockchainInfo(self):
|
||||||
get_height = self.rpc_cb2('get_height', timeout=30)
|
get_height = self.rpc2('get_height', timeout=30)
|
||||||
rv = {
|
rv = {
|
||||||
'blocks': get_height['height'],
|
'blocks': get_height['height'],
|
||||||
'verificationprogress': 0.0,
|
'verificationprogress': 0.0,
|
||||||
@ -165,7 +168,7 @@ class XMRInterface(CoinInterface):
|
|||||||
# get_block_count returns "Internal error" if bootstrap-daemon is active
|
# get_block_count returns "Internal error" if bootstrap-daemon is active
|
||||||
if get_height['untrusted'] is True:
|
if get_height['untrusted'] is True:
|
||||||
rv['bootstrapping'] = True
|
rv['bootstrapping'] = True
|
||||||
get_info = self.rpc_cb2('get_info', timeout=30)
|
get_info = self.rpc2('get_info', timeout=30)
|
||||||
if 'height_without_bootstrap' in get_info:
|
if 'height_without_bootstrap' in get_info:
|
||||||
rv['blocks'] = get_info['height_without_bootstrap']
|
rv['blocks'] = get_info['height_without_bootstrap']
|
||||||
|
|
||||||
@ -173,7 +176,7 @@ class XMRInterface(CoinInterface):
|
|||||||
if rv['known_block_count'] > rv['blocks']:
|
if rv['known_block_count'] > rv['blocks']:
|
||||||
rv['verificationprogress'] = rv['blocks'] / rv['known_block_count']
|
rv['verificationprogress'] = rv['blocks'] / rv['known_block_count']
|
||||||
else:
|
else:
|
||||||
rv['known_block_count'] = self.rpc_cb('get_block_count', timeout=30)['count']
|
rv['known_block_count'] = self.rpc('get_block_count', timeout=30)['count']
|
||||||
rv['verificationprogress'] = rv['blocks'] / rv['known_block_count']
|
rv['verificationprogress'] = rv['blocks'] / rv['known_block_count']
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self._log.warning('XMR get_block_count failed with: %s', str(e))
|
self._log.warning('XMR get_block_count failed with: %s', str(e))
|
||||||
@ -182,7 +185,7 @@ class XMRInterface(CoinInterface):
|
|||||||
return rv
|
return rv
|
||||||
|
|
||||||
def getChainHeight(self):
|
def getChainHeight(self):
|
||||||
return self.rpc_cb2('get_height', timeout=30)['height']
|
return self.rpc2('get_height', timeout=30)['height']
|
||||||
|
|
||||||
def getWalletInfo(self):
|
def getWalletInfo(self):
|
||||||
with self._mx_wallet:
|
with self._mx_wallet:
|
||||||
@ -195,8 +198,8 @@ class XMRInterface(CoinInterface):
|
|||||||
raise e
|
raise e
|
||||||
|
|
||||||
rv = {}
|
rv = {}
|
||||||
self.rpc_wallet_cb('refresh')
|
self.rpc_wallet('refresh')
|
||||||
balance_info = self.rpc_wallet_cb('get_balance')
|
balance_info = self.rpc_wallet('get_balance')
|
||||||
rv['balance'] = self.format_amount(balance_info['unlocked_balance'])
|
rv['balance'] = self.format_amount(balance_info['unlocked_balance'])
|
||||||
rv['unconfirmed_balance'] = self.format_amount(balance_info['balance'] - balance_info['unlocked_balance'])
|
rv['unconfirmed_balance'] = self.format_amount(balance_info['balance'] - balance_info['unlocked_balance'])
|
||||||
rv['encrypted'] = False if self._wallet_password is None else True
|
rv['encrypted'] = False if self._wallet_password is None else True
|
||||||
@ -209,13 +212,13 @@ class XMRInterface(CoinInterface):
|
|||||||
def getMainWalletAddress(self) -> str:
|
def getMainWalletAddress(self) -> str:
|
||||||
with self._mx_wallet:
|
with self._mx_wallet:
|
||||||
self.openWallet(self._wallet_filename)
|
self.openWallet(self._wallet_filename)
|
||||||
return self.rpc_wallet_cb('get_address')['address']
|
return self.rpc_wallet('get_address')['address']
|
||||||
|
|
||||||
def getNewAddress(self, placeholder) -> str:
|
def getNewAddress(self, placeholder) -> str:
|
||||||
with self._mx_wallet:
|
with self._mx_wallet:
|
||||||
self.openWallet(self._wallet_filename)
|
self.openWallet(self._wallet_filename)
|
||||||
new_address = self.rpc_wallet_cb('create_address', {'account_index': 0})['address']
|
new_address = self.rpc_wallet('create_address', {'account_index': 0})['address']
|
||||||
self.rpc_wallet_cb('store')
|
self.rpc_wallet('store')
|
||||||
return new_address
|
return new_address
|
||||||
|
|
||||||
def get_fee_rate(self, conf_target: int = 2):
|
def get_fee_rate(self, conf_target: int = 2):
|
||||||
@ -280,7 +283,7 @@ class XMRInterface(CoinInterface):
|
|||||||
def publishBLockTx(self, kbv: bytes, Kbs: bytes, output_amount: int, feerate: int, delay_for: int = 10, unlock_time: int = 0) -> bytes:
|
def publishBLockTx(self, kbv: bytes, Kbs: bytes, output_amount: int, feerate: int, delay_for: int = 10, unlock_time: int = 0) -> bytes:
|
||||||
with self._mx_wallet:
|
with self._mx_wallet:
|
||||||
self.openWallet(self._wallet_filename)
|
self.openWallet(self._wallet_filename)
|
||||||
self.rpc_wallet_cb('refresh')
|
self.rpc_wallet('refresh')
|
||||||
|
|
||||||
Kbv = self.getPubkey(kbv)
|
Kbv = self.getPubkey(kbv)
|
||||||
shared_addr = xmr_util.encode_address(Kbv, Kbs)
|
shared_addr = xmr_util.encode_address(Kbv, Kbs)
|
||||||
@ -288,7 +291,7 @@ class XMRInterface(CoinInterface):
|
|||||||
params = {'destinations': [{'amount': output_amount, 'address': shared_addr}], 'unlock_time': unlock_time}
|
params = {'destinations': [{'amount': output_amount, 'address': shared_addr}], 'unlock_time': unlock_time}
|
||||||
if self._fee_priority > 0:
|
if self._fee_priority > 0:
|
||||||
params['priority'] = self._fee_priority
|
params['priority'] = self._fee_priority
|
||||||
rv = self.rpc_wallet_cb('transfer', params)
|
rv = self.rpc_wallet('transfer', params)
|
||||||
self._log.info('publishBLockTx %s to address_b58 %s', rv['tx_hash'], shared_addr)
|
self._log.info('publishBLockTx %s to address_b58 %s', rv['tx_hash'], shared_addr)
|
||||||
tx_hash = bytes.fromhex(rv['tx_hash'])
|
tx_hash = bytes.fromhex(rv['tx_hash'])
|
||||||
|
|
||||||
@ -296,7 +299,7 @@ class XMRInterface(CoinInterface):
|
|||||||
i = 0
|
i = 0
|
||||||
while not self._sc.delay_event.is_set():
|
while not self._sc.delay_event.is_set():
|
||||||
gt_params = {'out': True, 'pending': True, 'failed': True, 'pool': True, }
|
gt_params = {'out': True, 'pending': True, 'failed': True, 'pool': True, }
|
||||||
rv = self.rpc_wallet_cb('get_transfers', gt_params)
|
rv = self.rpc_wallet('get_transfers', gt_params)
|
||||||
self._log.debug('get_transfers {}'.format(dumpj(rv)))
|
self._log.debug('get_transfers {}'.format(dumpj(rv)))
|
||||||
if 'pending' not in rv:
|
if 'pending' not in rv:
|
||||||
break
|
break
|
||||||
@ -325,26 +328,26 @@ class XMRInterface(CoinInterface):
|
|||||||
self.createWallet(params)
|
self.createWallet(params)
|
||||||
self.openWallet(address_b58)
|
self.openWallet(address_b58)
|
||||||
|
|
||||||
self.rpc_wallet_cb('refresh', timeout=600)
|
self.rpc_wallet('refresh', timeout=600)
|
||||||
|
|
||||||
'''
|
'''
|
||||||
# Debug
|
# Debug
|
||||||
try:
|
try:
|
||||||
current_height = self.rpc_wallet_cb('get_height')['height']
|
current_height = self.rpc_wallet('get_height')['height']
|
||||||
self._log.info('findTxB XMR current_height %d\nAddress: %s', current_height, address_b58)
|
self._log.info('findTxB XMR current_height %d\nAddress: %s', current_height, address_b58)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self._log.info('rpc_cb failed %s', str(e))
|
self._log.info('rpc failed %s', str(e))
|
||||||
current_height = None # If the transfer is available it will be deep enough
|
current_height = None # If the transfer is available it will be deep enough
|
||||||
# and (current_height is None or current_height - transfer['block_height'] > cb_block_confirmed):
|
# and (current_height is None or current_height - transfer['block_height'] > cb_block_confirmed):
|
||||||
'''
|
'''
|
||||||
params = {'transfer_type': 'available'}
|
params = {'transfer_type': 'available'}
|
||||||
transfers = self.rpc_wallet_cb('incoming_transfers', params)
|
transfers = self.rpc_wallet('incoming_transfers', params)
|
||||||
rv = None
|
rv = None
|
||||||
if 'transfers' in transfers:
|
if 'transfers' in transfers:
|
||||||
for transfer in transfers['transfers']:
|
for transfer in transfers['transfers']:
|
||||||
# unlocked <- wallet->is_transfer_unlocked() checks unlock_time and CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE
|
# unlocked <- wallet->is_transfer_unlocked() checks unlock_time and CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE
|
||||||
if not transfer['unlocked']:
|
if not transfer['unlocked']:
|
||||||
full_tx = self.rpc_wallet_cb('get_transfer_by_txid', {'txid': transfer['tx_hash']})
|
full_tx = self.rpc_wallet('get_transfer_by_txid', {'txid': transfer['tx_hash']})
|
||||||
unlock_time = full_tx['transfer']['unlock_time']
|
unlock_time = full_tx['transfer']['unlock_time']
|
||||||
if unlock_time != 0:
|
if unlock_time != 0:
|
||||||
self._log.warning('Coin b lock txn is locked: {}, unlock_time {}'.format(transfer['tx_hash'], unlock_time))
|
self._log.warning('Coin b lock txn is locked: {}, unlock_time {}'.format(transfer['tx_hash'], unlock_time))
|
||||||
@ -360,17 +363,17 @@ class XMRInterface(CoinInterface):
|
|||||||
def findTxnByHash(self, txid):
|
def findTxnByHash(self, txid):
|
||||||
with self._mx_wallet:
|
with self._mx_wallet:
|
||||||
self.openWallet(self._wallet_filename)
|
self.openWallet(self._wallet_filename)
|
||||||
self.rpc_wallet_cb('refresh', timeout=600)
|
self.rpc_wallet('refresh', timeout=600)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
current_height = self.rpc_cb2('get_height', timeout=30)['height']
|
current_height = self.rpc2('get_height', timeout=30)['height']
|
||||||
self._log.info('findTxnByHash XMR current_height %d\nhash: %s', current_height, txid)
|
self._log.info('findTxnByHash XMR current_height %d\nhash: %s', current_height, txid)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self._log.info('rpc_cb failed %s', str(e))
|
self._log.info('rpc failed %s', str(e))
|
||||||
current_height = None # If the transfer is available it will be deep enough
|
current_height = None # If the transfer is available it will be deep enough
|
||||||
|
|
||||||
params = {'transfer_type': 'available'}
|
params = {'transfer_type': 'available'}
|
||||||
rv = self.rpc_wallet_cb('incoming_transfers', params)
|
rv = self.rpc_wallet('incoming_transfers', params)
|
||||||
if 'transfers' in rv:
|
if 'transfers' in rv:
|
||||||
for transfer in rv['transfers']:
|
for transfer in rv['transfers']:
|
||||||
if transfer['tx_hash'] == txid \
|
if transfer['tx_hash'] == txid \
|
||||||
@ -405,11 +408,11 @@ class XMRInterface(CoinInterface):
|
|||||||
self.createWallet(params)
|
self.createWallet(params)
|
||||||
self.openWallet(wallet_filename)
|
self.openWallet(wallet_filename)
|
||||||
|
|
||||||
self.rpc_wallet_cb('refresh')
|
self.rpc_wallet('refresh')
|
||||||
rv = self.rpc_wallet_cb('get_balance')
|
rv = self.rpc_wallet('get_balance')
|
||||||
if rv['balance'] < cb_swap_value:
|
if rv['balance'] < cb_swap_value:
|
||||||
self._log.warning('Balance is too low, checking for existing spend.')
|
self._log.warning('Balance is too low, checking for existing spend.')
|
||||||
txns = self.rpc_wallet_cb('get_transfers', {'out': True})
|
txns = self.rpc_wallet('get_transfers', {'out': True})
|
||||||
if 'out' in txns:
|
if 'out' in txns:
|
||||||
txns = txns['out']
|
txns = txns['out']
|
||||||
if len(txns) > 0:
|
if len(txns) > 0:
|
||||||
@ -434,7 +437,7 @@ class XMRInterface(CoinInterface):
|
|||||||
if self._fee_priority > 0:
|
if self._fee_priority > 0:
|
||||||
params['priority'] = self._fee_priority
|
params['priority'] = self._fee_priority
|
||||||
|
|
||||||
rv = self.rpc_wallet_cb('sweep_all', params)
|
rv = self.rpc_wallet('sweep_all', params)
|
||||||
self._log.debug('sweep_all {}'.format(json.dumps(rv)))
|
self._log.debug('sweep_all {}'.format(json.dumps(rv)))
|
||||||
|
|
||||||
return bytes.fromhex(rv['tx_hash_list'][0])
|
return bytes.fromhex(rv['tx_hash_list'][0])
|
||||||
@ -444,24 +447,24 @@ class XMRInterface(CoinInterface):
|
|||||||
value_sats = make_int(value, self.exp())
|
value_sats = make_int(value, self.exp())
|
||||||
|
|
||||||
self.openWallet(self._wallet_filename)
|
self.openWallet(self._wallet_filename)
|
||||||
self.rpc_wallet_cb('refresh')
|
self.rpc_wallet('refresh')
|
||||||
|
|
||||||
if subfee:
|
if subfee:
|
||||||
balance = self.rpc_wallet_cb('get_balance')
|
balance = self.rpc_wallet('get_balance')
|
||||||
diff = balance['unlocked_balance'] - value_sats
|
diff = balance['unlocked_balance'] - value_sats
|
||||||
if diff >= 0 and diff <= 10:
|
if diff >= 0 and diff <= 10:
|
||||||
self._log.info('subfee enabled and value close to total, using sweep_all.')
|
self._log.info('subfee enabled and value close to total, using sweep_all.')
|
||||||
params = {'address': addr_to}
|
params = {'address': addr_to}
|
||||||
if self._fee_priority > 0:
|
if self._fee_priority > 0:
|
||||||
params['priority'] = self._fee_priority
|
params['priority'] = self._fee_priority
|
||||||
rv = self.rpc_wallet_cb('sweep_all', params)
|
rv = self.rpc_wallet('sweep_all', params)
|
||||||
return rv['tx_hash_list'][0]
|
return rv['tx_hash_list'][0]
|
||||||
raise ValueError('Withdraw value must be close to total to use subfee/sweep_all.')
|
raise ValueError('Withdraw value must be close to total to use subfee/sweep_all.')
|
||||||
|
|
||||||
params = {'destinations': [{'amount': value_sats, 'address': addr_to}]}
|
params = {'destinations': [{'amount': value_sats, 'address': addr_to}]}
|
||||||
if self._fee_priority > 0:
|
if self._fee_priority > 0:
|
||||||
params['priority'] = self._fee_priority
|
params['priority'] = self._fee_priority
|
||||||
rv = self.rpc_wallet_cb('transfer', params)
|
rv = self.rpc_wallet('transfer', params)
|
||||||
return rv['tx_hash']
|
return rv['tx_hash']
|
||||||
|
|
||||||
def showLockTransfers(self, kbv, Kbs, restore_height):
|
def showLockTransfers(self, kbv, Kbs, restore_height):
|
||||||
@ -488,9 +491,9 @@ class XMRInterface(CoinInterface):
|
|||||||
self.createWallet(params)
|
self.createWallet(params)
|
||||||
self.openWallet(address_b58)
|
self.openWallet(address_b58)
|
||||||
|
|
||||||
self.rpc_wallet_cb('refresh')
|
self.rpc_wallet('refresh')
|
||||||
|
|
||||||
rv = self.rpc_wallet_cb('get_transfers', {'in': True, 'out': True, 'pending': True, 'failed': True})
|
rv = self.rpc_wallet('get_transfers', {'in': True, 'out': True, 'pending': True, 'failed': True})
|
||||||
rv['filename'] = wallet_file
|
rv['filename'] = wallet_file
|
||||||
return rv
|
return rv
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -500,8 +503,8 @@ class XMRInterface(CoinInterface):
|
|||||||
with self._mx_wallet:
|
with self._mx_wallet:
|
||||||
self.openWallet(self._wallet_filename)
|
self.openWallet(self._wallet_filename)
|
||||||
|
|
||||||
self.rpc_wallet_cb('refresh')
|
self.rpc_wallet('refresh')
|
||||||
balance_info = self.rpc_wallet_cb('get_balance')
|
balance_info = self.rpc_wallet('get_balance')
|
||||||
return balance_info['unlocked_balance']
|
return balance_info['unlocked_balance']
|
||||||
|
|
||||||
def changeWalletPassword(self, old_password, new_password):
|
def changeWalletPassword(self, old_password, new_password):
|
||||||
@ -511,7 +514,7 @@ class XMRInterface(CoinInterface):
|
|||||||
self._wallet_password = old_password
|
self._wallet_password = old_password
|
||||||
try:
|
try:
|
||||||
self.openWallet(self._wallet_filename)
|
self.openWallet(self._wallet_filename)
|
||||||
self.rpc_wallet_cb('change_wallet_password', {'old_password': old_password, 'new_password': new_password})
|
self.rpc_wallet('change_wallet_password', {'old_password': old_password, 'new_password': new_password})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self._wallet_password = orig_password
|
self._wallet_password = orig_password
|
||||||
raise e
|
raise e
|
||||||
@ -536,4 +539,4 @@ class XMRInterface(CoinInterface):
|
|||||||
raise ValueError('Balance too low')
|
raise ValueError('Balance too low')
|
||||||
|
|
||||||
def getTransaction(self, txid: bytes):
|
def getTransaction(self, txid: bytes):
|
||||||
return self.rpc_cb2('get_transactions', {'txs_hashes': [txid.hex(), ]})
|
return self.rpc2('get_transactions', {'txs_hashes': [txid.hex(), ]})
|
||||||
|
@ -63,6 +63,9 @@ def withdraw_coin(swap_client, coin_type, post_string, is_json):
|
|||||||
type_from = get_data_entry_or(post_data, 'type_from', 'plain')
|
type_from = get_data_entry_or(post_data, 'type_from', 'plain')
|
||||||
type_to = get_data_entry_or(post_data, 'type_to', 'plain')
|
type_to = get_data_entry_or(post_data, 'type_to', 'plain')
|
||||||
txid_hex = swap_client.withdrawParticl(type_from, type_to, value, address, subfee)
|
txid_hex = swap_client.withdrawParticl(type_from, type_to, value, address, subfee)
|
||||||
|
elif coin_type == Coins.LTC:
|
||||||
|
type_from = get_data_entry_or(post_data, 'type_from', 'plain')
|
||||||
|
txid_hex = swap_client.withdrawLTC(type_from, value, address, subfee)
|
||||||
else:
|
else:
|
||||||
txid_hex = swap_client.withdrawCoin(coin_type, value, address, subfee)
|
txid_hex = swap_client.withdrawCoin(coin_type, value, address, subfee)
|
||||||
|
|
||||||
@ -92,6 +95,8 @@ def js_coins(self, url_split, post_string, is_json) -> bytes:
|
|||||||
entry['variant'] = 'Anon'
|
entry['variant'] = 'Anon'
|
||||||
elif coin == Coins.PART_BLIND:
|
elif coin == Coins.PART_BLIND:
|
||||||
entry['variant'] = 'Blind'
|
entry['variant'] = 'Blind'
|
||||||
|
elif coin == Coins.LTC_MWEB:
|
||||||
|
entry['variant'] = 'MWEB'
|
||||||
coins.append(entry)
|
coins.append(entry)
|
||||||
|
|
||||||
return bytes(json.dumps(coins), 'UTF-8')
|
return bytes(json.dumps(coins), 'UTF-8')
|
||||||
@ -108,19 +113,30 @@ def js_wallets(self, url_split, post_string, is_json):
|
|||||||
cmd = url_split[4]
|
cmd = url_split[4]
|
||||||
if cmd == 'withdraw':
|
if cmd == 'withdraw':
|
||||||
return bytes(json.dumps(withdraw_coin(swap_client, coin_type, post_string, is_json)), 'UTF-8')
|
return bytes(json.dumps(withdraw_coin(swap_client, coin_type, post_string, is_json)), 'UTF-8')
|
||||||
if cmd == 'nextdepositaddr':
|
elif cmd == 'nextdepositaddr':
|
||||||
return bytes(json.dumps(swap_client.cacheNewAddressForCoin(coin_type)), 'UTF-8')
|
return bytes(json.dumps(swap_client.cacheNewAddressForCoin(coin_type)), 'UTF-8')
|
||||||
if cmd == 'createutxo':
|
elif cmd == 'createutxo':
|
||||||
post_data = getFormData(post_string, is_json)
|
post_data = getFormData(post_string, is_json)
|
||||||
ci = swap_client.ci(coin_type)
|
ci = swap_client.ci(coin_type)
|
||||||
value = ci.make_int(get_data_entry(post_data, 'value'))
|
value = ci.make_int(get_data_entry(post_data, 'value'))
|
||||||
txid_hex, new_addr = ci.createUTXO(value)
|
txid_hex, new_addr = ci.createUTXO(value)
|
||||||
return bytes(json.dumps({'txid': txid_hex, 'address': new_addr}), 'UTF-8')
|
return bytes(json.dumps({'txid': txid_hex, 'address': new_addr}), 'UTF-8')
|
||||||
if cmd == 'reseed':
|
elif cmd == 'reseed':
|
||||||
swap_client.reseedWallet(coin_type)
|
swap_client.reseedWallet(coin_type)
|
||||||
return bytes(json.dumps({'reseeded': True}), 'UTF-8')
|
return bytes(json.dumps({'reseeded': True}), 'UTF-8')
|
||||||
|
elif cmd == 'newstealthaddress':
|
||||||
|
if coin_type != Coins.PART:
|
||||||
|
raise ValueError('Invalid coin for command')
|
||||||
|
return bytes(json.dumps(swap_client.ci(coin_type).getNewStealthAddress()), 'UTF-8')
|
||||||
|
elif cmd == 'newmwebaddress':
|
||||||
|
if coin_type not in (Coins.LTC, Coins.LTC_MWEB):
|
||||||
|
raise ValueError('Invalid coin for command')
|
||||||
|
return bytes(json.dumps(swap_client.ci(coin_type).getNewMwebAddress()), 'UTF-8')
|
||||||
|
|
||||||
raise ValueError('Unknown command')
|
raise ValueError('Unknown command')
|
||||||
|
|
||||||
|
if coin_type == Coins.LTC_MWEB:
|
||||||
|
coin_type = Coins.LTC
|
||||||
rv = swap_client.getWalletInfo(coin_type)
|
rv = swap_client.getWalletInfo(coin_type)
|
||||||
rv.update(swap_client.getBlockchainInfo(coin_type))
|
rv.update(swap_client.getBlockchainInfo(coin_type))
|
||||||
ci = swap_client.ci(coin_type)
|
ci = swap_client.ci(coin_type)
|
||||||
@ -647,7 +663,7 @@ def js_setpassword(self, url_split, post_string, is_json) -> bytes:
|
|||||||
if have_data_entry(post_data, 'coin'):
|
if have_data_entry(post_data, 'coin'):
|
||||||
# Set password for one coin
|
# Set password for one coin
|
||||||
coin = getCoinType(get_data_entry(post_data, 'coin'))
|
coin = getCoinType(get_data_entry(post_data, 'coin'))
|
||||||
if coin in (Coins.PART_ANON, Coins.PART_BLIND):
|
if coin in (Coins.PART_ANON, Coins.PART_BLIND, Coins.LTC_MWEB):
|
||||||
raise ValueError('Invalid coin.')
|
raise ValueError('Invalid coin.')
|
||||||
swap_client.changeWalletPasswords(old_password, new_password, coin)
|
swap_client.changeWalletPasswords(old_password, new_password, coin)
|
||||||
return bytes(json.dumps({'success': True}), 'UTF-8')
|
return bytes(json.dumps({'success': True}), 'UTF-8')
|
||||||
|
12
basicswap/templates/style.html
Normal file
12
basicswap/templates/style.html
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{% set select_box_arrow_svg = '<svg class="absolute right-4 top-1/2 transform -translate-y-1/2" width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M11.3333 6.1133C11.2084 5.98913 11.0395 5.91943 10.8633 5.91943C10.6872 5.91943 10.5182 5.98913 10.3933 6.1133L8.00001 8.47329L5.64001 6.1133C5.5151 5.98913 5.34613 5.91943 5.17001 5.91943C4.99388 5.91943 4.82491 5.98913 4.70001 6.1133C4.63752 6.17527 4.58792 6.249 4.55408 6.33024C4.52023 6.41148 4.50281 6.49862 4.50281 6.58663C4.50281 6.67464 4.52023 6.76177 4.55408 6.84301C4.58792 6.92425 4.63752 6.99799 4.70001 7.05996L7.52667 9.88663C7.58865 9.94911 7.66238 9.99871 7.74362 10.0326C7.82486 10.0664 7.912 10.0838 8.00001 10.0838C8.08801 10.0838 8.17515 10.0664 8.25639 10.0326C8.33763 9.99871 8.41136 9.94911 8.47334 9.88663L11.3333 7.05996C11.3958 6.99799 11.4454 6.92425 11.4793 6.84301C11.5131 6.76177 11.5305 6.67464 11.5305 6.58663C11.5305 6.49862 11.5131 6.41148 11.4793 6.33024C11.4454 6.249 11.3958 6.17527 11.3333 6.1133Z" fill="#8896AB"></path>
|
||||||
|
</svg>' %}
|
||||||
|
|
||||||
|
{% set select_box_class = 'hover:border-blue-500 bg-gray-50 text-gray-900 appearance-none pr-10 dark:bg-gray-500 dark:text-white border border-gray-300 dark:border-gray-400 dark:text-gray-50 dark:placeholder-white text-sm rounded-lg outline-none focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 focus:ring-0' %}
|
||||||
|
|
||||||
|
{% set circular_arrows_svg = '<svg class="text-gray-500 w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24">
|
||||||
|
<g fill="#ffffff" class="nc-icon-wrapper">
|
||||||
|
<path fill="#ffffff" d="M12,3c1.989,0,3.873,0.65,5.43,1.833l-3.604,3.393l9.167,0.983L22.562,0l-3.655,3.442 C16.957,1.862,14.545,1,12,1C5.935,1,1,5.935,1,12h2C3,7.037,7.037,3,12,3z"></path>
|
||||||
|
<path data-color="color-2" d="M12,21c-1.989,0-3.873-0.65-5.43-1.833l3.604-3.393l-9.167-0.983L1.438,24l3.655-3.442 C7.043,22.138,9.455,23,12,23c6.065,0,11-4.935,11-11h-2C21,16.963,16.963,21,12,21z"></path>
|
||||||
|
</g>
|
||||||
|
</svg>' %}
|
@ -1,4 +1,6 @@
|
|||||||
{% include 'header.html' %}
|
{% include 'header.html' %}
|
||||||
|
{% from 'style.html' import select_box_arrow_svg, select_box_class, circular_arrows_svg %}
|
||||||
|
|
||||||
<div class="container mx-auto">
|
<div class="container mx-auto">
|
||||||
<section class="p-5 mt-5">
|
<section class="p-5 mt-5">
|
||||||
<div class="flex flex-wrap items-center -m-2">
|
<div class="flex flex-wrap items-center -m-2">
|
||||||
@ -47,12 +49,7 @@
|
|||||||
<div class="w-full md:w-1/2 p-3 p-6 container flex flex-wrap items-center justify-end items-center mx-auto">
|
<div class="w-full md:w-1/2 p-3 p-6 container flex flex-wrap items-center justify-end items-center mx-auto">
|
||||||
<a class="w-full md:w-1/2 p-3 p-6 container flex flex-wrap items-center justify-end items-center mx-auto">
|
<a class="w-full md:w-1/2 p-3 p-6 container flex flex-wrap items-center justify-end items-center mx-auto">
|
||||||
<a class="mr-5 flex flex-wrap justify-center px-5 py-3 bg-blue-500 hover:bg-blue-600 font-medium text-sm text-white border dark:bg-gray-500 dark:hover:bg-gray-700 border-blue-500 rounded-md shadow-button focus:ring-0 focus:outline-none" id="refresh" href="/wallet/{{ w.ticker }}">
|
<a class="mr-5 flex flex-wrap justify-center px-5 py-3 bg-blue-500 hover:bg-blue-600 font-medium text-sm text-white border dark:bg-gray-500 dark:hover:bg-gray-700 border-blue-500 rounded-md shadow-button focus:ring-0 focus:outline-none" id="refresh" href="/wallet/{{ w.ticker }}">
|
||||||
<svg class="text-gray-500 w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24">
|
{{ circular_arrows_svg }}
|
||||||
<g fill="#ffffff" class="nc-icon-wrapper">
|
|
||||||
<path fill="#ffffff" d="M12,3c1.989,0,3.873,0.65,5.43,1.833l-3.604,3.393l9.167,0.983L22.562,0l-3.655,3.442 C16.957,1.862,14.545,1,12,1C5.935,1,1,5.935,1,12h2C3,7.037,7.037,3,12,3z"></path>
|
|
||||||
<path data-color="color-2" d="M12,21c-1.989,0-3.873-0.65-5.43-1.833l3.604-3.393l-9.167-0.983L1.438,24l3.655-3.442 C7.043,22.138,9.455,23,12,23c6.065,0,11-4.935,11-11h-2C21,16.963,16.963,21,12,21z"></path>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
<span>Refresh</span>
|
<span>Refresh</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@ -165,7 +162,7 @@
|
|||||||
</td>
|
</td>
|
||||||
<td class="py-3 px-6 bold coinname-value" data-coinname="{{ w.name }}">{{ w.balance }} {{ w.ticker }} (<span class="usd-value"></span>){% if w.unconfirmed %} <span class="inline-block py-1 px-2 rounded-full bg-green-100 text-green-500 dark:bg-gray-500 dark:text-green-500">Unconfirmed: +{{ w.unconfirmed }} {{ w.ticker }}</span>{% endif %}</td>
|
<td class="py-3 px-6 bold coinname-value" data-coinname="{{ w.name }}">{{ w.balance }} {{ w.ticker }} (<span class="usd-value"></span>){% if w.unconfirmed %} <span class="inline-block py-1 px-2 rounded-full bg-green-100 text-green-500 dark:bg-gray-500 dark:text-green-500">Unconfirmed: +{{ w.unconfirmed }} {{ w.ticker }}</span>{% endif %}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% if w.cid == '1' %}
|
{% if w.cid == '1' %} {# PART #}
|
||||||
<tr class="opacity-100 text-gray-500 dark:text-gray-100 hover:bg-coolGray-200 dark:hover:bg-gray-600">
|
<tr class="opacity-100 text-gray-500 dark:text-gray-100 hover:bg-coolGray-200 dark:hover:bg-gray-600">
|
||||||
<td class="py-3 px-6 bold">
|
<td class="py-3 px-6 bold">
|
||||||
<span class="inline-flex align-middle items-center justify-center w-9 h-10 bg-white-50 rounded">
|
<span class="inline-flex align-middle items-center justify-center w-9 h-10 bg-white-50 rounded">
|
||||||
@ -180,9 +177,21 @@
|
|||||||
<img class="h-7" src="/static/images/coins/{{ w.name }}.png" alt="{{ w.name }} Anon">
|
<img class="h-7" src="/static/images/coins/{{ w.name }}.png" alt="{{ w.name }} Anon">
|
||||||
</span>Anon Balance:
|
</span>Anon Balance:
|
||||||
</td>
|
</td>
|
||||||
<td class="py-3 px-6 bold coinname-value" data-coinname="{{ w.name }}">{{ w.anon_balance }} {{ w.ticker }} (<span class="usd-value"></span>) {% if w.anon_pending %} <span class="inline-block py-1 px-2 rounded-full bg-green-100 text-green-500 dark:bg-gray-500 dark:text-green-500">Pending: +{{ w.anon_pending }} {{ w.ticker }}</span>{% endif %}</td>
|
<td class="py-3 px-6 bold coinname-value" data-coinname="{{ w.name }}">{{ w.anon_balance }} {{ w.ticker }} (<span class="usd-value"></span>) {% if w.anon_pending %} <span class="inline-block py-1 px-2 rounded-full bg-green-100 text-green-500 dark:bg-gray-500 dark:text-green-500">Pending: +{{ w.anon_pending }} {{ w.ticker }}</span>{% endif %}</td>
|
||||||
<td class="usd-value"></td>
|
<td class="usd-value"></td>
|
||||||
</tr> {% endif %} <tr class="opacity-100 text-gray-500 dark:text-gray-100 hover:bg-coolGray-200 dark:hover:bg-gray-600">
|
</tr>
|
||||||
|
{% endif %} {# / PART #}
|
||||||
|
{% if w.cid == '3' %} {# LTC #}
|
||||||
|
<tr class="opacity-100 text-gray-500 dark:text-gray-100 hover:bg-coolGray-200 dark:hover:bg-gray-600">
|
||||||
|
<td class="py-3 px-6 bold">
|
||||||
|
<span class="inline-flex align-middle items-center justify-center w-9 h-10 bg-white-50 rounded">
|
||||||
|
<img class="h-7" src="/static/images/coins/{{ w.name }}.png" alt="{{ w.name }} MWEB">
|
||||||
|
</span>MWEB Balance:
|
||||||
|
</td>
|
||||||
|
<td class="py-3 px-6 bold coinname-value" data-coinname="{{ w.name }}">{{ w.mweb_balance }} {{ w.ticker }} (<span class="usd-value"></span>) {% if w.mweb_pending %} <span class="inline-block py-1 px-2 rounded-full bg-green-100 text-green-500 dark:bg-gray-500 dark:text-green-500">Pending: +{{ w.mweb_pending }} {{ w.ticker }}</span>{% endif %}</td>
|
||||||
|
</tr>
|
||||||
|
{% endif %} {# / LTC #}
|
||||||
|
<tr class="opacity-100 text-gray-500 dark:text-gray-100 hover:bg-coolGray-200 dark:hover:bg-gray-600">
|
||||||
<td class="py-3 px-6 bold">Blocks:</td>
|
<td class="py-3 px-6 bold">Blocks:</td>
|
||||||
<td class="py-3 px-6">{{ w.blocks }} {% if w.known_block_count %} / {{ w.known_block_count }} {% endif %}</td>
|
<td class="py-3 px-6">{{ w.blocks }} {% if w.known_block_count %} / {{ w.known_block_count }} {% endif %}</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -192,13 +201,13 @@
|
|||||||
</tr> {% if w.bootstrapping %} <tr class="opacity-100 text-gray-500 dark:text-gray-100 hover:bg-coolGray-200 dark:hover:bg-gray-600">
|
</tr> {% if w.bootstrapping %} <tr class="opacity-100 text-gray-500 dark:text-gray-100 hover:bg-coolGray-200 dark:hover:bg-gray-600">
|
||||||
<td class="py-3 px-6 bold">Bootstrapping:</td>
|
<td class="py-3 px-6 bold">Bootstrapping:</td>
|
||||||
<td class="py-3 px-6">{{ w.bootstrapping }}</td>
|
<td class="py-3 px-6">{{ w.bootstrapping }}</td>
|
||||||
</tr> {% endif %}
|
</tr> {% endif %} {# / bootstrapping #}
|
||||||
{% if w.encrypted %}
|
{% if w.encrypted %}
|
||||||
<tr class="opacity-100 text-gray-500 dark:text-gray-100 hover:bg-coolGray-200 dark:hover:bg-gray-600">
|
<tr class="opacity-100 text-gray-500 dark:text-gray-100 hover:bg-coolGray-200 dark:hover:bg-gray-600">
|
||||||
<td class="py-3 px-6 bold">Locked:</td>
|
<td class="py-3 px-6 bold">Locked:</td>
|
||||||
<td class="py-3 px-6">{{ w.locked }}</td>
|
<td class="py-3 px-6">{{ w.locked }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endif %}
|
{% endif %} {# / encrypted #}
|
||||||
<tr class="opacity-100 text-gray-500 dark:text-gray-100 hover:bg-coolGray-200 dark:hover:bg-gray-600">
|
<tr class="opacity-100 text-gray-500 dark:text-gray-100 hover:bg-coolGray-200 dark:hover:bg-gray-600">
|
||||||
<td class="py-3 px-6 bold">Expected Seed:</td>
|
<td class="py-3 px-6 bold">Expected Seed:</td>
|
||||||
<td class="py-3 px-6">{{ w.expected_seed }}</td> {% if block_unknown_seeds and w.expected_seed != true %} {# Only show addresses if wallet seed is correct #}
|
<td class="py-3 px-6">{{ w.expected_seed }}</td> {% if block_unknown_seeds and w.expected_seed != true %} {# Only show addresses if wallet seed is correct #}
|
||||||
@ -235,13 +244,22 @@
|
|||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
</tr>
|
</tr>
|
||||||
{% if w.cid == '1' %}
|
{% if w.cid == '1' %} {# PART #}
|
||||||
<tr class="opacity-100 text-gray-500 dark:text-gray-100 hover:bg-coolGray-200 dark:hover:bg-gray-600">
|
<tr class="opacity-100 text-gray-500 dark:text-gray-100 hover:bg-coolGray-200 dark:hover:bg-gray-600">
|
||||||
<td class="py-3 px-6 bold">Stealth Address</td>
|
<td class="py-3 px-6 bold">Stealth Address</td>
|
||||||
<td colspan=2 class="py-3 px-6 monospace bold select-all">{{ w.stealth_address }}</td>
|
<td colspan=2 class="py-3 px-6 monospace bold select-all">{{ w.stealth_address }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endif %}
|
{% endif %} {# / PART #}
|
||||||
{% if w.cid == '6' %}
|
{% if w.cid == '3' %} {# LTC #}
|
||||||
|
<tr class="opacity-100 text-gray-500 dark:text-gray-100 hover:bg-coolGray-200 dark:hover:bg-gray-600">
|
||||||
|
<td class="py-3 px-6 bold">
|
||||||
|
<button type="submit" class="flex flex-wrap justify-center py-2 px-4 bg-blue-500 hover:bg-blue-600 font-medium text-sm text-white border border-blue-500 rounded-md shadow-button focus:ring-0 focus:outline-none" name="newmwebaddr_{{ w.cid }}" value="New MWEB Address">
|
||||||
|
{{ circular_arrows_svg }} New MWEB Address</button>
|
||||||
|
</td>
|
||||||
|
<td colspan=2 class="py-3 px-6 monospace bold select-all">{{ w.mweb_address }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endif %} {# / LTC #}
|
||||||
|
{% if w.cid == '6' %} {# XMR #}
|
||||||
<tr class="opacity-100 text-gray-500 dark:text-gray-100 hover:bg-coolGray-200 dark:hover:bg-gray-600">
|
<tr class="opacity-100 text-gray-500 dark:text-gray-100 hover:bg-coolGray-200 dark:hover:bg-gray-600">
|
||||||
<td class="py-3 px-6 bold">Main Address</td>
|
<td class="py-3 px-6 bold">Main Address</td>
|
||||||
<td colspan=2 class="py-3 px-6 monospace bold select-all">{{ w.main_address }}</td>
|
<td colspan=2 class="py-3 px-6 monospace bold select-all">{{ w.main_address }}</td>
|
||||||
@ -249,12 +267,7 @@
|
|||||||
<tr class="opacity-100 text-gray-500 dark:text-gray-100 hover:bg-coolGray-200 dark:hover:bg-gray-600">
|
<tr class="opacity-100 text-gray-500 dark:text-gray-100 hover:bg-coolGray-200 dark:hover:bg-gray-600">
|
||||||
<td class="py-3 px-6 bold">
|
<td class="py-3 px-6 bold">
|
||||||
<button type="submit" class="flex flex-wrap justify-center py-2 px-4 bg-blue-500 hover:bg-blue-600 font-medium text-sm text-white border border-blue-500 rounded-md shadow-button focus:ring-0 focus:outline-none" name="newaddr_{{ w.cid }}" value="New Subaddress">
|
<button type="submit" class="flex flex-wrap justify-center py-2 px-4 bg-blue-500 hover:bg-blue-600 font-medium text-sm text-white border border-blue-500 rounded-md shadow-button focus:ring-0 focus:outline-none" name="newaddr_{{ w.cid }}" value="New Subaddress">
|
||||||
<svg class="text-gray-500 w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24">
|
{{ circular_arrows_svg }} New {{ w.ticker }} Sub Address </button>
|
||||||
<g fill="#ffffff" class="nc-icon-wrapper">
|
|
||||||
<path fill="#ffffff" d="M12,3c1.989,0,3.873,0.65,5.43,1.833l-3.604,3.393l9.167,0.983L22.562,0l-3.655,3.442 C16.957,1.862,14.545,1,12,1C5.935,1,1,5.935,1,12h2C3,7.037,7.037,3,12,3z"></path>
|
|
||||||
<path data-color="color-2" d="M12,21c-1.989,0-3.873-0.65-5.43-1.833l3.604-3.393l-9.167-0.983L1.438,24l3.655-3.442 C7.043,22.138,9.455,23,12,23c6.065,0,11-4.935,11-11h-2C21,16.963,16.963,21,12,21z"></path>
|
|
||||||
</g>
|
|
||||||
</svg> New {{ w.ticker }} Sub Address </button>
|
|
||||||
</td>
|
</td>
|
||||||
<td colspan=2 class="py-3 px-6 monospace select-all">{{ w.deposit_address }}</td>
|
<td colspan=2 class="py-3 px-6 monospace select-all">{{ w.deposit_address }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -262,12 +275,7 @@
|
|||||||
<tr class="opacity-100 text-gray-500 dark:text-gray-100 hover:bg-coolGray-200 dark:hover:bg-gray-600">
|
<tr class="opacity-100 text-gray-500 dark:text-gray-100 hover:bg-coolGray-200 dark:hover:bg-gray-600">
|
||||||
<td class="py-3 px-6 bold">
|
<td class="py-3 px-6 bold">
|
||||||
<button type="submit" class="flex flex-wrap justify-center py-2 px-4 bg-blue-500 hover:bg-blue-600 font-medium text-sm text-white border border-blue-500 rounded-md shadow-button focus:ring-0 focus:outline-none" name="newaddr_{{ w.cid }}" value="New Deposit Address">
|
<button type="submit" class="flex flex-wrap justify-center py-2 px-4 bg-blue-500 hover:bg-blue-600 font-medium text-sm text-white border border-blue-500 rounded-md shadow-button focus:ring-0 focus:outline-none" name="newaddr_{{ w.cid }}" value="New Deposit Address">
|
||||||
<svg class="text-gray-500 w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24">
|
{{ circular_arrows_svg }} New {{ w.ticker }} Deposit Address</button>
|
||||||
<g fill="#ffffff" class="nc-icon-wrapper">
|
|
||||||
<path fill="#ffffff" d="M12,3c1.989,0,3.873,0.65,5.43,1.833l-3.604,3.393l9.167,0.983L22.562,0l-3.655,3.442 C16.957,1.862,14.545,1,12,1C5.935,1,1,5.935,1,12h2C3,7.037,7.037,3,12,3z"></path>
|
|
||||||
<path data-color="color-2" d="M12,21c-1.989,0-3.873-0.65-5.43-1.833l3.604-3.393l-9.167-0.983L1.438,24l3.655-3.442 C7.043,22.138,9.455,23,12,23c6.065,0,11-4.935,11-11h-2C21,16.963,16.963,21,12,21z"></path>
|
|
||||||
</g>
|
|
||||||
</svg>New {{ w.ticker }} Deposit Address</button>
|
|
||||||
</td>
|
</td>
|
||||||
<td colspan=2 class="py-3 px-6 monospace bold select-all" id="deposit_address">{{ w.deposit_address }}</td>
|
<td colspan=2 class="py-3 px-6 monospace bold select-all" id="deposit_address">{{ w.deposit_address }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -342,16 +350,14 @@
|
|||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% if w.cid == '1' %}
|
{% if w.cid == '1' %} {# PART #}
|
||||||
<tr class="opacity-100 text-gray-500 dark:text-gray-100">
|
<tr class="opacity-100 text-gray-500 dark:text-gray-100">
|
||||||
<td class="py-3 px-6 bold">Type From -> To:</td>
|
<td class="py-3 px-6 bold">Type From -> To:</td>
|
||||||
<td class="py-3 px-6">
|
<td class="py-3 px-6">
|
||||||
<div class="w-full md:flex-1">
|
<div class="w-full md:flex-1">
|
||||||
<div class="relative">
|
<div class="relative">
|
||||||
<svg class="absolute right-4 top-1/2 transform -translate-y-1/2" width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
{{ select_box_arrow_svg }}
|
||||||
<path d="M11.3333 6.1133C11.2084 5.98913 11.0395 5.91943 10.8633 5.91943C10.6872 5.91943 10.5182 5.98913 10.3933 6.1133L8.00001 8.47329L5.64001 6.1133C5.5151 5.98913 5.34613 5.91943 5.17001 5.91943C4.99388 5.91943 4.82491 5.98913 4.70001 6.1133C4.63752 6.17527 4.58792 6.249 4.55408 6.33024C4.52023 6.41148 4.50281 6.49862 4.50281 6.58663C4.50281 6.67464 4.52023 6.76177 4.55408 6.84301C4.58792 6.92425 4.63752 6.99799 4.70001 7.05996L7.52667 9.88663C7.58865 9.94911 7.66238 9.99871 7.74362 10.0326C7.82486 10.0664 7.912 10.0838 8.00001 10.0838C8.08801 10.0838 8.17515 10.0664 8.25639 10.0326C8.33763 9.99871 8.41136 9.94911 8.47334 9.88663L11.3333 7.05996C11.3958 6.99799 11.4454 6.92425 11.4793 6.84301C11.5131 6.76177 11.5305 6.67464 11.5305 6.58663C11.5305 6.49862 11.5131 6.41148 11.4793 6.33024C11.4454 6.249 11.3958 6.17527 11.3333 6.1133Z" fill="#8896AB"></path>
|
<select class="{{ select_box_class }}" name="withdraw_type_from_{{ w.cid }}">
|
||||||
</svg>
|
|
||||||
<select class="hover:border-blue-500 bg-gray-50 text-gray-900 appearance-none pr-10 dark:bg-gray-500 dark:text-white border border-gray-300 dark:border-gray-400 dark:text-gray-50 dark:placeholder-white text-sm rounded-lg outline-none focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 focus:ring-0" name="withdraw_type_from_{{ w.cid }}">
|
|
||||||
<option value="plain" {% if w.wd_type_from=='plain' %} selected{% endif %}>Plain</option>
|
<option value="plain" {% if w.wd_type_from=='plain' %} selected{% endif %}>Plain</option>
|
||||||
<option value="blind" {% if w.wd_type_from=='blind' %} selected{% endif %}>Blind</option>
|
<option value="blind" {% if w.wd_type_from=='blind' %} selected{% endif %}>Blind</option>
|
||||||
<option value="anon" {% if w.wd_type_from=='anon' %} selected{% endif %}>Anon</option>
|
<option value="anon" {% if w.wd_type_from=='anon' %} selected{% endif %}>Anon</option>
|
||||||
@ -362,10 +368,8 @@
|
|||||||
<td class="py-3 px-6">
|
<td class="py-3 px-6">
|
||||||
<div class="w-full md:flex-1">
|
<div class="w-full md:flex-1">
|
||||||
<div class="relative">
|
<div class="relative">
|
||||||
<svg class="absolute right-4 top-1/2 transform -translate-y-1/2" width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
{{ select_box_arrow_svg }}
|
||||||
<path d="M11.3333 6.1133C11.2084 5.98913 11.0395 5.91943 10.8633 5.91943C10.6872 5.91943 10.5182 5.98913 10.3933 6.1133L8.00001 8.47329L5.64001 6.1133C5.5151 5.98913 5.34613 5.91943 5.17001 5.91943C4.99388 5.91943 4.82491 5.98913 4.70001 6.1133C4.63752 6.17527 4.58792 6.249 4.55408 6.33024C4.52023 6.41148 4.50281 6.49862 4.50281 6.58663C4.50281 6.67464 4.52023 6.76177 4.55408 6.84301C4.58792 6.92425 4.63752 6.99799 4.70001 7.05996L7.52667 9.88663C7.58865 9.94911 7.66238 9.99871 7.74362 10.0326C7.82486 10.0664 7.912 10.0838 8.00001 10.0838C8.08801 10.0838 8.17515 10.0664 8.25639 10.0326C8.33763 9.99871 8.41136 9.94911 8.47334 9.88663L11.3333 7.05996C11.3958 6.99799 11.4454 6.92425 11.4793 6.84301C11.5131 6.76177 11.5305 6.67464 11.5305 6.58663C11.5305 6.49862 11.5131 6.41148 11.4793 6.33024C11.4454 6.249 11.3958 6.17527 11.3333 6.1133Z" fill="#8896AB"></path>
|
<select class="{{ select_box_class }}" name="withdraw_type_to_{{ w.cid }}">
|
||||||
</svg>
|
|
||||||
<select class="hover:border-blue-500 bg-gray-50 text-gray-900 appearance-none pr-10 dark:bg-gray-500 dark:text-white border border-gray-300 dark:border-gray-400 dark:text-gray-50 dark:placeholder-white text-sm rounded-lg outline-none focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 focus:ring-0" name="withdraw_type_to_{{ w.cid }}">
|
|
||||||
<option value="plain" {% if w.wd_type_to=='plain' %} selected{% endif %}>Plain</option>
|
<option value="plain" {% if w.wd_type_to=='plain' %} selected{% endif %}>Plain</option>
|
||||||
<option value="blind" {% if w.wd_type_to=='blind' %} selected{% endif %}>Blind</option>
|
<option value="blind" {% if w.wd_type_to=='blind' %} selected{% endif %}>Blind</option>
|
||||||
<option value="anon" {% if w.wd_type_to=='anon' %} selected{% endif %}>Anon</option>
|
<option value="anon" {% if w.wd_type_to=='anon' %} selected{% endif %}>Anon</option>
|
||||||
@ -374,7 +378,23 @@
|
|||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endif %}
|
{% endif %} {# / PART #}
|
||||||
|
{% if w.cid == '3' %} {# LTC #}
|
||||||
|
<tr class="opacity-100 text-gray-500 dark:text-gray-100">
|
||||||
|
<td class="py-3 px-6 bold">Type From:</td>
|
||||||
|
<td class="py-3 px-6">
|
||||||
|
<div class="w-full md:flex-1">
|
||||||
|
<div class="relative">
|
||||||
|
{{ select_box_arrow_svg }}
|
||||||
|
<select class="{{ select_box_class }}" name="withdraw_type_from_{{ w.cid }}">
|
||||||
|
<option value="plain" {% if w.wd_type_from=='plain' %} selected{% endif %}>Plain</option>
|
||||||
|
<option value="mweb" {% if w.wd_type_from=='mweb' %} selected{% endif %}>MWEB</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endif %} {# / LTC #}
|
||||||
<tr class="opacity-100 text-gray-500 dark:text-gray-100 hover:bg-coolGray-200 dark:hover:bg-gray-600">
|
<tr class="opacity-100 text-gray-500 dark:text-gray-100 hover:bg-coolGray-200 dark:hover:bg-gray-600">
|
||||||
<td class="py-3 px-6 bold">Fee Rate:</td>
|
<td class="py-3 px-6 bold">Fee Rate:</td>
|
||||||
<td class="py-3 px-6 bold">{{ w.fee_rate }}</td>
|
<td class="py-3 px-6 bold">{{ w.fee_rate }}</td>
|
||||||
@ -392,7 +412,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
{% if w.cid != '6' %}
|
{% if w.cid != '6' %} {# !XMR #}
|
||||||
{% if w.show_utxo_groups %}
|
{% if w.show_utxo_groups %}
|
||||||
<section class="p-6">
|
<section class="p-6">
|
||||||
<div class="flex flex-wrap items-center">
|
<div class="flex flex-wrap items-center">
|
||||||
@ -647,4 +667,4 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -113,7 +113,7 @@
|
|||||||
<div class="bold inline-block py-1 px-2 rounded-full bg-green-100 text-xs text-green-500 dark:bg-gray-500 dark:text-green-500 usd-value"></div>
|
<div class="bold inline-block py-1 px-2 rounded-full bg-green-100 text-xs text-green-500 dark:bg-gray-500 dark:text-green-500 usd-value"></div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if w.cid == '1' %}
|
{% if w.cid == '1' %} {# PART #}
|
||||||
<div class="flex mb-2 justify-between items-center">
|
<div class="flex mb-2 justify-between items-center">
|
||||||
<h4 class="text-xs font-medium dark:text-white">Blind Balance:</h4>
|
<h4 class="text-xs font-medium dark:text-white">Blind Balance:</h4>
|
||||||
<span class="bold inline-block py-1 px-2 rounded-full bg-blue-100 text-xs text-black-500 dark:bg-gray-500 dark:text-gray-200 coinname-value" data-coinname="{{ w.name }}">{{ w.blind_balance }} {{ w.ticker }}</span>
|
<span class="bold inline-block py-1 px-2 rounded-full bg-blue-100 text-xs text-black-500 dark:bg-gray-500 dark:text-gray-200 coinname-value" data-coinname="{{ w.name }}">{{ w.blind_balance }} {{ w.ticker }}</span>
|
||||||
@ -130,7 +130,7 @@
|
|||||||
<div class="flex mb-2 justify-between items-center">
|
<div class="flex mb-2 justify-between items-center">
|
||||||
<h4 class="text-xs font-bold text-green-500 dark:text-green-500">Blind Unconfirmed USD value:</h4>
|
<h4 class="text-xs font-bold text-green-500 dark:text-green-500">Blind Unconfirmed USD value:</h4>
|
||||||
<div class="bold inline-block py-1 px-2 rounded-full bg-green-100 text-xs text-green-500 dark:bg-gray-500 dark:text-green-500 usd-value"></div>
|
<div class="bold inline-block py-1 px-2 rounded-full bg-green-100 text-xs text-green-500 dark:bg-gray-500 dark:text-green-500 usd-value"></div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="flex mb-2 justify-between items-center">
|
<div class="flex mb-2 justify-between items-center">
|
||||||
<h4 class="text-xs font-medium dark:text-white">Anon Balance:</h4>
|
<h4 class="text-xs font-medium dark:text-white">Anon Balance:</h4>
|
||||||
@ -149,9 +149,30 @@
|
|||||||
<div class="flex mb-2 justify-between items-center">
|
<div class="flex mb-2 justify-between items-center">
|
||||||
<h4 class="text-xs font-bold text-green-500 dark:text-green-500">Anon Pending USD value:</h4>
|
<h4 class="text-xs font-bold text-green-500 dark:text-green-500">Anon Pending USD value:</h4>
|
||||||
<div class="bold inline-block py-1 px-2 rounded-full bg-green-100 text-xs text-green-500 dark:bg-gray-500 dark:text-green-500 usd-value"></div>
|
<div class="bold inline-block py-1 px-2 rounded-full bg-green-100 text-xs text-green-500 dark:bg-gray-500 dark:text-green-500 usd-value"></div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endif %} {# / PART #}
|
||||||
|
{% if w.cid == '3' %} {# LTC #}
|
||||||
|
<div class="flex mb-2 justify-between items-center">
|
||||||
|
<h4 class="text-xs font-medium dark:text-white">MWEB Balance:</h4>
|
||||||
|
<span class="bold inline-block py-1 px-2 rounded-full bg-blue-100 text-xs text-black-500 dark:bg-gray-500 dark:text-gray-200 coinname-value" data-coinname="{{ w.name }}">{{ w.mweb_balance }} {{ w.ticker }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex mb-2 justify-between items-center">
|
||||||
|
<h4 class="text-xs font-medium dark:text-white">MWEB USD value:</h4>
|
||||||
|
<div class="bold inline-block py-1 px-2 rounded-full bg-blue-100 text-xs text-black-500 dark:bg-gray-500 dark:text-gray-200 usd-value"></div>
|
||||||
|
</div>
|
||||||
|
{% if w.mweb_pending %}
|
||||||
|
<div class="flex mb-2 justify-between items-center">
|
||||||
|
<h4 class="text-xs font-bold text-green-500 dark:text-green-500">MWEB Pending:</h4>
|
||||||
|
<span class="bold inline-block py-1 px-2 rounded-full bg-green-100 text-xs text-green-500 dark:bg-gray-500 dark:text-green-500 coinname-value" data-coinname="{{ w.name }}">
|
||||||
|
+{{ w.mweb_pending }} {{ w.ticker }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex mb-2 justify-between items-center">
|
||||||
|
<h4 class="text-xs font-bold text-green-500 dark:text-green-500">MWEB Pending USD value:</h4>
|
||||||
|
<div class="bold inline-block py-1 px-2 rounded-full bg-green-100 text-xs text-green-500 dark:bg-gray-500 dark:text-green-500 usd-value"></div>
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endif %} {# / LTC #}
|
||||||
<div class="flex mb-2 justify-between items-center">
|
<div class="flex mb-2 justify-between items-center">
|
||||||
<h4 class="text-xs font-medium dark:text-white">Blocks:</h4>
|
<h4 class="text-xs font-medium dark:text-white">Blocks:</h4>
|
||||||
<span class="inline-block py-1 px-2 rounded-full bg-blue-100 text-xs text-black-500 dark:bg-gray-500 dark:text-gray-200">{{ w.blocks }}{% if w.known_block_count %} / {{ w.known_block_count }}{% endif %}</span>
|
<span class="inline-block py-1 px-2 rounded-full bg-blue-100 text-xs text-black-500 dark:bg-gray-500 dark:text-gray-200">{{ w.blocks }}{% if w.known_block_count %} / {{ w.known_block_count }}{% endif %}</span>
|
||||||
@ -409,4 +430,4 @@ window.onload = async () => {
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -51,12 +51,16 @@ def format_wallet_data(swap_client, ci, w):
|
|||||||
|
|
||||||
if ci.coin_type() == Coins.PART:
|
if ci.coin_type() == Coins.PART:
|
||||||
wf['stealth_address'] = w.get('stealth_address', '?')
|
wf['stealth_address'] = w.get('stealth_address', '?')
|
||||||
wf['blind_balance'] = "{:.8f}".format(float(w['blind_balance']))
|
wf['blind_balance'] = w.get('blind_balance', '?')
|
||||||
if 'blind_unconfirmed' in w and float(w['blind_unconfirmed']) > 0.0:
|
if 'blind_unconfirmed' in w and float(w['blind_unconfirmed']) > 0.0:
|
||||||
wf['blind_unconfirmed'] = w['blind_unconfirmed']
|
wf['blind_unconfirmed'] = w['blind_unconfirmed']
|
||||||
wf['anon_balance'] = w.get('anon_balance', '?')
|
wf['anon_balance'] = w.get('anon_balance', '?')
|
||||||
if 'anon_pending' in w and float(w['anon_pending']) > 0.0:
|
if 'anon_pending' in w and float(w['anon_pending']) > 0.0:
|
||||||
wf['anon_pending'] = w['anon_pending']
|
wf['anon_pending'] = w['anon_pending']
|
||||||
|
elif ci.coin_type() == Coins.LTC:
|
||||||
|
wf['mweb_address'] = w.get('mweb_address', '?')
|
||||||
|
wf['mweb_balance'] = w.get('mweb_balance', '?')
|
||||||
|
wf['mweb_pending'] = w.get('mweb_pending', '?')
|
||||||
|
|
||||||
checkAddressesOwned(swap_client, ci, wf)
|
checkAddressesOwned(swap_client, ci, wf)
|
||||||
return wf
|
return wf
|
||||||
@ -128,6 +132,8 @@ def page_wallet(self, url_split, post_string):
|
|||||||
|
|
||||||
if bytes('newaddr_' + cid, 'utf-8') in form_data:
|
if bytes('newaddr_' + cid, 'utf-8') in form_data:
|
||||||
swap_client.cacheNewAddressForCoin(coin_id)
|
swap_client.cacheNewAddressForCoin(coin_id)
|
||||||
|
elif bytes('newmwebaddr_' + cid, 'utf-8') in form_data:
|
||||||
|
swap_client.cacheNewStealthAddressForCoin(coin_id)
|
||||||
elif bytes('reseed_' + cid, 'utf-8') in form_data:
|
elif bytes('reseed_' + cid, 'utf-8') in form_data:
|
||||||
try:
|
try:
|
||||||
swap_client.reseedWallet(coin_id)
|
swap_client.reseedWallet(coin_id)
|
||||||
@ -158,22 +164,28 @@ def page_wallet(self, url_split, post_string):
|
|||||||
page_data['wd_type_to_' + cid] = type_to
|
page_data['wd_type_to_' + cid] = type_to
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
err_messages.append('Missing type')
|
err_messages.append('Missing type')
|
||||||
|
elif coin_id == Coins.LTC:
|
||||||
|
try:
|
||||||
|
type_from = form_data[bytes('withdraw_type_from_' + cid, 'utf-8')][0].decode('utf-8')
|
||||||
|
page_data['wd_type_from_' + cid] = type_from
|
||||||
|
except Exception as e:
|
||||||
|
err_messages.append('Missing type')
|
||||||
|
|
||||||
if len(messages) == 0:
|
if len(messages) == 0:
|
||||||
ci = swap_client.ci(coin_id)
|
ci = swap_client.ci(coin_id)
|
||||||
ticker = ci.ticker()
|
ticker = ci.ticker()
|
||||||
if coin_id == Coins.PART:
|
try:
|
||||||
try:
|
if coin_id == Coins.PART:
|
||||||
txid = swap_client.withdrawParticl(type_from, type_to, value, address, subfee)
|
txid = swap_client.withdrawParticl(type_from, type_to, value, address, subfee)
|
||||||
messages.append('Withdrew {} {} ({} to {}) to address {}<br/>In txid: {}'.format(value, ticker, type_from, type_to, address, txid))
|
messages.append('Withdrew {} {} ({} to {}) to address {}<br/>In txid: {}'.format(value, ticker, type_from, type_to, address, txid))
|
||||||
except Exception as e:
|
elif coin_id == Coins.LTC:
|
||||||
err_messages.append(str(e))
|
txid = swap_client.withdrawLTC(type_from, value, address, subfee)
|
||||||
else:
|
messages.append('Withdrew {} {} (from {}) to address {}<br/>In txid: {}'.format(value, ticker, type_from, address, txid))
|
||||||
try:
|
else:
|
||||||
txid = swap_client.withdrawCoin(coin_id, value, address, subfee)
|
txid = swap_client.withdrawCoin(coin_id, value, address, subfee)
|
||||||
messages.append('Withdrew {} {} to address {}<br/>In txid: {}'.format(value, ticker, address, txid))
|
messages.append('Withdrew {} {} to address {}<br/>In txid: {}'.format(value, ticker, address, txid))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
err_messages.append(str(e))
|
err_messages.append(str(e))
|
||||||
swap_client.updateWalletsInfo(True, coin_id)
|
swap_client.updateWalletsInfo(True, coin_id)
|
||||||
elif have_data_entry(form_data, 'showutxogroups'):
|
elif have_data_entry(form_data, 'showutxogroups'):
|
||||||
show_utxo_groups = True
|
show_utxo_groups = True
|
||||||
@ -227,6 +239,8 @@ def page_wallet(self, url_split, post_string):
|
|||||||
|
|
||||||
if k == Coins.XMR:
|
if k == Coins.XMR:
|
||||||
wallet_data['main_address'] = w.get('main_address', 'Refresh necessary')
|
wallet_data['main_address'] = w.get('main_address', 'Refresh necessary')
|
||||||
|
elif k == Coins.LTC:
|
||||||
|
wallet_data['mweb_address'] = w.get('mweb_address', 'Refresh necessary')
|
||||||
|
|
||||||
if 'wd_type_from_' + cid in page_data:
|
if 'wd_type_from_' + cid in page_data:
|
||||||
wallet_data['wd_type_from'] = page_data['wd_type_from_' + cid]
|
wallet_data['wd_type_from'] = page_data['wd_type_from_' + cid]
|
||||||
|
@ -419,6 +419,8 @@ def getCoinName(c):
|
|||||||
return chainparams[Coins.PART]['name'].capitalize() + ' Anon'
|
return chainparams[Coins.PART]['name'].capitalize() + ' Anon'
|
||||||
if c == Coins.PART_BLIND:
|
if c == Coins.PART_BLIND:
|
||||||
return chainparams[Coins.PART]['name'].capitalize() + ' Blind'
|
return chainparams[Coins.PART]['name'].capitalize() + ' Blind'
|
||||||
|
if c == Coins.LTC_MWEB:
|
||||||
|
return chainparams[Coins.LTC]['name'].capitalize() + ' MWEB'
|
||||||
|
|
||||||
coin_chainparams = chainparams[c]
|
coin_chainparams = chainparams[c]
|
||||||
if coin_chainparams.get('use_ticker_as_name', False):
|
if coin_chainparams.get('use_ticker_as_name', False):
|
||||||
@ -441,6 +443,11 @@ def listAvailableCoins(swap_client, with_variants=True, split_from=False):
|
|||||||
coins.append((int(v), getCoinName(v)))
|
coins.append((int(v), getCoinName(v)))
|
||||||
if split_from and v not in invalid_coins_from:
|
if split_from and v not in invalid_coins_from:
|
||||||
coins_from.append(coins[-1])
|
coins_from.append(coins[-1])
|
||||||
|
if with_variants and k == Coins.LTC:
|
||||||
|
for v in (Coins.LTC_MWEB, ):
|
||||||
|
coins.append((int(v), getCoinName(v)))
|
||||||
|
if split_from and v not in invalid_coins_from:
|
||||||
|
coins_from.append(coins[-1])
|
||||||
if split_from:
|
if split_from:
|
||||||
return coins_from, coins
|
return coins_from, coins
|
||||||
return coins
|
return coins
|
||||||
|
@ -42,7 +42,7 @@ PARTICL_VERSION = os.getenv('PARTICL_VERSION', '23.2.7.0')
|
|||||||
PARTICL_VERSION_TAG = os.getenv('PARTICL_VERSION_TAG', '')
|
PARTICL_VERSION_TAG = os.getenv('PARTICL_VERSION_TAG', '')
|
||||||
PARTICL_LINUX_EXTRA = os.getenv('PARTICL_LINUX_EXTRA', 'nousb')
|
PARTICL_LINUX_EXTRA = os.getenv('PARTICL_LINUX_EXTRA', 'nousb')
|
||||||
|
|
||||||
LITECOIN_VERSION = os.getenv('LITECOIN_VERSION', '0.21.2')
|
LITECOIN_VERSION = os.getenv('LITECOIN_VERSION', '0.21.2.2')
|
||||||
LITECOIN_VERSION_TAG = os.getenv('LITECOIN_VERSION_TAG', '')
|
LITECOIN_VERSION_TAG = os.getenv('LITECOIN_VERSION_TAG', '')
|
||||||
|
|
||||||
BITCOIN_VERSION = os.getenv('BITCOIN_VERSION', '23.0')
|
BITCOIN_VERSION = os.getenv('BITCOIN_VERSION', '23.0')
|
||||||
@ -602,7 +602,7 @@ def prepareCore(coin, version_data, settings, data_dir, extra_opts={}):
|
|||||||
assert_url = 'https://raw.githubusercontent.com/particl/gitian.sigs/master/%s-%s/%s/%s' % (version + version_tag, os_dir_name, signing_key_name, assert_filename)
|
assert_url = 'https://raw.githubusercontent.com/particl/gitian.sigs/master/%s-%s/%s/%s' % (version + version_tag, os_dir_name, signing_key_name, assert_filename)
|
||||||
elif coin == 'litecoin':
|
elif coin == 'litecoin':
|
||||||
release_url = 'https://download.litecoin.org/litecoin-{}/{}/{}'.format(version, os_name, release_filename)
|
release_url = 'https://download.litecoin.org/litecoin-{}/{}/{}'.format(version, os_name, release_filename)
|
||||||
assert_filename = '{}-core-{}-{}-build.assert'.format(coin, os_name, version.rsplit('.', 1)[0])
|
assert_filename = '{}-core-{}-{}-build.assert'.format(coin, os_name, '.'.join(version.split('.')[:2]))
|
||||||
assert_url = 'https://raw.githubusercontent.com/litecoin-project/gitian.sigs.ltc/master/%s-%s/%s/%s' % (version, os_dir_name, signing_key_name, assert_filename)
|
assert_url = 'https://raw.githubusercontent.com/litecoin-project/gitian.sigs.ltc/master/%s-%s/%s/%s' % (version, os_dir_name, signing_key_name, assert_filename)
|
||||||
elif coin == 'bitcoin':
|
elif coin == 'bitcoin':
|
||||||
release_url = 'https://bitcoincore.org/bin/bitcoin-core-{}/{}'.format(version, release_filename)
|
release_url = 'https://bitcoincore.org/bin/bitcoin-core-{}/{}'.format(version, release_filename)
|
||||||
@ -1141,6 +1141,12 @@ def test_particl_encryption(data_dir, settings, chain, use_tor_proxy):
|
|||||||
finalise_daemon(d)
|
finalise_daemon(d)
|
||||||
|
|
||||||
|
|
||||||
|
def encrypt_wallet(swap_client, coin_type) -> None:
|
||||||
|
ci = swap_client.ci(coin_type)
|
||||||
|
ci.changeWalletPassword('', WALLET_ENCRYPTION_PWD)
|
||||||
|
ci.unlockWallet(WALLET_ENCRYPTION_PWD)
|
||||||
|
|
||||||
|
|
||||||
def initialise_wallets(particl_wallet_mnemonic, with_coins, data_dir, settings, chain, use_tor_proxy):
|
def initialise_wallets(particl_wallet_mnemonic, with_coins, data_dir, settings, chain, use_tor_proxy):
|
||||||
swap_client = None
|
swap_client = None
|
||||||
daemons = []
|
daemons = []
|
||||||
@ -1185,16 +1191,18 @@ def initialise_wallets(particl_wallet_mnemonic, with_coins, data_dir, settings,
|
|||||||
if len(wallets) < 1:
|
if len(wallets) < 1:
|
||||||
logger.info('Creating wallet.dat for {}.'.format(getCoinName(c)))
|
logger.info('Creating wallet.dat for {}.'.format(getCoinName(c)))
|
||||||
|
|
||||||
if c == Coins.BTC:
|
if c in (Coins.BTC, Coins.LTC):
|
||||||
# wallet_name, disable_private_keys, blank, passphrase, avoid_reuse, descriptors
|
# wallet_name, disable_private_keys, blank, passphrase, avoid_reuse, descriptors
|
||||||
swap_client.callcoinrpc(c, 'createwallet', ['wallet.dat', False, True, '', False, False])
|
swap_client.callcoinrpc(c, 'createwallet', ['wallet.dat', False, True, WALLET_ENCRYPTION_PWD, False, False])
|
||||||
|
swap_client.ci(c).unlockWallet(WALLET_ENCRYPTION_PWD)
|
||||||
else:
|
else:
|
||||||
swap_client.callcoinrpc(c, 'createwallet', ['wallet.dat'])
|
swap_client.callcoinrpc(c, 'createwallet', ['wallet.dat'])
|
||||||
|
if WALLET_ENCRYPTION_PWD != '':
|
||||||
|
encrypt_wallet(swap_client, c)
|
||||||
|
|
||||||
if WALLET_ENCRYPTION_PWD != '':
|
if c == Coins.LTC:
|
||||||
ci = swap_client.ci(c)
|
password = WALLET_ENCRYPTION_PWD if WALLET_ENCRYPTION_PWD != '' else None
|
||||||
ci.changeWalletPassword('', WALLET_ENCRYPTION_PWD)
|
swap_client.ci(Coins.LTC_MWEB).init_wallet(password)
|
||||||
ci.unlockWallet(WALLET_ENCRYPTION_PWD)
|
|
||||||
|
|
||||||
if c == Coins.PART:
|
if c == Coins.PART:
|
||||||
if 'particl' in with_coins:
|
if 'particl' in with_coins:
|
||||||
|
@ -1,3 +1,11 @@
|
|||||||
|
|
||||||
|
0.12.4
|
||||||
|
==============
|
||||||
|
|
||||||
|
- LTC creates a new wallet to hold MWEB balance.
|
||||||
|
- MWEB wallet should be be automatically created at startup or when unlocked if system is encrypted.
|
||||||
|
|
||||||
|
|
||||||
0.12.3
|
0.12.3
|
||||||
==============
|
==============
|
||||||
|
|
||||||
|
@ -672,7 +672,7 @@ class Test(unittest.TestCase):
|
|||||||
# Verify expected inputs were used
|
# Verify expected inputs were used
|
||||||
bid, offer = swap_clients[2].getBidAndOffer(bid_id)
|
bid, offer = swap_clients[2].getBidAndOffer(bid_id)
|
||||||
assert (bid.initiate_tx)
|
assert (bid.initiate_tx)
|
||||||
wtx = ci_from.rpc_callback('gettransaction', [bid.initiate_tx.txid.hex(),])
|
wtx = ci_from.rpc_wallet('gettransaction', [bid.initiate_tx.txid.hex(),])
|
||||||
itx_after = ci_from.describeTx(wtx['hex'])
|
itx_after = ci_from.describeTx(wtx['hex'])
|
||||||
assert (len(itx_after['vin']) == len(itx_decoded['vin']))
|
assert (len(itx_after['vin']) == len(itx_decoded['vin']))
|
||||||
for i, txin in enumerate(itx_decoded['vin']):
|
for i, txin in enumerate(itx_decoded['vin']):
|
||||||
|
@ -902,7 +902,7 @@ class Test(TestFunctions):
|
|||||||
# Verify expected inputs were used
|
# Verify expected inputs were used
|
||||||
bid, offer = swap_clients[2].getBidAndOffer(bid_id)
|
bid, offer = swap_clients[2].getBidAndOffer(bid_id)
|
||||||
assert (bid.initiate_tx)
|
assert (bid.initiate_tx)
|
||||||
wtx = ci_from.rpc_callback('gettransaction', [bid.initiate_tx.txid.hex(),])
|
wtx = ci_from.rpc('gettransaction', [bid.initiate_tx.txid.hex(),])
|
||||||
itx_after = ci_from.describeTx(wtx['hex'])
|
itx_after = ci_from.describeTx(wtx['hex'])
|
||||||
assert (len(itx_after['vin']) == len(itx_decoded['vin']))
|
assert (len(itx_after['vin']) == len(itx_decoded['vin']))
|
||||||
for i, txin in enumerate(itx_decoded['vin']):
|
for i, txin in enumerate(itx_decoded['vin']):
|
||||||
|
@ -677,7 +677,7 @@ class Test(unittest.TestCase):
|
|||||||
# Verify expected inputs were used
|
# Verify expected inputs were used
|
||||||
bid, offer = swap_clients[2].getBidAndOffer(bid_id)
|
bid, offer = swap_clients[2].getBidAndOffer(bid_id)
|
||||||
assert (bid.initiate_tx)
|
assert (bid.initiate_tx)
|
||||||
wtx = ci_from.rpc_callback('gettransaction', [bid.initiate_tx.txid.hex(),])
|
wtx = ci_from.rpc('gettransaction', [bid.initiate_tx.txid.hex(),])
|
||||||
itx_after = ci_from.describeTx(wtx['hex'])
|
itx_after = ci_from.describeTx(wtx['hex'])
|
||||||
assert (len(itx_after['vin']) == len(itx_decoded['vin']))
|
assert (len(itx_after['vin']) == len(itx_decoded['vin']))
|
||||||
for i, txin in enumerate(itx_decoded['vin']):
|
for i, txin in enumerate(itx_decoded['vin']):
|
||||||
|
@ -60,6 +60,16 @@ class TestFunctions(BaseTest):
|
|||||||
node_a_id = 0
|
node_a_id = 0
|
||||||
node_b_id = 1
|
node_b_id = 1
|
||||||
|
|
||||||
|
def callnoderpc(self, method, params=[], wallet=None, node_id=0):
|
||||||
|
return callnoderpc(node_id, method, params, wallet, self.base_rpc_port)
|
||||||
|
|
||||||
|
def mineBlock(self, num_blocks=1):
|
||||||
|
self.callnoderpc('generatetoaddress', [num_blocks, self.btc_addr])
|
||||||
|
|
||||||
|
def check_softfork_active(self, feature_name):
|
||||||
|
deploymentinfo = self.callnoderpc('getdeploymentinfo')
|
||||||
|
assert (deploymentinfo['deployments'][feature_name]['active'] is True)
|
||||||
|
|
||||||
def getBalance(self, js_wallets, coin) -> float:
|
def getBalance(self, js_wallets, coin) -> float:
|
||||||
if coin == Coins.PART_BLIND:
|
if coin == Coins.PART_BLIND:
|
||||||
coin_ticker: str = 'PART'
|
coin_ticker: str = 'PART'
|
||||||
@ -79,12 +89,6 @@ class TestFunctions(BaseTest):
|
|||||||
|
|
||||||
return float(js_wallets[coin_ticker][balance_type]) + float(js_wallets[coin_ticker][unconfirmed_name])
|
return float(js_wallets[coin_ticker][balance_type]) + float(js_wallets[coin_ticker][unconfirmed_name])
|
||||||
|
|
||||||
def callnoderpc(self, method, params=[], wallet=None, node_id=0):
|
|
||||||
return callnoderpc(node_id, method, params, wallet, self.base_rpc_port)
|
|
||||||
|
|
||||||
def mineBlock(self, num_blocks=1):
|
|
||||||
self.callnoderpc('generatetoaddress', [num_blocks, self.btc_addr])
|
|
||||||
|
|
||||||
def prepare_balance(self, coin, amount: float, port_target_node: int, port_take_from_node: int, test_balance: bool = True) -> None:
|
def prepare_balance(self, coin, amount: float, port_target_node: int, port_take_from_node: int, test_balance: bool = True) -> None:
|
||||||
delay_iterations = 100 if coin == Coins.NAV else 20
|
delay_iterations = 100 if coin == Coins.NAV else 20
|
||||||
delay_time = 5 if coin == Coins.NAV else 3
|
delay_time = 5 if coin == Coins.NAV else 3
|
||||||
@ -149,8 +153,8 @@ class TestFunctions(BaseTest):
|
|||||||
js_1 = read_json_api(1800 + id_bidder, 'wallets')
|
js_1 = read_json_api(1800 + id_bidder, 'wallets')
|
||||||
node1_from_before: float = self.getBalance(js_1, coin_from)
|
node1_from_before: float = self.getBalance(js_1, coin_from)
|
||||||
|
|
||||||
node0_sent_messages_before: int = ci_part0.rpc_callback('smsgoutbox', ['count',])['num_messages']
|
node0_sent_messages_before: int = ci_part0.rpc('smsgoutbox', ['count',])['num_messages']
|
||||||
node1_sent_messages_before: int = ci_part1.rpc_callback('smsgoutbox', ['count',])['num_messages']
|
node1_sent_messages_before: int = ci_part1.rpc('smsgoutbox', ['count',])['num_messages']
|
||||||
|
|
||||||
amt_swap = ci_from.make_int(random.uniform(0.1, 2.0), r=1)
|
amt_swap = ci_from.make_int(random.uniform(0.1, 2.0), r=1)
|
||||||
rate_swap = ci_to.make_int(random.uniform(0.2, 20.0), r=1)
|
rate_swap = ci_to.make_int(random.uniform(0.2, 20.0), r=1)
|
||||||
@ -224,8 +228,8 @@ class TestFunctions(BaseTest):
|
|||||||
if False: # TODO: set stakeaddress and xmr rewards to non wallet addresses
|
if False: # TODO: set stakeaddress and xmr rewards to non wallet addresses
|
||||||
assert (node1_to_after < node1_to_before - amount_to_float)
|
assert (node1_to_after < node1_to_before - amount_to_float)
|
||||||
|
|
||||||
node0_sent_messages_after: int = ci_part0.rpc_callback('smsgoutbox', ['count',])['num_messages']
|
node0_sent_messages_after: int = ci_part0.rpc('smsgoutbox', ['count',])['num_messages']
|
||||||
node1_sent_messages_after: int = ci_part1.rpc_callback('smsgoutbox', ['count',])['num_messages']
|
node1_sent_messages_after: int = ci_part1.rpc('smsgoutbox', ['count',])['num_messages']
|
||||||
node0_sent_messages: int = node0_sent_messages_after - node0_sent_messages_before
|
node0_sent_messages: int = node0_sent_messages_after - node0_sent_messages_before
|
||||||
node1_sent_messages: int = node1_sent_messages_after - node1_sent_messages_before
|
node1_sent_messages: int = node1_sent_messages_after - node1_sent_messages_before
|
||||||
split_msgs: int = 2 if (ci_from.curve_type() != Curves.secp256k1 or ci_to.curve_type() != Curves.secp256k1) else 0
|
split_msgs: int = 2 if (ci_from.curve_type() != Curves.secp256k1 or ci_to.curve_type() != Curves.secp256k1) else 0
|
||||||
@ -434,21 +438,22 @@ class BasicSwapTest(TestFunctions):
|
|||||||
def test_001_nested_segwit(self):
|
def test_001_nested_segwit(self):
|
||||||
# p2sh-p2wpkh
|
# p2sh-p2wpkh
|
||||||
logging.info('---------- Test {} p2sh nested segwit'.format(self.test_coin_from.name))
|
logging.info('---------- Test {} p2sh nested segwit'.format(self.test_coin_from.name))
|
||||||
|
ci = self.swap_clients[0].ci(self.test_coin_from)
|
||||||
|
|
||||||
addr_p2sh_segwit = self.callnoderpc('getnewaddress', ['segwit test', 'p2sh-segwit'])
|
addr_p2sh_segwit = ci.rpc_wallet('getnewaddress', ['segwit test', 'p2sh-segwit'])
|
||||||
addr_info = self.callnoderpc('getaddressinfo', [addr_p2sh_segwit, ])
|
addr_info = ci.rpc_wallet('getaddressinfo', [addr_p2sh_segwit, ])
|
||||||
assert addr_info['script'] == 'witness_v0_keyhash'
|
assert addr_info['script'] == 'witness_v0_keyhash'
|
||||||
|
|
||||||
txid = self.callnoderpc('sendtoaddress', [addr_p2sh_segwit, 1.0])
|
txid = ci.rpc_wallet('sendtoaddress', [addr_p2sh_segwit, 1.0])
|
||||||
assert len(txid) == 64
|
assert len(txid) == 64
|
||||||
|
|
||||||
self.mineBlock()
|
self.mineBlock()
|
||||||
ro = self.callnoderpc('scantxoutset', ['start', ['addr({})'.format(addr_p2sh_segwit)]])
|
ro = ci.rpc('scantxoutset', ['start', ['addr({})'.format(addr_p2sh_segwit)]])
|
||||||
assert (len(ro['unspents']) == 1)
|
assert (len(ro['unspents']) == 1)
|
||||||
assert (ro['unspents'][0]['txid'] == txid)
|
assert (ro['unspents'][0]['txid'] == txid)
|
||||||
|
|
||||||
tx_wallet = self.callnoderpc('gettransaction', [txid, ])['hex']
|
tx_wallet = ci.rpc_wallet('gettransaction', [txid, ])['hex']
|
||||||
tx = self.callnoderpc('decoderawtransaction', [tx_wallet, ])
|
tx = ci.rpc('decoderawtransaction', [tx_wallet, ])
|
||||||
|
|
||||||
prevout_n = -1
|
prevout_n = -1
|
||||||
for txo in tx['vout']:
|
for txo in tx['vout']:
|
||||||
@ -457,14 +462,14 @@ class BasicSwapTest(TestFunctions):
|
|||||||
break
|
break
|
||||||
assert prevout_n > -1
|
assert prevout_n > -1
|
||||||
|
|
||||||
tx_funded = self.callnoderpc('createrawtransaction', [[{'txid': txid, 'vout': prevout_n}], {addr_p2sh_segwit: 0.99}])
|
tx_funded = ci.rpc('createrawtransaction', [[{'txid': txid, 'vout': prevout_n}], {addr_p2sh_segwit: 0.99}])
|
||||||
tx_signed = self.callnoderpc('signrawtransactionwithwallet', [tx_funded, ])['hex']
|
tx_signed = ci.rpc_wallet('signrawtransactionwithwallet', [tx_funded, ])['hex']
|
||||||
tx_funded_decoded = self.callnoderpc('decoderawtransaction', [tx_funded, ])
|
tx_funded_decoded = ci.rpc('decoderawtransaction', [tx_funded, ])
|
||||||
tx_signed_decoded = self.callnoderpc('decoderawtransaction', [tx_signed, ])
|
tx_signed_decoded = ci.rpc('decoderawtransaction', [tx_signed, ])
|
||||||
assert tx_funded_decoded['txid'] != tx_signed_decoded['txid']
|
assert tx_funded_decoded['txid'] != tx_signed_decoded['txid']
|
||||||
|
|
||||||
# Add scriptsig for txids to match
|
# Add scriptsig for txids to match
|
||||||
addr_p2sh_segwit_info = self.callnoderpc('getaddressinfo', [addr_p2sh_segwit, ])
|
addr_p2sh_segwit_info = ci.rpc_wallet('getaddressinfo', [addr_p2sh_segwit, ])
|
||||||
decoded_tx = FromHex(CTransaction(), tx_funded)
|
decoded_tx = FromHex(CTransaction(), tx_funded)
|
||||||
decoded_tx.vin[0].scriptSig = bytes.fromhex('16' + addr_p2sh_segwit_info['hex'])
|
decoded_tx.vin[0].scriptSig = bytes.fromhex('16' + addr_p2sh_segwit_info['hex'])
|
||||||
txid_with_scriptsig = decoded_tx.rehash()
|
txid_with_scriptsig = decoded_tx.rehash()
|
||||||
@ -473,18 +478,19 @@ class BasicSwapTest(TestFunctions):
|
|||||||
def test_002_native_segwit(self):
|
def test_002_native_segwit(self):
|
||||||
# p2wpkh
|
# p2wpkh
|
||||||
logging.info('---------- Test {} p2sh native segwit'.format(self.test_coin_from.name))
|
logging.info('---------- Test {} p2sh native segwit'.format(self.test_coin_from.name))
|
||||||
|
ci = self.swap_clients[0].ci(self.test_coin_from)
|
||||||
|
|
||||||
addr_segwit = self.callnoderpc('getnewaddress', ['segwit test', 'bech32'])
|
addr_segwit = ci.rpc_wallet('getnewaddress', ['segwit test', 'bech32'])
|
||||||
addr_info = self.callnoderpc('getaddressinfo', [addr_segwit, ])
|
addr_info = ci.rpc_wallet('getaddressinfo', [addr_segwit, ])
|
||||||
assert addr_info['iswitness'] is True
|
assert addr_info['iswitness'] is True
|
||||||
|
|
||||||
txid = self.callnoderpc('sendtoaddress', [addr_segwit, 1.0])
|
txid = ci.rpc_wallet('sendtoaddress', [addr_segwit, 1.0])
|
||||||
assert len(txid) == 64
|
assert len(txid) == 64
|
||||||
tx_wallet = self.callnoderpc('gettransaction', [txid, ])['hex']
|
tx_wallet = ci.rpc_wallet('gettransaction', [txid, ])['hex']
|
||||||
tx = self.callnoderpc('decoderawtransaction', [tx_wallet, ])
|
tx = ci.rpc('decoderawtransaction', [tx_wallet, ])
|
||||||
|
|
||||||
self.mineBlock()
|
self.mineBlock()
|
||||||
ro = self.callnoderpc('scantxoutset', ['start', ['addr({})'.format(addr_segwit)]])
|
ro = ci.rpc('scantxoutset', ['start', ['addr({})'.format(addr_segwit)]])
|
||||||
assert (len(ro['unspents']) == 1)
|
assert (len(ro['unspents']) == 1)
|
||||||
assert (ro['unspents'][0]['txid'] == txid)
|
assert (ro['unspents'][0]['txid'] == txid)
|
||||||
|
|
||||||
@ -495,19 +501,17 @@ class BasicSwapTest(TestFunctions):
|
|||||||
break
|
break
|
||||||
assert prevout_n > -1
|
assert prevout_n > -1
|
||||||
|
|
||||||
tx_funded = self.callnoderpc('createrawtransaction', [[{'txid': txid, 'vout': prevout_n}], {addr_segwit: 0.99}])
|
tx_funded = ci.rpc('createrawtransaction', [[{'txid': txid, 'vout': prevout_n}], {addr_segwit: 0.99}])
|
||||||
tx_signed = self.callnoderpc('signrawtransactionwithwallet', [tx_funded, ])['hex']
|
tx_signed = ci.rpc_wallet('signrawtransactionwithwallet', [tx_funded, ])['hex']
|
||||||
tx_funded_decoded = self.callnoderpc('decoderawtransaction', [tx_funded, ])
|
tx_funded_decoded = ci.rpc('decoderawtransaction', [tx_funded, ])
|
||||||
tx_signed_decoded = self.callnoderpc('decoderawtransaction', [tx_signed, ])
|
tx_signed_decoded = ci.rpc('decoderawtransaction', [tx_signed, ])
|
||||||
assert tx_funded_decoded['txid'] == tx_signed_decoded['txid']
|
assert tx_funded_decoded['txid'] == tx_signed_decoded['txid']
|
||||||
|
|
||||||
def test_003_cltv(self):
|
def test_003_cltv(self):
|
||||||
logging.info('---------- Test {} cltv'.format(self.test_coin_from.name))
|
logging.info('---------- Test {} cltv'.format(self.test_coin_from.name))
|
||||||
ci = self.swap_clients[0].ci(self.test_coin_from)
|
ci = self.swap_clients[0].ci(self.test_coin_from)
|
||||||
|
|
||||||
deploymentinfo = self.callnoderpc('getdeploymentinfo')
|
self.check_softfork_active('bip65')
|
||||||
bip65_active = deploymentinfo['deployments']['bip65']['active']
|
|
||||||
assert (bip65_active)
|
|
||||||
|
|
||||||
chain_height = self.callnoderpc('getblockcount')
|
chain_height = self.callnoderpc('getblockcount')
|
||||||
script = CScript([chain_height + 3, OP_CHECKLOCKTIMEVERIFY, ])
|
script = CScript([chain_height + 3, OP_CHECKLOCKTIMEVERIFY, ])
|
||||||
@ -517,12 +521,12 @@ class BasicSwapTest(TestFunctions):
|
|||||||
tx.nVersion = ci.txVersion()
|
tx.nVersion = ci.txVersion()
|
||||||
tx.vout.append(ci.txoType()(ci.make_int(1.1), script_dest))
|
tx.vout.append(ci.txoType()(ci.make_int(1.1), script_dest))
|
||||||
tx_hex = ToHex(tx)
|
tx_hex = ToHex(tx)
|
||||||
tx_funded = self.callnoderpc('fundrawtransaction', [tx_hex])
|
tx_funded = ci.rpc_wallet('fundrawtransaction', [tx_hex])
|
||||||
utxo_pos = 0 if tx_funded['changepos'] == 1 else 1
|
utxo_pos = 0 if tx_funded['changepos'] == 1 else 1
|
||||||
tx_signed = self.callnoderpc('signrawtransactionwithwallet', [tx_funded['hex'], ])['hex']
|
tx_signed = ci.rpc_wallet('signrawtransactionwithwallet', [tx_funded['hex'], ])['hex']
|
||||||
txid = self.callnoderpc('sendrawtransaction', [tx_signed, ])
|
txid = ci.rpc('sendrawtransaction', [tx_signed, ])
|
||||||
|
|
||||||
addr_out = self.callnoderpc('getnewaddress', ['cltv test', 'bech32'])
|
addr_out = ci.rpc_wallet('getnewaddress', ['cltv test', 'bech32'])
|
||||||
pkh = ci.decodeSegwitAddress(addr_out)
|
pkh = ci.decodeSegwitAddress(addr_out)
|
||||||
script_out = ci.getScriptForPubkeyHash(pkh)
|
script_out = ci.getScriptForPubkeyHash(pkh)
|
||||||
|
|
||||||
@ -548,15 +552,15 @@ class BasicSwapTest(TestFunctions):
|
|||||||
|
|
||||||
self.mineBlock(5)
|
self.mineBlock(5)
|
||||||
try:
|
try:
|
||||||
txid = self.callnoderpc('sendrawtransaction', [tx_spend_invalid_hex, ])
|
txid = ci.rpc('sendrawtransaction', [tx_spend_invalid_hex, ])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
assert ('Locktime requirement not satisfied' in str(e))
|
assert ('Locktime requirement not satisfied' in str(e))
|
||||||
else:
|
else:
|
||||||
assert False, 'Should fail'
|
assert False, 'Should fail'
|
||||||
|
|
||||||
txid = self.callnoderpc('sendrawtransaction', [tx_spend_hex, ])
|
txid = ci.rpc('sendrawtransaction', [tx_spend_hex, ])
|
||||||
self.mineBlock()
|
self.mineBlock()
|
||||||
ro = self.callnoderpc('listreceivedbyaddress', [0, ])
|
ro = ci.rpc_wallet('listreceivedbyaddress', [0, ])
|
||||||
sum_addr = 0
|
sum_addr = 0
|
||||||
for entry in ro:
|
for entry in ro:
|
||||||
if entry['address'] == addr_out:
|
if entry['address'] == addr_out:
|
||||||
@ -564,7 +568,7 @@ class BasicSwapTest(TestFunctions):
|
|||||||
assert (sum_addr == 1.0999)
|
assert (sum_addr == 1.0999)
|
||||||
|
|
||||||
# Ensure tx was mined
|
# Ensure tx was mined
|
||||||
tx_wallet = self.callnoderpc('gettransaction', [txid, ])
|
tx_wallet = ci.rpc_wallet('gettransaction', [txid, ])
|
||||||
assert (len(tx_wallet['blockhash']) == 64)
|
assert (len(tx_wallet['blockhash']) == 64)
|
||||||
|
|
||||||
def test_004_csv(self):
|
def test_004_csv(self):
|
||||||
@ -572,6 +576,8 @@ class BasicSwapTest(TestFunctions):
|
|||||||
swap_clients = self.swap_clients
|
swap_clients = self.swap_clients
|
||||||
ci = self.swap_clients[0].ci(self.test_coin_from)
|
ci = self.swap_clients[0].ci(self.test_coin_from)
|
||||||
|
|
||||||
|
self.check_softfork_active('bip66')
|
||||||
|
|
||||||
script = CScript([3, OP_CHECKSEQUENCEVERIFY, ])
|
script = CScript([3, OP_CHECKSEQUENCEVERIFY, ])
|
||||||
|
|
||||||
script_dest = ci.getScriptDest(script)
|
script_dest = ci.getScriptDest(script)
|
||||||
@ -579,17 +585,17 @@ class BasicSwapTest(TestFunctions):
|
|||||||
tx.nVersion = ci.txVersion()
|
tx.nVersion = ci.txVersion()
|
||||||
tx.vout.append(ci.txoType()(ci.make_int(1.1), script_dest))
|
tx.vout.append(ci.txoType()(ci.make_int(1.1), script_dest))
|
||||||
tx_hex = ToHex(tx)
|
tx_hex = ToHex(tx)
|
||||||
tx_funded = self.callnoderpc('fundrawtransaction', [tx_hex])
|
tx_funded = ci.rpc_wallet('fundrawtransaction', [tx_hex])
|
||||||
utxo_pos = 0 if tx_funded['changepos'] == 1 else 1
|
utxo_pos = 0 if tx_funded['changepos'] == 1 else 1
|
||||||
tx_signed = self.callnoderpc('signrawtransactionwithwallet', [tx_funded['hex'], ])['hex']
|
tx_signed = ci.rpc_wallet('signrawtransactionwithwallet', [tx_funded['hex'], ])['hex']
|
||||||
txid = self.callnoderpc('sendrawtransaction', [tx_signed, ])
|
txid = ci.rpc('sendrawtransaction', [tx_signed, ])
|
||||||
|
|
||||||
addr_out = self.callnoderpc('getnewaddress', ['csv test', 'bech32'])
|
addr_out = ci.rpc_wallet('getnewaddress', ['csv test', 'bech32'])
|
||||||
pkh = ci.decodeSegwitAddress(addr_out)
|
pkh = ci.decodeSegwitAddress(addr_out)
|
||||||
script_out = ci.getScriptForPubkeyHash(pkh)
|
script_out = ci.getScriptForPubkeyHash(pkh)
|
||||||
|
|
||||||
# Double check output type
|
# Double check output type
|
||||||
prev_tx = self.callnoderpc('decoderawtransaction', [tx_signed, ])
|
prev_tx = ci.rpc('decoderawtransaction', [tx_signed, ])
|
||||||
assert (prev_tx['vout'][utxo_pos]['scriptPubKey']['type'] == 'witness_v0_scripthash')
|
assert (prev_tx['vout'][utxo_pos]['scriptPubKey']['type'] == 'witness_v0_scripthash')
|
||||||
|
|
||||||
tx_spend = CTransaction()
|
tx_spend = CTransaction()
|
||||||
@ -601,16 +607,16 @@ class BasicSwapTest(TestFunctions):
|
|||||||
tx_spend.wit.vtxinwit[0].scriptWitness.stack = [script, ]
|
tx_spend.wit.vtxinwit[0].scriptWitness.stack = [script, ]
|
||||||
tx_spend_hex = ToHex(tx_spend)
|
tx_spend_hex = ToHex(tx_spend)
|
||||||
try:
|
try:
|
||||||
txid = self.callnoderpc('sendrawtransaction', [tx_spend_hex, ])
|
txid = ci.rpc('sendrawtransaction', [tx_spend_hex, ])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
assert ('non-BIP68-final' in str(e))
|
assert ('non-BIP68-final' in str(e))
|
||||||
else:
|
else:
|
||||||
assert False, 'Should fail'
|
assert False, 'Should fail'
|
||||||
|
|
||||||
self.mineBlock(3)
|
self.mineBlock(3)
|
||||||
txid = self.callnoderpc('sendrawtransaction', [tx_spend_hex, ])
|
txid = ci.rpc('sendrawtransaction', [tx_spend_hex, ])
|
||||||
self.mineBlock(1)
|
self.mineBlock(1)
|
||||||
ro = self.callnoderpc('listreceivedbyaddress', [0, ])
|
ro = ci.rpc_wallet('listreceivedbyaddress', [0, ])
|
||||||
sum_addr = 0
|
sum_addr = 0
|
||||||
for entry in ro:
|
for entry in ro:
|
||||||
if entry['address'] == addr_out:
|
if entry['address'] == addr_out:
|
||||||
@ -618,20 +624,22 @@ class BasicSwapTest(TestFunctions):
|
|||||||
assert (sum_addr == 1.0999)
|
assert (sum_addr == 1.0999)
|
||||||
|
|
||||||
# Ensure tx was mined
|
# Ensure tx was mined
|
||||||
tx_wallet = self.callnoderpc('gettransaction', [txid, ])
|
tx_wallet = ci.rpc_wallet('gettransaction', [txid, ])
|
||||||
assert (len(tx_wallet['blockhash']) == 64)
|
assert (len(tx_wallet['blockhash']) == 64)
|
||||||
|
|
||||||
def test_005_watchonly(self):
|
def test_005_watchonly(self):
|
||||||
logging.info('---------- Test {} watchonly'.format(self.test_coin_from.name))
|
logging.info('---------- Test {} watchonly'.format(self.test_coin_from.name))
|
||||||
|
ci = self.swap_clients[0].ci(self.test_coin_from)
|
||||||
|
ci1 = self.swap_clients[1].ci(self.test_coin_from)
|
||||||
|
|
||||||
addr = self.callnoderpc('getnewaddress', ['watchonly test', 'bech32'])
|
addr = ci.rpc_wallet('getnewaddress', ['watchonly test', 'bech32'])
|
||||||
ro = self.callnoderpc('importaddress', [addr, '', False], node_id=1)
|
ro = ci1.rpc_wallet('importaddress', [addr, '', False])
|
||||||
txid = self.callnoderpc('sendtoaddress', [addr, 1.0])
|
txid = ci.rpc_wallet('sendtoaddress', [addr, 1.0])
|
||||||
tx_hex = self.callnoderpc('getrawtransaction', [txid, ])
|
tx_hex = ci.rpc('getrawtransaction', [txid, ])
|
||||||
self.callnoderpc('sendrawtransaction', [tx_hex, ], node_id=1)
|
ci1.rpc_wallet('sendrawtransaction', [tx_hex, ])
|
||||||
ro = self.callnoderpc('gettransaction', [txid, ], node_id=1)
|
ro = ci1.rpc_wallet('gettransaction', [txid, ])
|
||||||
assert (ro['txid'] == txid)
|
assert (ro['txid'] == txid)
|
||||||
balances = self.callnoderpc('getbalances', node_id=1)
|
balances = ci1.rpc_wallet('getbalances')
|
||||||
assert (balances['watchonly']['trusted'] + balances['watchonly']['untrusted_pending'] >= 1.0)
|
assert (balances['watchonly']['trusted'] + balances['watchonly']['untrusted_pending'] >= 1.0)
|
||||||
|
|
||||||
def test_006_getblock_verbosity(self):
|
def test_006_getblock_verbosity(self):
|
||||||
@ -643,6 +651,7 @@ class BasicSwapTest(TestFunctions):
|
|||||||
|
|
||||||
def test_007_hdwallet(self):
|
def test_007_hdwallet(self):
|
||||||
logging.info('---------- Test {} hdwallet'.format(self.test_coin_from.name))
|
logging.info('---------- Test {} hdwallet'.format(self.test_coin_from.name))
|
||||||
|
ci = self.swap_clients[0].ci(self.test_coin_from)
|
||||||
|
|
||||||
test_seed = '8e54a313e6df8918df6d758fafdbf127a115175fdd2238d0e908dd8093c9ac3b'
|
test_seed = '8e54a313e6df8918df6d758fafdbf127a115175fdd2238d0e908dd8093c9ac3b'
|
||||||
test_wif = self.swap_clients[0].ci(self.test_coin_from).encodeKey(bytes.fromhex(test_seed))
|
test_wif = self.swap_clients[0].ci(self.test_coin_from).encodeKey(bytes.fromhex(test_seed))
|
||||||
@ -657,7 +666,7 @@ class BasicSwapTest(TestFunctions):
|
|||||||
self.swap_clients[0].initialiseWallet(Coins.BTC, raise_errors=True)
|
self.swap_clients[0].initialiseWallet(Coins.BTC, raise_errors=True)
|
||||||
assert self.swap_clients[0].checkWalletSeed(Coins.BTC) is True
|
assert self.swap_clients[0].checkWalletSeed(Coins.BTC) is True
|
||||||
for i in range(1500):
|
for i in range(1500):
|
||||||
self.callnoderpc('getnewaddress')
|
ci.rpc_wallet('getnewaddress')
|
||||||
assert self.swap_clients[0].checkWalletSeed(Coins.BTC) is True
|
assert self.swap_clients[0].checkWalletSeed(Coins.BTC) is True
|
||||||
|
|
||||||
rv = read_json_api(1800, 'getcoinseed', {'coin': 'XMR'})
|
rv = read_json_api(1800, 'getcoinseed', {'coin': 'XMR'})
|
||||||
@ -667,38 +676,44 @@ class BasicSwapTest(TestFunctions):
|
|||||||
logging.info('---------- Test {} gettxout'.format(self.test_coin_from.name))
|
logging.info('---------- Test {} gettxout'.format(self.test_coin_from.name))
|
||||||
|
|
||||||
swap_client = self.swap_clients[0]
|
swap_client = self.swap_clients[0]
|
||||||
|
ci = swap_client.ci(self.test_coin_from)
|
||||||
|
|
||||||
addr_1 = self.callnoderpc('getnewaddress', ['gettxout test 1',])
|
addr_1 = ci.rpc_wallet('getnewaddress', ['gettxout test 1',])
|
||||||
txid = self.callnoderpc('sendtoaddress', [addr_1, 1.0])
|
txid = ci.rpc_wallet('sendtoaddress', [addr_1, 1.0])
|
||||||
assert len(txid) == 64
|
assert len(txid) == 64
|
||||||
|
|
||||||
self.mineBlock()
|
self.mineBlock()
|
||||||
|
|
||||||
unspents = self.callnoderpc('listunspent', [0, 999999999, [addr_1,]])
|
unspents = ci.rpc_wallet('listunspent', [0, 999999999, [addr_1,]])
|
||||||
assert (len(unspents) == 1)
|
assert (len(unspents) == 1)
|
||||||
|
|
||||||
utxo = unspents[0]
|
utxo = unspents[0]
|
||||||
txout = self.callnoderpc('gettxout', [utxo['txid'], utxo['vout']])
|
txout = ci.rpc('gettxout', [utxo['txid'], utxo['vout']])
|
||||||
assert (addr_1 == txout['scriptPubKey']['address'])
|
if 'address' in txout:
|
||||||
|
assert (addr_1 == txout['scriptPubKey']['address'])
|
||||||
|
else:
|
||||||
|
assert (addr_1 in txout['scriptPubKey']['addresses'])
|
||||||
# Spend
|
# Spend
|
||||||
addr_2 = self.callnoderpc('getnewaddress', ['gettxout test 2',])
|
addr_2 = ci.rpc_wallet('getnewaddress', ['gettxout test 2',])
|
||||||
tx_funded = self.callnoderpc('createrawtransaction', [[{'txid': utxo['txid'], 'vout': utxo['vout']}], {addr_2: 0.99}])
|
tx_funded = ci.rpc('createrawtransaction', [[{'txid': utxo['txid'], 'vout': utxo['vout']}], {addr_2: 0.99}])
|
||||||
tx_signed = self.callnoderpc('signrawtransactionwithwallet', [tx_funded,])['hex']
|
tx_signed = ci.rpc_wallet('signrawtransactionwithwallet', [tx_funded,])['hex']
|
||||||
self.callnoderpc('sendrawtransaction', [tx_signed,])
|
ci.rpc('sendrawtransaction', [tx_signed,])
|
||||||
|
|
||||||
# utxo should be unavailable when spent in the mempool
|
# utxo should be unavailable when spent in the mempool
|
||||||
txout = self.callnoderpc('gettxout', [utxo['txid'], utxo['vout']])
|
txout = ci.rpc('gettxout', [utxo['txid'], utxo['vout']])
|
||||||
assert (txout is None)
|
assert (txout is None)
|
||||||
|
|
||||||
def test_009_scantxoutset(self):
|
def test_009_scantxoutset(self):
|
||||||
logging.info('---------- Test {} scantxoutset'.format(self.test_coin_from.name))
|
logging.info('---------- Test {} scantxoutset'.format(self.test_coin_from.name))
|
||||||
addr_1 = self.callnoderpc('getnewaddress', ['scantxoutset test', ])
|
ci = self.swap_clients[0].ci(self.test_coin_from)
|
||||||
txid = self.callnoderpc('sendtoaddress', [addr_1, 1.0])
|
|
||||||
|
addr_1 = ci.rpc_wallet('getnewaddress', ['scantxoutset test', ])
|
||||||
|
txid = ci.rpc_wallet('sendtoaddress', [addr_1, 1.0])
|
||||||
assert len(txid) == 64
|
assert len(txid) == 64
|
||||||
|
|
||||||
self.mineBlock()
|
self.mineBlock()
|
||||||
|
|
||||||
ro = self.callnoderpc('scantxoutset', ['start', ['addr({})'.format(addr_1)]])
|
ro = ci.rpc('scantxoutset', ['start', ['addr({})'.format(addr_1)]])
|
||||||
assert (len(ro['unspents']) == 1)
|
assert (len(ro['unspents']) == 1)
|
||||||
assert (ro['unspents'][0]['txid'] == txid)
|
assert (ro['unspents'][0]['txid'] == txid)
|
||||||
|
|
||||||
@ -712,7 +727,7 @@ class BasicSwapTest(TestFunctions):
|
|||||||
amount: int = ci.make_int(random.uniform(0.1, 2.0), r=1)
|
amount: int = ci.make_int(random.uniform(0.1, 2.0), r=1)
|
||||||
|
|
||||||
# Record unspents before createSCLockTx as the used ones will be locked
|
# Record unspents before createSCLockTx as the used ones will be locked
|
||||||
unspents = self.callnoderpc('listunspent')
|
unspents = ci.rpc_wallet('listunspent')
|
||||||
|
|
||||||
# fee_rate is in sats/kvB
|
# fee_rate is in sats/kvB
|
||||||
fee_rate: int = 1000
|
fee_rate: int = 1000
|
||||||
@ -728,10 +743,10 @@ class BasicSwapTest(TestFunctions):
|
|||||||
lock_tx = ci.fundSCLockTx(lock_tx, fee_rate)
|
lock_tx = ci.fundSCLockTx(lock_tx, fee_rate)
|
||||||
lock_tx = ci.signTxWithWallet(lock_tx)
|
lock_tx = ci.signTxWithWallet(lock_tx)
|
||||||
|
|
||||||
unspents_after = self.callnoderpc('listunspent')
|
unspents_after = ci.rpc_wallet('listunspent')
|
||||||
assert (len(unspents) > len(unspents_after))
|
assert (len(unspents) > len(unspents_after))
|
||||||
|
|
||||||
tx_decoded = self.callnoderpc('decoderawtransaction', [lock_tx.hex()])
|
tx_decoded = ci.rpc('decoderawtransaction', [lock_tx.hex()])
|
||||||
txid = tx_decoded['txid']
|
txid = tx_decoded['txid']
|
||||||
|
|
||||||
vsize = tx_decoded['vsize']
|
vsize = tx_decoded['vsize']
|
||||||
@ -752,8 +767,8 @@ class BasicSwapTest(TestFunctions):
|
|||||||
break
|
break
|
||||||
fee_value = in_value - out_value
|
fee_value = in_value - out_value
|
||||||
|
|
||||||
self.callnoderpc('sendrawtransaction', [lock_tx.hex()])
|
ci.rpc('sendrawtransaction', [lock_tx.hex()])
|
||||||
rv = self.callnoderpc('gettransaction', [txid])
|
rv = ci.rpc_wallet('gettransaction', [txid])
|
||||||
wallet_tx_fee = -ci.make_int(rv['fee'])
|
wallet_tx_fee = -ci.make_int(rv['fee'])
|
||||||
|
|
||||||
assert (wallet_tx_fee == fee_value)
|
assert (wallet_tx_fee == fee_value)
|
||||||
@ -765,7 +780,7 @@ class BasicSwapTest(TestFunctions):
|
|||||||
lock_spend_tx = ci.createSCLockSpendTx(lock_tx, lock_tx_script, pkh_out, fee_rate, fee_info=fee_info)
|
lock_spend_tx = ci.createSCLockSpendTx(lock_tx, lock_tx_script, pkh_out, fee_rate, fee_info=fee_info)
|
||||||
vsize_estimated: int = fee_info['vsize']
|
vsize_estimated: int = fee_info['vsize']
|
||||||
|
|
||||||
tx_decoded = self.callnoderpc('decoderawtransaction', [lock_spend_tx.hex()])
|
tx_decoded = ci.rpc('decoderawtransaction', [lock_spend_tx.hex()])
|
||||||
txid = tx_decoded['txid']
|
txid = tx_decoded['txid']
|
||||||
|
|
||||||
witness_stack = [
|
witness_stack = [
|
||||||
@ -775,11 +790,11 @@ class BasicSwapTest(TestFunctions):
|
|||||||
lock_tx_script,
|
lock_tx_script,
|
||||||
]
|
]
|
||||||
lock_spend_tx = ci.setTxSignature(lock_spend_tx, witness_stack)
|
lock_spend_tx = ci.setTxSignature(lock_spend_tx, witness_stack)
|
||||||
tx_decoded = self.callnoderpc('decoderawtransaction', [lock_spend_tx.hex()])
|
tx_decoded = ci.rpc('decoderawtransaction', [lock_spend_tx.hex()])
|
||||||
vsize_actual: int = tx_decoded['vsize']
|
vsize_actual: int = tx_decoded['vsize']
|
||||||
|
|
||||||
assert (vsize_actual <= vsize_estimated and vsize_estimated - vsize_actual < 4)
|
assert (vsize_actual <= vsize_estimated and vsize_estimated - vsize_actual < 4)
|
||||||
assert (self.callnoderpc('sendrawtransaction', [lock_spend_tx.hex()]) == txid)
|
assert (ci.rpc('sendrawtransaction', [lock_spend_tx.hex()]) == txid)
|
||||||
|
|
||||||
expect_vsize: int = ci.xmr_swap_a_lock_spend_tx_vsize()
|
expect_vsize: int = ci.xmr_swap_a_lock_spend_tx_vsize()
|
||||||
assert (expect_vsize >= vsize_actual)
|
assert (expect_vsize >= vsize_actual)
|
||||||
@ -796,7 +811,7 @@ class BasicSwapTest(TestFunctions):
|
|||||||
lock_tx_b_spend = ci.getTransaction(lock_tx_b_spend_txid)
|
lock_tx_b_spend = ci.getTransaction(lock_tx_b_spend_txid)
|
||||||
if lock_tx_b_spend is None:
|
if lock_tx_b_spend is None:
|
||||||
lock_tx_b_spend = ci.getWalletTransaction(lock_tx_b_spend_txid)
|
lock_tx_b_spend = ci.getWalletTransaction(lock_tx_b_spend_txid)
|
||||||
lock_tx_b_spend_decoded = self.callnoderpc('decoderawtransaction', [lock_tx_b_spend.hex()])
|
lock_tx_b_spend_decoded = ci.rpc('decoderawtransaction', [lock_tx_b_spend.hex()])
|
||||||
|
|
||||||
expect_vsize: int = ci.xmr_swap_b_lock_spend_tx_vsize()
|
expect_vsize: int = ci.xmr_swap_b_lock_spend_tx_vsize()
|
||||||
assert (expect_vsize >= lock_tx_b_spend_decoded['vsize'])
|
assert (expect_vsize >= lock_tx_b_spend_decoded['vsize'])
|
||||||
@ -816,17 +831,17 @@ class BasicSwapTest(TestFunctions):
|
|||||||
tx.nVersion = ci.txVersion()
|
tx.nVersion = ci.txVersion()
|
||||||
tx.vout.append(ci.txoType()(ci.make_int(1.1), script_dest))
|
tx.vout.append(ci.txoType()(ci.make_int(1.1), script_dest))
|
||||||
tx_hex = ToHex(tx)
|
tx_hex = ToHex(tx)
|
||||||
tx_funded = self.callnoderpc('fundrawtransaction', [tx_hex])
|
tx_funded = ci.rpc_wallet('fundrawtransaction', [tx_hex])
|
||||||
utxo_pos = 0 if tx_funded['changepos'] == 1 else 1
|
utxo_pos = 0 if tx_funded['changepos'] == 1 else 1
|
||||||
tx_signed = self.callnoderpc('signrawtransactionwithwallet', [tx_funded['hex'], ])['hex']
|
tx_signed = ci.rpc_wallet('signrawtransactionwithwallet', [tx_funded['hex'], ])['hex']
|
||||||
txid = self.callnoderpc('sendrawtransaction', [tx_signed, ])
|
txid = ci.rpc('sendrawtransaction', [tx_signed, ])
|
||||||
|
|
||||||
addr_out = self.callnoderpc('getnewaddress', ['csv test', 'bech32'])
|
addr_out = ci.rpc_wallet('getnewaddress', ['csv test', 'bech32'])
|
||||||
pkh = ci.decodeSegwitAddress(addr_out)
|
pkh = ci.decodeSegwitAddress(addr_out)
|
||||||
script_out = ci.getScriptForPubkeyHash(pkh)
|
script_out = ci.getScriptForPubkeyHash(pkh)
|
||||||
|
|
||||||
# Double check output type
|
# Double check output type
|
||||||
prev_tx = self.callnoderpc('decoderawtransaction', [tx_signed, ])
|
prev_tx = ci.rpc('decoderawtransaction', [tx_signed, ])
|
||||||
assert (prev_tx['vout'][utxo_pos]['scriptPubKey']['type'] == 'scripthash')
|
assert (prev_tx['vout'][utxo_pos]['scriptPubKey']['type'] == 'scripthash')
|
||||||
|
|
||||||
tx_spend = CTransaction()
|
tx_spend = CTransaction()
|
||||||
@ -836,9 +851,9 @@ class BasicSwapTest(TestFunctions):
|
|||||||
tx_spend.vout.append(ci.txoType()(ci.make_int(1.0999), script_out))
|
tx_spend.vout.append(ci.txoType()(ci.make_int(1.0999), script_out))
|
||||||
tx_spend_hex = ToHex(tx_spend)
|
tx_spend_hex = ToHex(tx_spend)
|
||||||
|
|
||||||
txid = self.callnoderpc('sendrawtransaction', [tx_spend_hex, ])
|
txid = ci.rpc('sendrawtransaction', [tx_spend_hex, ])
|
||||||
self.mineBlock(1)
|
self.mineBlock(1)
|
||||||
ro = self.callnoderpc('listreceivedbyaddress', [0, ])
|
ro = ci.rpc_wallet('listreceivedbyaddress', [0, ])
|
||||||
sum_addr = 0
|
sum_addr = 0
|
||||||
for entry in ro:
|
for entry in ro:
|
||||||
if entry['address'] == addr_out:
|
if entry['address'] == addr_out:
|
||||||
@ -846,7 +861,7 @@ class BasicSwapTest(TestFunctions):
|
|||||||
assert (sum_addr == 1.0999)
|
assert (sum_addr == 1.0999)
|
||||||
|
|
||||||
# Ensure tx was mined
|
# Ensure tx was mined
|
||||||
tx_wallet = self.callnoderpc('gettransaction', [txid, ])
|
tx_wallet = ci.rpc_wallet('gettransaction', [txid, ])
|
||||||
assert (len(tx_wallet['blockhash']) == 64)
|
assert (len(tx_wallet['blockhash']) == 64)
|
||||||
|
|
||||||
def test_012_p2sh_p2wsh(self):
|
def test_012_p2sh_p2wsh(self):
|
||||||
@ -863,17 +878,17 @@ class BasicSwapTest(TestFunctions):
|
|||||||
tx.nVersion = ci.txVersion()
|
tx.nVersion = ci.txVersion()
|
||||||
tx.vout.append(ci.txoType()(ci.make_int(1.1), script_dest))
|
tx.vout.append(ci.txoType()(ci.make_int(1.1), script_dest))
|
||||||
tx_hex = ToHex(tx)
|
tx_hex = ToHex(tx)
|
||||||
tx_funded = self.callnoderpc('fundrawtransaction', [tx_hex])
|
tx_funded = ci.rpc_wallet('fundrawtransaction', [tx_hex])
|
||||||
utxo_pos = 0 if tx_funded['changepos'] == 1 else 1
|
utxo_pos = 0 if tx_funded['changepos'] == 1 else 1
|
||||||
tx_signed = self.callnoderpc('signrawtransactionwithwallet', [tx_funded['hex'], ])['hex']
|
tx_signed = ci.rpc_wallet('signrawtransactionwithwallet', [tx_funded['hex'], ])['hex']
|
||||||
txid = self.callnoderpc('sendrawtransaction', [tx_signed, ])
|
txid = ci.rpc('sendrawtransaction', [tx_signed, ])
|
||||||
|
|
||||||
addr_out = self.callnoderpc('getnewaddress', ['csv test', 'bech32'])
|
addr_out = ci.rpc_wallet('getnewaddress', ['csv test', 'bech32'])
|
||||||
pkh = ci.decodeSegwitAddress(addr_out)
|
pkh = ci.decodeSegwitAddress(addr_out)
|
||||||
script_out = ci.getScriptForPubkeyHash(pkh)
|
script_out = ci.getScriptForPubkeyHash(pkh)
|
||||||
|
|
||||||
# Double check output type
|
# Double check output type
|
||||||
prev_tx = self.callnoderpc('decoderawtransaction', [tx_signed, ])
|
prev_tx = ci.rpc('decoderawtransaction', [tx_signed, ])
|
||||||
assert (prev_tx['vout'][utxo_pos]['scriptPubKey']['type'] == 'scripthash')
|
assert (prev_tx['vout'][utxo_pos]['scriptPubKey']['type'] == 'scripthash')
|
||||||
|
|
||||||
tx_spend = CTransaction()
|
tx_spend = CTransaction()
|
||||||
@ -885,9 +900,9 @@ class BasicSwapTest(TestFunctions):
|
|||||||
tx_spend.wit.vtxinwit[0].scriptWitness.stack = [script, ]
|
tx_spend.wit.vtxinwit[0].scriptWitness.stack = [script, ]
|
||||||
tx_spend_hex = ToHex(tx_spend)
|
tx_spend_hex = ToHex(tx_spend)
|
||||||
|
|
||||||
txid = self.callnoderpc('sendrawtransaction', [tx_spend_hex, ])
|
txid = ci.rpc('sendrawtransaction', [tx_spend_hex, ])
|
||||||
self.mineBlock(1)
|
self.mineBlock(1)
|
||||||
ro = self.callnoderpc('listreceivedbyaddress', [0, ])
|
ro = ci.rpc_wallet('listreceivedbyaddress', [0, ])
|
||||||
sum_addr = 0
|
sum_addr = 0
|
||||||
for entry in ro:
|
for entry in ro:
|
||||||
if entry['address'] == addr_out:
|
if entry['address'] == addr_out:
|
||||||
@ -895,7 +910,7 @@ class BasicSwapTest(TestFunctions):
|
|||||||
assert (sum_addr == 1.0999)
|
assert (sum_addr == 1.0999)
|
||||||
|
|
||||||
# Ensure tx was mined
|
# Ensure tx was mined
|
||||||
tx_wallet = self.callnoderpc('gettransaction', [txid, ])
|
tx_wallet = ci.rpc_wallet('gettransaction', [txid, ])
|
||||||
assert (len(tx_wallet['blockhash']) == 64)
|
assert (len(tx_wallet['blockhash']) == 64)
|
||||||
|
|
||||||
def test_01_a_full_swap(self):
|
def test_01_a_full_swap(self):
|
||||||
@ -1045,7 +1060,7 @@ class BasicSwapTest(TestFunctions):
|
|||||||
# Verify expected inputs were used
|
# Verify expected inputs were used
|
||||||
bid, _, _, _, _ = swap_clients[2].getXmrBidAndOffer(bid_id)
|
bid, _, _, _, _ = swap_clients[2].getXmrBidAndOffer(bid_id)
|
||||||
assert (bid.xmr_a_lock_tx)
|
assert (bid.xmr_a_lock_tx)
|
||||||
wtx = ci.rpc_callback('gettransaction', [bid.xmr_a_lock_tx.txid.hex(),])
|
wtx = ci.rpc_wallet('gettransaction', [bid.xmr_a_lock_tx.txid.hex(),])
|
||||||
itx_after = ci.describeTx(wtx['hex'])
|
itx_after = ci.describeTx(wtx['hex'])
|
||||||
assert (len(itx_after['vin']) == len(itx_decoded['vin']))
|
assert (len(itx_after['vin']) == len(itx_decoded['vin']))
|
||||||
for i, txin in enumerate(itx_decoded['vin']):
|
for i, txin in enumerate(itx_decoded['vin']):
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# Copyright (c) 2021-2022 tecnovert
|
# Copyright (c) 2021-2023 tecnovert
|
||||||
# Distributed under the MIT software license, see the accompanying
|
# Distributed under the MIT software license, see the accompanying
|
||||||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
@ -24,9 +24,10 @@ from tests.basicswap.common import (
|
|||||||
wait_for_bid,
|
wait_for_bid,
|
||||||
wait_for_offer,
|
wait_for_offer,
|
||||||
wait_for_in_progress,
|
wait_for_in_progress,
|
||||||
|
TEST_HTTP_PORT,
|
||||||
LTC_BASE_RPC_PORT,
|
LTC_BASE_RPC_PORT,
|
||||||
)
|
)
|
||||||
from .test_btc_xmr import BasicSwapTest, test_delay_event
|
from .test_btc_xmr import BasicSwapTest, test_delay_event, callnoderpc
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
@ -37,9 +38,20 @@ class TestLTC(BasicSwapTest):
|
|||||||
start_ltc_nodes = True
|
start_ltc_nodes = True
|
||||||
base_rpc_port = LTC_BASE_RPC_PORT
|
base_rpc_port = LTC_BASE_RPC_PORT
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def prepareExtraCoins(cls):
|
||||||
|
logging.info('Mining {} chain to height 1352 to activate CVS (BIP66)'.format(cls.test_coin_from.name))
|
||||||
|
chain_height = callnoderpc(0, 'getblockcount', base_rpc_port=LTC_BASE_RPC_PORT)
|
||||||
|
num_blocks: int = 1352 - chain_height
|
||||||
|
callnoderpc(0, 'generatetoaddress', [num_blocks, cls.ltc_addr], base_rpc_port=LTC_BASE_RPC_PORT)
|
||||||
|
|
||||||
def mineBlock(self, num_blocks=1):
|
def mineBlock(self, num_blocks=1):
|
||||||
self.callnoderpc('generatetoaddress', [num_blocks, self.ltc_addr])
|
self.callnoderpc('generatetoaddress', [num_blocks, self.ltc_addr])
|
||||||
|
|
||||||
|
def check_softfork_active(self, feature_name):
|
||||||
|
deploymentinfo = self.callnoderpc('getblockchaininfo')
|
||||||
|
assert (deploymentinfo['softforks'][feature_name]['active'] is True)
|
||||||
|
|
||||||
def test_001_nested_segwit(self):
|
def test_001_nested_segwit(self):
|
||||||
logging.info('---------- Test {} p2sh nested segwit'.format(self.test_coin_from.name))
|
logging.info('---------- Test {} p2sh nested segwit'.format(self.test_coin_from.name))
|
||||||
logging.info('Skipped')
|
logging.info('Skipped')
|
||||||
@ -47,17 +59,18 @@ class TestLTC(BasicSwapTest):
|
|||||||
def test_002_native_segwit(self):
|
def test_002_native_segwit(self):
|
||||||
logging.info('---------- Test {} p2sh native segwit'.format(self.test_coin_from.name))
|
logging.info('---------- Test {} p2sh native segwit'.format(self.test_coin_from.name))
|
||||||
|
|
||||||
addr_segwit = self.callnoderpc('getnewaddress', ['segwit test', 'bech32'])
|
ci = self.swap_clients[0].ci(self.test_coin_from)
|
||||||
addr_info = self.callnoderpc('getaddressinfo', [addr_segwit, ])
|
addr_segwit = ci.rpc_wallet('getnewaddress', ['segwit test', 'bech32'])
|
||||||
|
addr_info = ci.rpc_wallet('getaddressinfo', [addr_segwit, ])
|
||||||
assert addr_info['iswitness'] is True
|
assert addr_info['iswitness'] is True
|
||||||
|
|
||||||
txid = self.callnoderpc('sendtoaddress', [addr_segwit, 1.0])
|
txid = ci.rpc_wallet('sendtoaddress', [addr_segwit, 1.0])
|
||||||
assert len(txid) == 64
|
assert len(txid) == 64
|
||||||
tx_wallet = self.callnoderpc('gettransaction', [txid, ])['hex']
|
tx_wallet = ci.rpc_wallet('gettransaction', [txid, ])['hex']
|
||||||
tx = self.callnoderpc('decoderawtransaction', [tx_wallet, ])
|
tx = ci.rpc('decoderawtransaction', [tx_wallet, ])
|
||||||
|
|
||||||
self.mineBlock()
|
self.mineBlock()
|
||||||
ro = self.callnoderpc('scantxoutset', ['start', ['addr({})'.format(addr_segwit)]])
|
ro = ci.rpc('scantxoutset', ['start', ['addr({})'.format(addr_segwit)]])
|
||||||
assert (len(ro['unspents']) == 1)
|
assert (len(ro['unspents']) == 1)
|
||||||
assert (ro['unspents'][0]['txid'] == txid)
|
assert (ro['unspents'][0]['txid'] == txid)
|
||||||
|
|
||||||
@ -68,10 +81,10 @@ class TestLTC(BasicSwapTest):
|
|||||||
break
|
break
|
||||||
assert prevout_n > -1
|
assert prevout_n > -1
|
||||||
|
|
||||||
tx_funded = self.callnoderpc('createrawtransaction', [[{'txid': txid, 'vout': prevout_n}], {addr_segwit: 0.99}])
|
tx_funded = ci.rpc('createrawtransaction', [[{'txid': txid, 'vout': prevout_n}], {addr_segwit: 0.99}])
|
||||||
tx_signed = self.callnoderpc('signrawtransactionwithwallet', [tx_funded, ])['hex']
|
tx_signed = ci.rpc_wallet('signrawtransactionwithwallet', [tx_funded, ])['hex']
|
||||||
tx_funded_decoded = self.callnoderpc('decoderawtransaction', [tx_funded, ])
|
tx_funded_decoded = ci.rpc('decoderawtransaction', [tx_funded, ])
|
||||||
tx_signed_decoded = self.callnoderpc('decoderawtransaction', [tx_signed, ])
|
tx_signed_decoded = ci.rpc('decoderawtransaction', [tx_signed, ])
|
||||||
assert tx_funded_decoded['txid'] == tx_signed_decoded['txid']
|
assert tx_funded_decoded['txid'] == tx_signed_decoded['txid']
|
||||||
|
|
||||||
def test_007_hdwallet(self):
|
def test_007_hdwallet(self):
|
||||||
@ -108,6 +121,115 @@ class TestLTC(BasicSwapTest):
|
|||||||
assert (js_0['num_swapping'] == 0 and js_0['num_watched_outputs'] == 0)
|
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)
|
assert (js_1['num_swapping'] == 0 and js_1['num_watched_outputs'] == 0)
|
||||||
|
|
||||||
|
def test_21_mweb(self):
|
||||||
|
logging.info('---------- Test MWEB {}'.format(self.test_coin_from.name))
|
||||||
|
swap_clients = self.swap_clients
|
||||||
|
|
||||||
|
ci0 = swap_clients[0].ci(self.test_coin_from)
|
||||||
|
ci1 = swap_clients[1].ci(self.test_coin_from)
|
||||||
|
|
||||||
|
mweb_addr_0 = ci0.rpc_wallet('getnewaddress', ['mweb addr test 0', 'mweb'])
|
||||||
|
mweb_addr_1 = ci1.rpc_wallet('getnewaddress', ['mweb addr test 1', 'mweb'])
|
||||||
|
|
||||||
|
addr_info0 = ci0.rpc_wallet('getaddressinfo', [mweb_addr_0,])
|
||||||
|
assert (addr_info0['ismweb'] is True)
|
||||||
|
|
||||||
|
addr_info1 = ci1.rpc_wallet('getaddressinfo', [mweb_addr_1,])
|
||||||
|
assert (addr_info1['ismweb'] is True)
|
||||||
|
|
||||||
|
txid = ci0.rpc_wallet('sendtoaddress', [mweb_addr_0, 10.0])
|
||||||
|
|
||||||
|
self.mineBlock()
|
||||||
|
|
||||||
|
txns = ci0.rpc_wallet('listtransactions')
|
||||||
|
|
||||||
|
utxos = ci0.rpc_wallet('listunspent')
|
||||||
|
balances = ci0.rpc_wallet('getbalances')
|
||||||
|
wi = ci0.rpc_wallet('getwalletinfo')
|
||||||
|
|
||||||
|
txid = ci0.rpc_wallet('sendtoaddress', [mweb_addr_1, 10.0])
|
||||||
|
|
||||||
|
self.mineBlock()
|
||||||
|
|
||||||
|
txns = ci1.rpc_wallet('listtransactions')
|
||||||
|
|
||||||
|
utxos = ci1.rpc_wallet('listunspent')
|
||||||
|
balances = ci1.rpc_wallet('getbalances')
|
||||||
|
wi = ci1.rpc_wallet('getwalletinfo')
|
||||||
|
|
||||||
|
mweb_tx = None
|
||||||
|
for utxo in utxos:
|
||||||
|
if utxo.get('address', '') == mweb_addr_1:
|
||||||
|
mweb_tx = utxo
|
||||||
|
assert (mweb_tx is not None)
|
||||||
|
|
||||||
|
tx = ci1.rpc_wallet('gettransaction', [mweb_tx['txid'],])
|
||||||
|
|
||||||
|
blockhash = tx['blockhash']
|
||||||
|
block = ci1.rpc('getblock', [blockhash, 3])
|
||||||
|
block = ci1.rpc('getblock', [blockhash, 0])
|
||||||
|
|
||||||
|
# TODO
|
||||||
|
|
||||||
|
def test_22_mweb_balance(self):
|
||||||
|
logging.info('---------- Test MWEB balance {}'.format(self.test_coin_from.name))
|
||||||
|
swap_clients = self.swap_clients
|
||||||
|
|
||||||
|
ci_mweb = swap_clients[0].ci(Coins.LTC_MWEB)
|
||||||
|
mweb_addr_0 = ci_mweb.getNewAddress()
|
||||||
|
addr_info0 = ci_mweb.rpc_wallet('getaddressinfo', [mweb_addr_0,])
|
||||||
|
assert (addr_info0['ismweb'] is True)
|
||||||
|
|
||||||
|
ltc_addr = read_json_api(TEST_HTTP_PORT + 0, 'wallets/ltc/nextdepositaddr')
|
||||||
|
ltc_mweb_addr = read_json_api(TEST_HTTP_PORT + 0, 'wallets/ltc_mweb/nextdepositaddr')
|
||||||
|
ltc_mweb_addr2 = read_json_api(TEST_HTTP_PORT + 0, 'wallets/ltc/newmwebaddress')
|
||||||
|
|
||||||
|
assert (ci_mweb.rpc_wallet('getaddressinfo', [ltc_addr,])['ismweb'] is False)
|
||||||
|
assert (ci_mweb.rpc_wallet('getaddressinfo', [ltc_mweb_addr,])['ismweb'] is True)
|
||||||
|
assert (ci_mweb.rpc_wallet('getaddressinfo', [ltc_mweb_addr2,])['ismweb'] is True)
|
||||||
|
|
||||||
|
post_json = {
|
||||||
|
'value': 10,
|
||||||
|
'address': ltc_mweb_addr,
|
||||||
|
'subfee': False,
|
||||||
|
}
|
||||||
|
json_rv = read_json_api(TEST_HTTP_PORT + 0, 'wallets/ltc/withdraw', post_json)
|
||||||
|
assert (len(json_rv['txid']) == 64)
|
||||||
|
|
||||||
|
self.mineBlock()
|
||||||
|
|
||||||
|
json_rv = read_json_api(TEST_HTTP_PORT + 0, 'wallets/ltc', post_json)
|
||||||
|
assert (json_rv['mweb_balance'] == 10.0)
|
||||||
|
mweb_address = json_rv['mweb_address']
|
||||||
|
|
||||||
|
post_json = {
|
||||||
|
'value': 11,
|
||||||
|
'address': mweb_address,
|
||||||
|
'subfee': False,
|
||||||
|
}
|
||||||
|
json_rv = read_json_api(TEST_HTTP_PORT + 0, 'wallets/ltc/withdraw', post_json)
|
||||||
|
assert (len(json_rv['txid']) == 64)
|
||||||
|
|
||||||
|
self.mineBlock()
|
||||||
|
|
||||||
|
json_rv = read_json_api(TEST_HTTP_PORT + 0, 'wallets/ltc_mweb', post_json)
|
||||||
|
assert (json_rv['mweb_balance'] == 21.0)
|
||||||
|
assert (json_rv['mweb_address'] == mweb_address)
|
||||||
|
ltc_address = json_rv['deposit_address']
|
||||||
|
|
||||||
|
# Check that spending the mweb balance takes from the correct wallet
|
||||||
|
post_json = {
|
||||||
|
'value': 1,
|
||||||
|
'address': ltc_address,
|
||||||
|
'subfee': False,
|
||||||
|
'type_from': 'mweb',
|
||||||
|
}
|
||||||
|
json_rv = read_json_api(TEST_HTTP_PORT + 0, 'wallets/ltc/withdraw', post_json)
|
||||||
|
assert (len(json_rv['txid']) == 64)
|
||||||
|
|
||||||
|
json_rv = read_json_api(TEST_HTTP_PORT + 0, 'wallets/ltc', post_json)
|
||||||
|
assert (json_rv['mweb_balance'] <= 20.0)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
@ -101,7 +101,7 @@ class Test(BaseTest):
|
|||||||
nonlocal ci
|
nonlocal ci
|
||||||
i = 0
|
i = 0
|
||||||
while not delay_event.is_set():
|
while not delay_event.is_set():
|
||||||
unspents = ci.rpc_callback('listunspentblind')
|
unspents = ci.rpc_wallet('listunspentblind')
|
||||||
if len(unspents) >= 1:
|
if len(unspents) >= 1:
|
||||||
return
|
return
|
||||||
delay_event.wait(delay_time)
|
delay_event.wait(delay_time)
|
||||||
@ -113,8 +113,8 @@ class Test(BaseTest):
|
|||||||
amount: int = ci.make_int(random.uniform(0.1, 2.0), r=1)
|
amount: int = ci.make_int(random.uniform(0.1, 2.0), r=1)
|
||||||
|
|
||||||
# Record unspents before createSCLockTx as the used ones will be locked
|
# Record unspents before createSCLockTx as the used ones will be locked
|
||||||
unspents = ci.rpc_callback('listunspentblind')
|
unspents = ci.rpc_wallet('listunspentblind')
|
||||||
locked_utxos_before = ci.rpc_callback('listlockunspent')
|
locked_utxos_before = ci.rpc_wallet('listlockunspent')
|
||||||
|
|
||||||
# fee_rate is in sats/kvB
|
# fee_rate is in sats/kvB
|
||||||
fee_rate: int = 1000
|
fee_rate: int = 1000
|
||||||
@ -131,33 +131,33 @@ class Test(BaseTest):
|
|||||||
lock_tx = ci.fundSCLockTx(lock_tx, fee_rate, vkbv)
|
lock_tx = ci.fundSCLockTx(lock_tx, fee_rate, vkbv)
|
||||||
lock_tx = ci.signTxWithWallet(lock_tx)
|
lock_tx = ci.signTxWithWallet(lock_tx)
|
||||||
|
|
||||||
unspents_after = ci.rpc_callback('listunspentblind')
|
unspents_after = ci.rpc_wallet('listunspentblind')
|
||||||
locked_utxos_after = ci.rpc_callback('listlockunspent')
|
locked_utxos_after = ci.rpc_wallet('listlockunspent')
|
||||||
|
|
||||||
assert (len(unspents) > len(unspents_after))
|
assert (len(unspents) > len(unspents_after))
|
||||||
assert (len(locked_utxos_after) > len(locked_utxos_before))
|
assert (len(locked_utxos_after) > len(locked_utxos_before))
|
||||||
lock_tx_decoded = ci.rpc_callback('decoderawtransaction', [lock_tx.hex()])
|
lock_tx_decoded = ci.rpc_wallet('decoderawtransaction', [lock_tx.hex()])
|
||||||
txid = lock_tx_decoded['txid']
|
txid = lock_tx_decoded['txid']
|
||||||
|
|
||||||
vsize = lock_tx_decoded['vsize']
|
vsize = lock_tx_decoded['vsize']
|
||||||
expect_fee_int = round(fee_rate * vsize / 1000)
|
expect_fee_int = round(fee_rate * vsize / 1000)
|
||||||
expect_fee = ci.format_amount(expect_fee_int)
|
expect_fee = ci.format_amount(expect_fee_int)
|
||||||
|
|
||||||
ci.rpc_callback('sendrawtransaction', [lock_tx.hex()])
|
ci.rpc_wallet('sendrawtransaction', [lock_tx.hex()])
|
||||||
rv = ci.rpc_callback('gettransaction', [txid])
|
rv = ci.rpc_wallet('gettransaction', [txid])
|
||||||
wallet_tx_fee = -ci.make_int(rv['details'][0]['fee'])
|
wallet_tx_fee = -ci.make_int(rv['details'][0]['fee'])
|
||||||
|
|
||||||
assert (wallet_tx_fee >= expect_fee_int)
|
assert (wallet_tx_fee >= expect_fee_int)
|
||||||
assert (wallet_tx_fee - expect_fee_int < 20)
|
assert (wallet_tx_fee - expect_fee_int < 20)
|
||||||
|
|
||||||
addr_out = ci.getNewAddress(True)
|
addr_out = ci.getNewAddress(True)
|
||||||
addrinfo = ci.rpc_callback('getaddressinfo', [addr_out,])
|
addrinfo = ci.rpc_wallet('getaddressinfo', [addr_out,])
|
||||||
pk_out = bytes.fromhex(addrinfo['pubkey'])
|
pk_out = bytes.fromhex(addrinfo['pubkey'])
|
||||||
fee_info = {}
|
fee_info = {}
|
||||||
lock_spend_tx = ci.createSCLockSpendTx(lock_tx, lock_tx_script, pk_out, fee_rate, vkbv, fee_info=fee_info)
|
lock_spend_tx = ci.createSCLockSpendTx(lock_tx, lock_tx_script, pk_out, fee_rate, vkbv, fee_info=fee_info)
|
||||||
vsize_estimated: int = fee_info['vsize']
|
vsize_estimated: int = fee_info['vsize']
|
||||||
|
|
||||||
spend_tx_decoded = ci.rpc_callback('decoderawtransaction', [lock_spend_tx.hex()])
|
spend_tx_decoded = ci.rpc('decoderawtransaction', [lock_spend_tx.hex()])
|
||||||
txid = spend_tx_decoded['txid']
|
txid = spend_tx_decoded['txid']
|
||||||
|
|
||||||
nonce = ci.getScriptLockTxNonce(vkbv)
|
nonce = ci.getScriptLockTxNonce(vkbv)
|
||||||
@ -172,12 +172,12 @@ class Test(BaseTest):
|
|||||||
lock_tx_script,
|
lock_tx_script,
|
||||||
]
|
]
|
||||||
lock_spend_tx = ci.setTxSignature(lock_spend_tx, witness_stack)
|
lock_spend_tx = ci.setTxSignature(lock_spend_tx, witness_stack)
|
||||||
tx_decoded = ci.rpc_callback('decoderawtransaction', [lock_spend_tx.hex()])
|
tx_decoded = ci.rpc('decoderawtransaction', [lock_spend_tx.hex()])
|
||||||
vsize_actual: int = tx_decoded['vsize']
|
vsize_actual: int = tx_decoded['vsize']
|
||||||
|
|
||||||
# Note: The fee is set allowing 9 bytes for the encoded fee amount, causing a small overestimate
|
# Note: The fee is set allowing 9 bytes for the encoded fee amount, causing a small overestimate
|
||||||
assert (vsize_actual <= vsize_estimated and vsize_estimated - vsize_actual < 10)
|
assert (vsize_actual <= vsize_estimated and vsize_estimated - vsize_actual < 10)
|
||||||
assert (ci.rpc_callback('sendrawtransaction', [lock_spend_tx.hex()]) == txid)
|
assert (ci.rpc('sendrawtransaction', [lock_spend_tx.hex()]) == txid)
|
||||||
|
|
||||||
# Test chain b (no-script) lock tx size
|
# Test chain b (no-script) lock tx size
|
||||||
v = ci.getNewSecretKey()
|
v = ci.getNewSecretKey()
|
||||||
@ -198,7 +198,7 @@ class Test(BaseTest):
|
|||||||
lock_tx_b_spend = ci.getTransaction(lock_tx_b_spend_txid)
|
lock_tx_b_spend = ci.getTransaction(lock_tx_b_spend_txid)
|
||||||
if lock_tx_b_spend is None:
|
if lock_tx_b_spend is None:
|
||||||
lock_tx_b_spend = ci.getWalletTransaction(lock_tx_b_spend_txid)
|
lock_tx_b_spend = ci.getWalletTransaction(lock_tx_b_spend_txid)
|
||||||
lock_tx_b_spend_decoded = ci.rpc_callback('decoderawtransaction', [lock_tx_b_spend.hex()])
|
lock_tx_b_spend_decoded = ci.rpc('decoderawtransaction', [lock_tx_b_spend.hex()])
|
||||||
|
|
||||||
expect_vsize: int = ci.xmr_swap_b_lock_spend_tx_vsize()
|
expect_vsize: int = ci.xmr_swap_b_lock_spend_tx_vsize()
|
||||||
assert (expect_vsize >= lock_tx_b_spend_decoded['vsize'])
|
assert (expect_vsize >= lock_tx_b_spend_decoded['vsize'])
|
||||||
@ -472,7 +472,7 @@ class Test(BaseTest):
|
|||||||
# Verify expected inputs were used
|
# Verify expected inputs were used
|
||||||
bid, _, _, _, _ = swap_clients[2].getXmrBidAndOffer(bid_id)
|
bid, _, _, _, _ = swap_clients[2].getXmrBidAndOffer(bid_id)
|
||||||
assert (bid.xmr_a_lock_tx)
|
assert (bid.xmr_a_lock_tx)
|
||||||
wtx = ci.rpc_callback('gettransaction', [bid.xmr_a_lock_tx.txid.hex(),])
|
wtx = ci.rpc_wallet('gettransaction', [bid.xmr_a_lock_tx.txid.hex(),])
|
||||||
itx_after = ci.describeTx(wtx['hex'])
|
itx_after = ci.describeTx(wtx['hex'])
|
||||||
assert (len(itx_after['vin']) == len(itx_decoded['vin']))
|
assert (len(itx_after['vin']) == len(itx_decoded['vin']))
|
||||||
for i, txin in enumerate(itx_decoded['vin']):
|
for i, txin in enumerate(itx_decoded['vin']):
|
||||||
|
@ -80,10 +80,10 @@ class Test(BaseTest):
|
|||||||
super(Test, cls).setUpClass()
|
super(Test, cls).setUpClass()
|
||||||
|
|
||||||
btc_addr1 = callnoderpc(1, 'getnewaddress', ['initial funds', 'bech32'], base_rpc_port=BTC_BASE_RPC_PORT)
|
btc_addr1 = callnoderpc(1, 'getnewaddress', ['initial funds', 'bech32'], base_rpc_port=BTC_BASE_RPC_PORT)
|
||||||
ltc_addr1 = callnoderpc(1, 'getnewaddress', ['initial funds', 'bech32'], base_rpc_port=LTC_BASE_RPC_PORT)
|
ltc_addr1 = callnoderpc(1, 'getnewaddress', ['initial funds', 'bech32'], base_rpc_port=LTC_BASE_RPC_PORT, wallet='wallet.dat')
|
||||||
|
|
||||||
callnoderpc(0, 'sendtoaddress', [btc_addr1, 1000], base_rpc_port=BTC_BASE_RPC_PORT)
|
callnoderpc(0, 'sendtoaddress', [btc_addr1, 1000], base_rpc_port=BTC_BASE_RPC_PORT)
|
||||||
callnoderpc(0, 'sendtoaddress', [ltc_addr1, 1000], base_rpc_port=LTC_BASE_RPC_PORT)
|
callnoderpc(0, 'sendtoaddress', [ltc_addr1, 1000], base_rpc_port=LTC_BASE_RPC_PORT, wallet='wallet.dat')
|
||||||
|
|
||||||
wait_for_balance(test_delay_event, 'http://127.0.0.1:1801/json/wallets/btc', 'balance', 1000.0)
|
wait_for_balance(test_delay_event, 'http://127.0.0.1:1801/json/wallets/btc', 'balance', 1000.0)
|
||||||
wait_for_balance(test_delay_event, 'http://127.0.0.1:1801/json/wallets/ltc', 'balance', 1000.0)
|
wait_for_balance(test_delay_event, 'http://127.0.0.1:1801/json/wallets/ltc', 'balance', 1000.0)
|
||||||
@ -182,6 +182,9 @@ class Test(BaseTest):
|
|||||||
rv = read_json_api(1800, 'automationstrategies/1')
|
rv = read_json_api(1800, 'automationstrategies/1')
|
||||||
assert (rv['label'] == 'Accept All')
|
assert (rv['label'] == 'Accept All')
|
||||||
|
|
||||||
|
sx_addr = read_json_api(1800, 'wallets/part/newstealthaddress')
|
||||||
|
assert (callnoderpc(0, 'getaddressinfo', [sx_addr, ])['isstealthaddress'] is True)
|
||||||
|
|
||||||
def test_004_validateSwapType(self):
|
def test_004_validateSwapType(self):
|
||||||
logging.info('---------- Test validateSwapType')
|
logging.info('---------- Test validateSwapType')
|
||||||
|
|
||||||
@ -570,7 +573,7 @@ class Test(BaseTest):
|
|||||||
def test_12_withdrawal(self):
|
def test_12_withdrawal(self):
|
||||||
logging.info('---------- Test LTC withdrawals')
|
logging.info('---------- Test LTC withdrawals')
|
||||||
|
|
||||||
ltc_addr = callnoderpc(0, 'getnewaddress', ['Withdrawal test', 'legacy'], base_rpc_port=LTC_BASE_RPC_PORT)
|
ltc_addr = callnoderpc(0, 'getnewaddress', ['Withdrawal test', 'legacy'], base_rpc_port=LTC_BASE_RPC_PORT, wallet='wallet.dat')
|
||||||
wallets0 = read_json_api(TEST_HTTP_PORT + 0, 'wallets')
|
wallets0 = read_json_api(TEST_HTTP_PORT + 0, 'wallets')
|
||||||
assert (float(wallets0['LTC']['balance']) > 100)
|
assert (float(wallets0['LTC']['balance']) > 100)
|
||||||
|
|
||||||
@ -712,7 +715,7 @@ class Test(BaseTest):
|
|||||||
# Verify expected inputs were used
|
# Verify expected inputs were used
|
||||||
bid, offer = swap_clients[2].getBidAndOffer(bid_id)
|
bid, offer = swap_clients[2].getBidAndOffer(bid_id)
|
||||||
assert (bid.initiate_tx)
|
assert (bid.initiate_tx)
|
||||||
wtx = ci.rpc_callback('gettransaction', [bid.initiate_tx.txid.hex(),])
|
wtx = ci.rpc('gettransaction', [bid.initiate_tx.txid.hex(),])
|
||||||
itx_after = ci.describeTx(wtx['hex'])
|
itx_after = ci.describeTx(wtx['hex'])
|
||||||
assert (len(itx_after['vin']) == len(itx_decoded['vin']))
|
assert (len(itx_after['vin']) == len(itx_decoded['vin']))
|
||||||
for i, txin in enumerate(itx_decoded['vin']):
|
for i, txin in enumerate(itx_decoded['vin']):
|
||||||
|
@ -530,29 +530,29 @@ class BaseTest(unittest.TestCase):
|
|||||||
|
|
||||||
if cls.start_ltc_nodes:
|
if cls.start_ltc_nodes:
|
||||||
num_blocks = 400
|
num_blocks = 400
|
||||||
cls.ltc_addr = callnoderpc(0, 'getnewaddress', ['mining_addr', 'bech32'], base_rpc_port=LTC_BASE_RPC_PORT)
|
cls.ltc_addr = callnoderpc(0, 'getnewaddress', ['mining_addr', 'bech32'], base_rpc_port=LTC_BASE_RPC_PORT, wallet='wallet.dat')
|
||||||
logging.info('Mining %d Litecoin blocks to %s', num_blocks, cls.ltc_addr)
|
logging.info('Mining %d Litecoin blocks to %s', num_blocks, cls.ltc_addr)
|
||||||
callnoderpc(0, 'generatetoaddress', [num_blocks, cls.ltc_addr], base_rpc_port=LTC_BASE_RPC_PORT)
|
callnoderpc(0, 'generatetoaddress', [num_blocks, cls.ltc_addr], base_rpc_port=LTC_BASE_RPC_PORT, wallet='wallet.dat')
|
||||||
|
|
||||||
num_blocks = 31
|
num_blocks = 31
|
||||||
cls.ltc_addr = cls.swap_clients[0].ci(Coins.LTC).pubkey_to_address(void_block_rewards_pubkey)
|
cls.ltc_addr = cls.swap_clients[0].ci(Coins.LTC).pubkey_to_address(void_block_rewards_pubkey)
|
||||||
logging.info('Mining %d Litecoin blocks to %s', num_blocks, cls.ltc_addr)
|
logging.info('Mining %d Litecoin blocks to %s', num_blocks, cls.ltc_addr)
|
||||||
callnoderpc(0, 'generatetoaddress', [num_blocks, cls.ltc_addr], base_rpc_port=LTC_BASE_RPC_PORT)
|
callnoderpc(0, 'generatetoaddress', [num_blocks, cls.ltc_addr], base_rpc_port=LTC_BASE_RPC_PORT, wallet='wallet.dat')
|
||||||
|
|
||||||
# https://github.com/litecoin-project/litecoin/issues/807
|
# https://github.com/litecoin-project/litecoin/issues/807
|
||||||
# Block 432 is when MWEB activates. It requires a peg-in. You'll need to generate an mweb address and send some coins to it. Then it will allow you to mine the next block.
|
# Block 432 is when MWEB activates. It requires a peg-in. You'll need to generate an mweb address and send some coins to it. Then it will allow you to mine the next block.
|
||||||
mweb_addr = callnoderpc(2, 'getnewaddress', ['mweb_addr', 'mweb'], base_rpc_port=LTC_BASE_RPC_PORT)
|
mweb_addr = callnoderpc(2, 'getnewaddress', ['mweb_addr', 'mweb'], base_rpc_port=LTC_BASE_RPC_PORT, wallet='wallet.dat')
|
||||||
callnoderpc(0, 'sendtoaddress', [mweb_addr, 1], base_rpc_port=LTC_BASE_RPC_PORT)
|
callnoderpc(0, 'sendtoaddress', [mweb_addr, 1], base_rpc_port=LTC_BASE_RPC_PORT, wallet='wallet.dat')
|
||||||
|
|
||||||
ltc_addr1 = callnoderpc(1, 'getnewaddress', ['initial addr'], base_rpc_port=LTC_BASE_RPC_PORT)
|
ltc_addr1 = callnoderpc(1, 'getnewaddress', ['initial addr'], base_rpc_port=LTC_BASE_RPC_PORT, wallet='wallet.dat')
|
||||||
for i in range(5):
|
for i in range(5):
|
||||||
callnoderpc(0, 'sendtoaddress', [ltc_addr1, 100], base_rpc_port=LTC_BASE_RPC_PORT)
|
callnoderpc(0, 'sendtoaddress', [ltc_addr1, 100], base_rpc_port=LTC_BASE_RPC_PORT, wallet='wallet.dat')
|
||||||
|
|
||||||
num_blocks = 69
|
num_blocks = 69
|
||||||
cls.ltc_addr = cls.swap_clients[0].ci(Coins.LTC).pubkey_to_address(void_block_rewards_pubkey)
|
cls.ltc_addr = cls.swap_clients[0].ci(Coins.LTC).pubkey_to_address(void_block_rewards_pubkey)
|
||||||
callnoderpc(0, 'generatetoaddress', [num_blocks, cls.ltc_addr], base_rpc_port=LTC_BASE_RPC_PORT)
|
callnoderpc(0, 'generatetoaddress', [num_blocks, cls.ltc_addr], base_rpc_port=LTC_BASE_RPC_PORT, wallet='wallet.dat')
|
||||||
|
|
||||||
checkForks(callnoderpc(0, 'getblockchaininfo', base_rpc_port=LTC_BASE_RPC_PORT))
|
checkForks(callnoderpc(0, 'getblockchaininfo', base_rpc_port=LTC_BASE_RPC_PORT, wallet='wallet.dat'))
|
||||||
|
|
||||||
num_blocks = 100
|
num_blocks = 100
|
||||||
if cls.start_xmr_nodes:
|
if cls.start_xmr_nodes:
|
||||||
@ -682,7 +682,7 @@ class Test(BaseTest):
|
|||||||
amount: int = ci.make_int(random.uniform(0.1, 2.0), r=1)
|
amount: int = ci.make_int(random.uniform(0.1, 2.0), r=1)
|
||||||
|
|
||||||
# Record unspents before createSCLockTx as the used ones will be locked
|
# Record unspents before createSCLockTx as the used ones will be locked
|
||||||
unspents = ci.rpc_callback('listunspent')
|
unspents = ci.rpc('listunspent')
|
||||||
|
|
||||||
# fee_rate is in sats/kvB
|
# fee_rate is in sats/kvB
|
||||||
fee_rate: int = 1000
|
fee_rate: int = 1000
|
||||||
@ -698,10 +698,10 @@ class Test(BaseTest):
|
|||||||
lock_tx = ci.fundSCLockTx(lock_tx, fee_rate)
|
lock_tx = ci.fundSCLockTx(lock_tx, fee_rate)
|
||||||
lock_tx = ci.signTxWithWallet(lock_tx)
|
lock_tx = ci.signTxWithWallet(lock_tx)
|
||||||
|
|
||||||
unspents_after = ci.rpc_callback('listunspent')
|
unspents_after = ci.rpc('listunspent')
|
||||||
assert (len(unspents) > len(unspents_after))
|
assert (len(unspents) > len(unspents_after))
|
||||||
|
|
||||||
tx_decoded = ci.rpc_callback('decoderawtransaction', [lock_tx.hex()])
|
tx_decoded = ci.rpc('decoderawtransaction', [lock_tx.hex()])
|
||||||
txid = tx_decoded['txid']
|
txid = tx_decoded['txid']
|
||||||
|
|
||||||
vsize = tx_decoded['vsize']
|
vsize = tx_decoded['vsize']
|
||||||
@ -722,8 +722,8 @@ class Test(BaseTest):
|
|||||||
break
|
break
|
||||||
fee_value = in_value - out_value
|
fee_value = in_value - out_value
|
||||||
|
|
||||||
ci.rpc_callback('sendrawtransaction', [lock_tx.hex()])
|
ci.rpc('sendrawtransaction', [lock_tx.hex()])
|
||||||
rv = ci.rpc_callback('gettransaction', [txid])
|
rv = ci.rpc('gettransaction', [txid])
|
||||||
wallet_tx_fee = -ci.make_int(rv['fee'])
|
wallet_tx_fee = -ci.make_int(rv['fee'])
|
||||||
|
|
||||||
assert (wallet_tx_fee == fee_value)
|
assert (wallet_tx_fee == fee_value)
|
||||||
@ -735,7 +735,7 @@ class Test(BaseTest):
|
|||||||
lock_spend_tx = ci.createSCLockSpendTx(lock_tx, lock_tx_script, pkh_out, fee_rate, fee_info=fee_info)
|
lock_spend_tx = ci.createSCLockSpendTx(lock_tx, lock_tx_script, pkh_out, fee_rate, fee_info=fee_info)
|
||||||
vsize_estimated: int = fee_info['vsize']
|
vsize_estimated: int = fee_info['vsize']
|
||||||
|
|
||||||
tx_decoded = ci.rpc_callback('decoderawtransaction', [lock_spend_tx.hex()])
|
tx_decoded = ci.rpc('decoderawtransaction', [lock_spend_tx.hex()])
|
||||||
txid = tx_decoded['txid']
|
txid = tx_decoded['txid']
|
||||||
|
|
||||||
witness_stack = [
|
witness_stack = [
|
||||||
@ -745,11 +745,11 @@ class Test(BaseTest):
|
|||||||
lock_tx_script,
|
lock_tx_script,
|
||||||
]
|
]
|
||||||
lock_spend_tx = ci.setTxSignature(lock_spend_tx, witness_stack)
|
lock_spend_tx = ci.setTxSignature(lock_spend_tx, witness_stack)
|
||||||
tx_decoded = ci.rpc_callback('decoderawtransaction', [lock_spend_tx.hex()])
|
tx_decoded = ci.rpc('decoderawtransaction', [lock_spend_tx.hex()])
|
||||||
vsize_actual: int = tx_decoded['vsize']
|
vsize_actual: int = tx_decoded['vsize']
|
||||||
|
|
||||||
assert (vsize_actual <= vsize_estimated and vsize_estimated - vsize_actual < 4)
|
assert (vsize_actual <= vsize_estimated and vsize_estimated - vsize_actual < 4)
|
||||||
assert (ci.rpc_callback('sendrawtransaction', [lock_spend_tx.hex()]) == txid)
|
assert (ci.rpc('sendrawtransaction', [lock_spend_tx.hex()]) == txid)
|
||||||
|
|
||||||
expect_vsize: int = ci.xmr_swap_a_lock_spend_tx_vsize()
|
expect_vsize: int = ci.xmr_swap_a_lock_spend_tx_vsize()
|
||||||
assert (expect_vsize >= vsize_actual)
|
assert (expect_vsize >= vsize_actual)
|
||||||
@ -766,7 +766,7 @@ class Test(BaseTest):
|
|||||||
lock_tx_b_spend = ci.getTransaction(lock_tx_b_spend_txid)
|
lock_tx_b_spend = ci.getTransaction(lock_tx_b_spend_txid)
|
||||||
if lock_tx_b_spend is None:
|
if lock_tx_b_spend is None:
|
||||||
lock_tx_b_spend = ci.getWalletTransaction(lock_tx_b_spend_txid)
|
lock_tx_b_spend = ci.getWalletTransaction(lock_tx_b_spend_txid)
|
||||||
lock_tx_b_spend_decoded = ci.rpc_callback('decoderawtransaction', [lock_tx_b_spend.hex()])
|
lock_tx_b_spend_decoded = ci.rpc('decoderawtransaction', [lock_tx_b_spend.hex()])
|
||||||
|
|
||||||
expect_vsize: int = ci.xmr_swap_b_lock_spend_tx_vsize()
|
expect_vsize: int = ci.xmr_swap_b_lock_spend_tx_vsize()
|
||||||
assert (expect_vsize >= lock_tx_b_spend_decoded['vsize'])
|
assert (expect_vsize >= lock_tx_b_spend_decoded['vsize'])
|
||||||
@ -1354,7 +1354,7 @@ class Test(BaseTest):
|
|||||||
lock_tx_b_spend = ci.getTransaction(lock_tx_b_spend_txid)
|
lock_tx_b_spend = ci.getTransaction(lock_tx_b_spend_txid)
|
||||||
if lock_tx_b_spend is None:
|
if lock_tx_b_spend is None:
|
||||||
lock_tx_b_spend = ci.getWalletTransaction(lock_tx_b_spend_txid)
|
lock_tx_b_spend = ci.getWalletTransaction(lock_tx_b_spend_txid)
|
||||||
lock_tx_b_spend_decoded = ci.rpc_callback('decoderawtransaction', [lock_tx_b_spend.hex()])
|
lock_tx_b_spend_decoded = ci.rpc('decoderawtransaction', [lock_tx_b_spend.hex()])
|
||||||
|
|
||||||
expect_vsize: int = ci.xmr_swap_b_lock_spend_tx_vsize()
|
expect_vsize: int = ci.xmr_swap_b_lock_spend_tx_vsize()
|
||||||
assert (expect_vsize >= lock_tx_b_spend_decoded['vsize'])
|
assert (expect_vsize >= lock_tx_b_spend_decoded['vsize'])
|
||||||
@ -1501,7 +1501,7 @@ class Test(BaseTest):
|
|||||||
# Verify expected inputs were used
|
# Verify expected inputs were used
|
||||||
bid, _, _, _, _ = swap_clients[2].getXmrBidAndOffer(bid_id)
|
bid, _, _, _, _ = swap_clients[2].getXmrBidAndOffer(bid_id)
|
||||||
assert (bid.xmr_a_lock_tx)
|
assert (bid.xmr_a_lock_tx)
|
||||||
wtx = ci.rpc_callback('gettransaction', [bid.xmr_a_lock_tx.txid.hex(),])
|
wtx = ci.rpc('gettransaction', [bid.xmr_a_lock_tx.txid.hex(),])
|
||||||
itx_after = ci.describeTx(wtx['hex'])
|
itx_after = ci.describeTx(wtx['hex'])
|
||||||
assert (len(itx_after['vin']) == len(itx_decoded['vin']))
|
assert (len(itx_after['vin']) == len(itx_decoded['vin']))
|
||||||
for i, txin in enumerate(itx_decoded['vin']):
|
for i, txin in enumerate(itx_decoded['vin']):
|
||||||
|
Loading…
Reference in New Issue
Block a user