|
|
|
#!/usr/bin/env python
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
# Copyright (c) 2020-2023 tecnovert
|
|
|
|
# Distributed under the MIT software license, see the accompanying
|
|
|
|
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
|
|
|
|
from .btc import BTCInterface
|
|
|
|
from basicswap.rpc import make_rpc_func
|
|
|
|
from basicswap.chainparams import Coins, chainparams
|
|
|
|
|
|
|
|
|
|
|
|
class LTCInterface(BTCInterface):
|
|
|
|
@staticmethod
|
|
|
|
def coin_type():
|
|
|
|
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 createUTXO(self, value_sats: int):
|
|
|
|
# Create a new address and send value_sats to it
|
|
|
|
|
|
|
|
spendable_balance = self.getSpendableBalance()
|
|
|
|
if spendable_balance < value_sats:
|
|
|
|
raise ValueError('Balance too low')
|
|
|
|
|
|
|
|
address = self.getNewAddress(self._use_segwit, 'create_utxo')
|
|
|
|
return self.withdrawCoin(self.format_amount(value_sats), 'plain', address, False), address
|
|
|
|
|
|
|
|
def getWalletInfo(self):
|
|
|
|
rv = super(LTCInterface, self).getWalletInfo()
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
def getUnspentsByAddr(self):
|
|
|
|
unspent_addr = dict()
|
|
|
|
unspent = self.rpc_wallet('listunspent')
|
|
|
|
for u in unspent:
|
|
|
|
if u.get('spendable', False) is False:
|
|
|
|
continue
|
|
|
|
if u.get('solvable', False) is False: # Filter out mweb outputs
|
|
|
|
continue
|
|
|
|
if 'address' not in u:
|
|
|
|
continue
|
|
|
|
if 'desc' in u:
|
|
|
|
desc = u['desc']
|
|
|
|
if self.using_segwit:
|
|
|
|
if self.use_p2shp2wsh():
|
|
|
|
if not desc.startswith('sh(wpkh'):
|
|
|
|
continue
|
|
|
|
else:
|
|
|
|
if not desc.startswith('wpkh'):
|
|
|
|
continue
|
|
|
|
else:
|
|
|
|
if not desc.startswith('pkh'):
|
|
|
|
continue
|
|
|
|
unspent_addr[u['address']] = unspent_addr.get(u['address'], 0) + self.make_int(u['amount'], r=1)
|
|
|
|
return unspent_addr
|
|
|
|
|
|
|
|
|
|
|
|
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())
|