CLI: always use the daemon's cmd_runner, and pass the 'wallet'
parameter explicitly to each command that requires it. Previous code was relying on side effects to set the wallet. This should fix #5614
This commit is contained in:
@@ -97,10 +97,16 @@ def command(s):
|
|||||||
@wraps(func)
|
@wraps(func)
|
||||||
def func_wrapper(*args, **kwargs):
|
def func_wrapper(*args, **kwargs):
|
||||||
c = known_commands[func.__name__]
|
c = known_commands[func.__name__]
|
||||||
wallet = args[0].wallet
|
|
||||||
password = kwargs.get('password')
|
password = kwargs.get('password')
|
||||||
|
wallet = kwargs.get('wallet') # wallet is passed here if we are offline
|
||||||
if c.requires_wallet and wallet is None:
|
if c.requires_wallet and wallet is None:
|
||||||
raise Exception("wallet not loaded. Use 'electrum daemon load_wallet'")
|
cmd_runner = args[0]
|
||||||
|
path = cmd_runner.config.get_wallet_path()
|
||||||
|
path = standardize_path(path)
|
||||||
|
wallet = cmd_runner.daemon.wallets.get(path)
|
||||||
|
if wallet is None:
|
||||||
|
raise Exception("wallet not loaded. Use 'electrum load_wallet'")
|
||||||
|
kwargs['wallet'] = wallet
|
||||||
if c.requires_password and password is None and wallet.has_password():
|
if c.requires_password and password is None and wallet.has_password():
|
||||||
return {'error': 'Password required' }
|
return {'error': 'Password required' }
|
||||||
return func(*args, **kwargs)
|
return func(*args, **kwargs)
|
||||||
@@ -111,21 +117,18 @@ def command(s):
|
|||||||
class Commands:
|
class Commands:
|
||||||
|
|
||||||
def __init__(self, config: 'SimpleConfig',
|
def __init__(self, config: 'SimpleConfig',
|
||||||
wallet: Abstract_Wallet,
|
|
||||||
network: Optional['Network'],
|
network: Optional['Network'],
|
||||||
daemon: 'Daemon' = None, callback=None):
|
daemon: 'Daemon' = None, callback=None):
|
||||||
self.config = config
|
self.config = config
|
||||||
self.wallet = wallet
|
|
||||||
self.daemon = daemon
|
self.daemon = daemon
|
||||||
self.network = network
|
self.network = network
|
||||||
self._callback = callback
|
self._callback = callback
|
||||||
self.lnworker = self.wallet.lnworker if self.wallet else None
|
|
||||||
|
|
||||||
def _run(self, method, args, password_getter=None, **kwargs):
|
def _run(self, method, args, password_getter=None, **kwargs):
|
||||||
"""This wrapper is called from unit tests and the Qt python console."""
|
"""This wrapper is called from unit tests and the Qt python console."""
|
||||||
cmd = known_commands[method]
|
cmd = known_commands[method]
|
||||||
password = kwargs.get('password', None)
|
password = kwargs.get('password', None)
|
||||||
if (cmd.requires_password and self.wallet.has_password()
|
if (cmd.requires_password and wallet.has_password()
|
||||||
and password is None):
|
and password is None):
|
||||||
password = password_getter()
|
password = password_getter()
|
||||||
if password is None:
|
if password is None:
|
||||||
@@ -183,7 +186,6 @@ class Commands:
|
|||||||
path = self.config.get_wallet_path()
|
path = self.config.get_wallet_path()
|
||||||
wallet = self.daemon.load_wallet(path, self.config.get('password'))
|
wallet = self.daemon.load_wallet(path, self.config.get('password'))
|
||||||
if wallet is not None:
|
if wallet is not None:
|
||||||
self.wallet = wallet
|
|
||||||
run_hook('load_wallet', wallet, None)
|
run_hook('load_wallet', wallet, None)
|
||||||
response = wallet is not None
|
response = wallet is not None
|
||||||
return response
|
return response
|
||||||
@@ -229,19 +231,19 @@ class Commands:
|
|||||||
}
|
}
|
||||||
|
|
||||||
@command('wp')
|
@command('wp')
|
||||||
async def password(self, password=None, new_password=None):
|
async def password(self, password=None, new_password=None, wallet=None):
|
||||||
"""Change wallet password. """
|
"""Change wallet password. """
|
||||||
if self.wallet.storage.is_encrypted_with_hw_device() and new_password:
|
if wallet.storage.is_encrypted_with_hw_device() and new_password:
|
||||||
raise Exception("Can't change the password of a wallet encrypted with a hw device.")
|
raise Exception("Can't change the password of a wallet encrypted with a hw device.")
|
||||||
b = self.wallet.storage.is_encrypted()
|
b = wallet.storage.is_encrypted()
|
||||||
self.wallet.update_password(password, new_password, b)
|
wallet.update_password(password, new_password, b)
|
||||||
self.wallet.storage.write()
|
wallet.storage.write()
|
||||||
return {'password':self.wallet.has_password()}
|
return {'password':wallet.has_password()}
|
||||||
|
|
||||||
@command('w')
|
@command('w')
|
||||||
async def get(self, key):
|
async def get(self, key, wallet=None):
|
||||||
"""Return item from wallet storage"""
|
"""Return item from wallet storage"""
|
||||||
return self.wallet.storage.get(key)
|
return wallet.storage.get(key)
|
||||||
|
|
||||||
@command('')
|
@command('')
|
||||||
async def getconfig(self, key):
|
async def getconfig(self, key):
|
||||||
@@ -281,10 +283,10 @@ class Commands:
|
|||||||
return await self.network.get_history_for_scripthash(sh)
|
return await self.network.get_history_for_scripthash(sh)
|
||||||
|
|
||||||
@command('w')
|
@command('w')
|
||||||
async def listunspent(self):
|
async def listunspent(self, wallet=None):
|
||||||
"""List unspent outputs. Returns the list of unspent transaction
|
"""List unspent outputs. Returns the list of unspent transaction
|
||||||
outputs in your wallet."""
|
outputs in your wallet."""
|
||||||
l = copy.deepcopy(self.wallet.get_utxos())
|
l = copy.deepcopy(wallet.get_utxos())
|
||||||
for i in l:
|
for i in l:
|
||||||
v = i["value"]
|
v = i["value"]
|
||||||
i["value"] = str(Decimal(v)/COIN) if v is not None else None
|
i["value"] = str(Decimal(v)/COIN) if v is not None else None
|
||||||
@@ -329,7 +331,7 @@ class Commands:
|
|||||||
return tx.as_dict()
|
return tx.as_dict()
|
||||||
|
|
||||||
@command('wp')
|
@command('wp')
|
||||||
async def signtransaction(self, tx, privkey=None, password=None):
|
async def signtransaction(self, tx, privkey=None, password=None, wallet=None):
|
||||||
"""Sign a transaction. The wallet keys will be used unless a private key is provided."""
|
"""Sign a transaction. The wallet keys will be used unless a private key is provided."""
|
||||||
tx = Transaction(tx)
|
tx = Transaction(tx)
|
||||||
if privkey:
|
if privkey:
|
||||||
@@ -337,7 +339,7 @@ class Commands:
|
|||||||
pubkey = ecc.ECPrivkey(privkey2).get_public_key_bytes(compressed=compressed).hex()
|
pubkey = ecc.ECPrivkey(privkey2).get_public_key_bytes(compressed=compressed).hex()
|
||||||
tx.sign({pubkey:(privkey2, compressed)})
|
tx.sign({pubkey:(privkey2, compressed)})
|
||||||
else:
|
else:
|
||||||
self.wallet.sign_transaction(tx, password)
|
wallet.sign_transaction(tx, password)
|
||||||
return tx.as_dict()
|
return tx.as_dict()
|
||||||
|
|
||||||
@command('')
|
@command('')
|
||||||
@@ -362,29 +364,29 @@ class Commands:
|
|||||||
return {'address':address, 'redeemScript':redeem_script}
|
return {'address':address, 'redeemScript':redeem_script}
|
||||||
|
|
||||||
@command('w')
|
@command('w')
|
||||||
async def freeze(self, address):
|
async def freeze(self, address, wallet=None):
|
||||||
"""Freeze address. Freeze the funds at one of your wallet\'s addresses"""
|
"""Freeze address. Freeze the funds at one of your wallet\'s addresses"""
|
||||||
return self.wallet.set_frozen_state_of_addresses([address], True)
|
return wallet.set_frozen_state_of_addresses([address], True)
|
||||||
|
|
||||||
@command('w')
|
@command('w')
|
||||||
async def unfreeze(self, address):
|
async def unfreeze(self, address, wallet=None):
|
||||||
"""Unfreeze address. Unfreeze the funds at one of your wallet\'s address"""
|
"""Unfreeze address. Unfreeze the funds at one of your wallet\'s address"""
|
||||||
return self.wallet.set_frozen_state_of_addresses([address], False)
|
return wallet.set_frozen_state_of_addresses([address], False)
|
||||||
|
|
||||||
@command('wp')
|
@command('wp')
|
||||||
async def getprivatekeys(self, address, password=None):
|
async def getprivatekeys(self, address, password=None, wallet=None):
|
||||||
"""Get private keys of addresses. You may pass a single wallet address, or a list of wallet addresses."""
|
"""Get private keys of addresses. You may pass a single wallet address, or a list of wallet addresses."""
|
||||||
if isinstance(address, str):
|
if isinstance(address, str):
|
||||||
address = address.strip()
|
address = address.strip()
|
||||||
if is_address(address):
|
if is_address(address):
|
||||||
return self.wallet.export_private_key(address, password)[0]
|
return wallet.export_private_key(address, password)[0]
|
||||||
domain = address
|
domain = address
|
||||||
return [self.wallet.export_private_key(address, password)[0] for address in domain]
|
return [wallet.export_private_key(address, password)[0] for address in domain]
|
||||||
|
|
||||||
@command('w')
|
@command('w')
|
||||||
async def ismine(self, address):
|
async def ismine(self, address, wallet=None):
|
||||||
"""Check if address is in wallet. Return true if and only address is in wallet"""
|
"""Check if address is in wallet. Return true if and only address is in wallet"""
|
||||||
return self.wallet.is_mine(address)
|
return wallet.is_mine(address)
|
||||||
|
|
||||||
@command('')
|
@command('')
|
||||||
async def dumpprivkeys(self):
|
async def dumpprivkeys(self):
|
||||||
@@ -397,15 +399,15 @@ class Commands:
|
|||||||
return is_address(address)
|
return is_address(address)
|
||||||
|
|
||||||
@command('w')
|
@command('w')
|
||||||
async def getpubkeys(self, address):
|
async def getpubkeys(self, address, wallet=None):
|
||||||
"""Return the public keys for a wallet address. """
|
"""Return the public keys for a wallet address. """
|
||||||
return self.wallet.get_public_keys(address)
|
return wallet.get_public_keys(address)
|
||||||
|
|
||||||
@command('w')
|
@command('w')
|
||||||
async def getbalance(self):
|
async def getbalance(self, wallet=None):
|
||||||
"""Return the balance of your wallet. """
|
"""Return the balance of your wallet. """
|
||||||
c, u, x = self.wallet.get_balance()
|
c, u, x = wallet.get_balance()
|
||||||
l = self.lnworker.get_balance() if self.lnworker else None
|
l = wallet.lnworker.get_balance() if wallet.lnworker else None
|
||||||
out = {"confirmed": str(Decimal(c)/COIN)}
|
out = {"confirmed": str(Decimal(c)/COIN)}
|
||||||
if u:
|
if u:
|
||||||
out["unconfirmed"] = str(Decimal(u)/COIN)
|
out["unconfirmed"] = str(Decimal(u)/COIN)
|
||||||
@@ -444,14 +446,14 @@ class Commands:
|
|||||||
return ELECTRUM_VERSION
|
return ELECTRUM_VERSION
|
||||||
|
|
||||||
@command('w')
|
@command('w')
|
||||||
async def getmpk(self):
|
async def getmpk(self, wallet=None):
|
||||||
"""Get master public key. Return your wallet\'s master public key"""
|
"""Get master public key. Return your wallet\'s master public key"""
|
||||||
return self.wallet.get_master_public_key()
|
return wallet.get_master_public_key()
|
||||||
|
|
||||||
@command('wp')
|
@command('wp')
|
||||||
async def getmasterprivate(self, password=None):
|
async def getmasterprivate(self, password=None, wallet=None):
|
||||||
"""Get master private key. Return your wallet\'s master private key"""
|
"""Get master private key. Return your wallet\'s master private key"""
|
||||||
return str(self.wallet.keystore.get_master_private_key(password))
|
return str(wallet.keystore.get_master_private_key(password))
|
||||||
|
|
||||||
@command('')
|
@command('')
|
||||||
async def convert_xkey(self, xkey, xtype):
|
async def convert_xkey(self, xkey, xtype):
|
||||||
@@ -463,27 +465,27 @@ class Commands:
|
|||||||
return node._replace(xtype=xtype).to_xkey()
|
return node._replace(xtype=xtype).to_xkey()
|
||||||
|
|
||||||
@command('wp')
|
@command('wp')
|
||||||
async def getseed(self, password=None):
|
async def getseed(self, password=None, wallet=None):
|
||||||
"""Get seed phrase. Print the generation seed of your wallet."""
|
"""Get seed phrase. Print the generation seed of your wallet."""
|
||||||
s = self.wallet.get_seed(password)
|
s = wallet.get_seed(password)
|
||||||
return s
|
return s
|
||||||
|
|
||||||
@command('wp')
|
@command('wp')
|
||||||
async def importprivkey(self, privkey, password=None):
|
async def importprivkey(self, privkey, password=None, wallet=None):
|
||||||
"""Import a private key."""
|
"""Import a private key."""
|
||||||
if not self.wallet.can_import_privkey():
|
if not wallet.can_import_privkey():
|
||||||
return "Error: This type of wallet cannot import private keys. Try to create a new wallet with that key."
|
return "Error: This type of wallet cannot import private keys. Try to create a new wallet with that key."
|
||||||
try:
|
try:
|
||||||
addr = self.wallet.import_private_key(privkey, password)
|
addr = wallet.import_private_key(privkey, password)
|
||||||
out = "Keypair imported: " + addr
|
out = "Keypair imported: " + addr
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
out = "Error: " + repr(e)
|
out = "Error: " + repr(e)
|
||||||
return out
|
return out
|
||||||
|
|
||||||
def _resolver(self, x):
|
def _resolver(self, x, wallet):
|
||||||
if x is None:
|
if x is None:
|
||||||
return None
|
return None
|
||||||
out = self.wallet.contacts.resolve(x)
|
out = wallet.contacts.resolve(x)
|
||||||
if out.get('type') == 'openalias' and self.nocheck is False and out.get('validated') is False:
|
if out.get('type') == 'openalias' and self.nocheck is False and out.get('validated') is False:
|
||||||
raise Exception('cannot verify alias', x)
|
raise Exception('cannot verify alias', x)
|
||||||
return out['address']
|
return out['address']
|
||||||
@@ -502,10 +504,10 @@ class Commands:
|
|||||||
return tx.as_dict() if tx else None
|
return tx.as_dict() if tx else None
|
||||||
|
|
||||||
@command('wp')
|
@command('wp')
|
||||||
async def signmessage(self, address, message, password=None):
|
async def signmessage(self, address, message, password=None, wallet=None):
|
||||||
"""Sign a message with a key. Use quotes if your message contains
|
"""Sign a message with a key. Use quotes if your message contains
|
||||||
whitespaces"""
|
whitespaces"""
|
||||||
sig = self.wallet.sign_message(address, message, password)
|
sig = wallet.sign_message(address, message, password)
|
||||||
return base64.b64encode(sig).decode('ascii')
|
return base64.b64encode(sig).decode('ascii')
|
||||||
|
|
||||||
@command('')
|
@command('')
|
||||||
@@ -515,26 +517,26 @@ class Commands:
|
|||||||
message = util.to_bytes(message)
|
message = util.to_bytes(message)
|
||||||
return ecc.verify_message_with_address(address, sig, message)
|
return ecc.verify_message_with_address(address, sig, message)
|
||||||
|
|
||||||
def _mktx(self, outputs, *, fee=None, feerate=None, change_addr=None, domain=None,
|
def _mktx(self, wallet, outputs, *, fee=None, feerate=None, change_addr=None, domain=None,
|
||||||
nocheck=False, unsigned=False, rbf=None, password=None, locktime=None):
|
nocheck=False, unsigned=False, rbf=None, password=None, locktime=None):
|
||||||
if fee is not None and feerate is not None:
|
if fee is not None and feerate is not None:
|
||||||
raise Exception("Cannot specify both 'fee' and 'feerate' at the same time!")
|
raise Exception("Cannot specify both 'fee' and 'feerate' at the same time!")
|
||||||
self.nocheck = nocheck
|
self.nocheck = nocheck
|
||||||
change_addr = self._resolver(change_addr)
|
change_addr = self._resolver(change_addr, wallet)
|
||||||
domain = None if domain is None else map(self._resolver, domain)
|
domain = None if domain is None else map(self._resolver, domain)
|
||||||
final_outputs = []
|
final_outputs = []
|
||||||
for address, amount in outputs:
|
for address, amount in outputs:
|
||||||
address = self._resolver(address)
|
address = self._resolver(address, wallet)
|
||||||
amount = satoshis(amount)
|
amount = satoshis(amount)
|
||||||
final_outputs.append(TxOutput(TYPE_ADDRESS, address, amount))
|
final_outputs.append(TxOutput(TYPE_ADDRESS, address, amount))
|
||||||
|
|
||||||
coins = self.wallet.get_spendable_coins(domain, self.config)
|
coins = wallet.get_spendable_coins(domain, self.config)
|
||||||
if feerate is not None:
|
if feerate is not None:
|
||||||
fee_per_kb = 1000 * Decimal(feerate)
|
fee_per_kb = 1000 * Decimal(feerate)
|
||||||
fee_estimator = partial(SimpleConfig.estimate_fee_for_feerate, fee_per_kb)
|
fee_estimator = partial(SimpleConfig.estimate_fee_for_feerate, fee_per_kb)
|
||||||
else:
|
else:
|
||||||
fee_estimator = fee
|
fee_estimator = fee
|
||||||
tx = self.wallet.make_unsigned_transaction(coins, final_outputs, self.config, fee_estimator, change_addr)
|
tx = wallet.make_unsigned_transaction(coins, final_outputs, self.config, fee_estimator, change_addr)
|
||||||
if locktime is not None:
|
if locktime is not None:
|
||||||
tx.locktime = locktime
|
tx.locktime = locktime
|
||||||
if rbf is None:
|
if rbf is None:
|
||||||
@@ -542,16 +544,17 @@ class Commands:
|
|||||||
if rbf:
|
if rbf:
|
||||||
tx.set_rbf(True)
|
tx.set_rbf(True)
|
||||||
if not unsigned:
|
if not unsigned:
|
||||||
self.wallet.sign_transaction(tx, password)
|
wallet.sign_transaction(tx, password)
|
||||||
return tx
|
return tx
|
||||||
|
|
||||||
@command('wp')
|
@command('wp')
|
||||||
async def payto(self, destination, amount, fee=None, feerate=None, from_addr=None, change_addr=None,
|
async def payto(self, destination, amount, fee=None, feerate=None, from_addr=None, change_addr=None,
|
||||||
nocheck=False, unsigned=False, rbf=None, password=None, locktime=None):
|
nocheck=False, unsigned=False, rbf=None, password=None, locktime=None, wallet=None):
|
||||||
"""Create a transaction. """
|
"""Create a transaction. """
|
||||||
tx_fee = satoshis(fee)
|
tx_fee = satoshis(fee)
|
||||||
domain = from_addr.split(',') if from_addr else None
|
domain = from_addr.split(',') if from_addr else None
|
||||||
tx = self._mktx([(destination, amount)],
|
tx = self._mktx(wallet,
|
||||||
|
[(destination, amount)],
|
||||||
fee=tx_fee,
|
fee=tx_fee,
|
||||||
feerate=feerate,
|
feerate=feerate,
|
||||||
change_addr=change_addr,
|
change_addr=change_addr,
|
||||||
@@ -565,11 +568,12 @@ class Commands:
|
|||||||
|
|
||||||
@command('wp')
|
@command('wp')
|
||||||
async def paytomany(self, outputs, fee=None, feerate=None, from_addr=None, change_addr=None,
|
async def paytomany(self, outputs, fee=None, feerate=None, from_addr=None, change_addr=None,
|
||||||
nocheck=False, unsigned=False, rbf=None, password=None, locktime=None):
|
nocheck=False, unsigned=False, rbf=None, password=None, locktime=None, wallet=None):
|
||||||
"""Create a multi-output transaction. """
|
"""Create a multi-output transaction. """
|
||||||
tx_fee = satoshis(fee)
|
tx_fee = satoshis(fee)
|
||||||
domain = from_addr.split(',') if from_addr else None
|
domain = from_addr.split(',') if from_addr else None
|
||||||
tx = self._mktx(outputs,
|
tx = self._mktx(wallet,
|
||||||
|
outputs,
|
||||||
fee=tx_fee,
|
fee=tx_fee,
|
||||||
feerate=feerate,
|
feerate=feerate,
|
||||||
change_addr=change_addr,
|
change_addr=change_addr,
|
||||||
@@ -582,7 +586,7 @@ class Commands:
|
|||||||
return tx.as_dict()
|
return tx.as_dict()
|
||||||
|
|
||||||
@command('w')
|
@command('w')
|
||||||
async def onchain_history(self, year=None, show_addresses=False, show_fiat=False, show_fees=False):
|
async def onchain_history(self, year=None, show_addresses=False, show_fiat=False, show_fees=False, wallet=None):
|
||||||
"""Wallet onchain history. Returns the transaction history of your wallet."""
|
"""Wallet onchain history. Returns the transaction history of your wallet."""
|
||||||
kwargs = {
|
kwargs = {
|
||||||
'show_addresses': show_addresses,
|
'show_addresses': show_addresses,
|
||||||
@@ -598,61 +602,61 @@ class Commands:
|
|||||||
from .exchange_rate import FxThread
|
from .exchange_rate import FxThread
|
||||||
fx = FxThread(self.config, None)
|
fx = FxThread(self.config, None)
|
||||||
kwargs['fx'] = fx
|
kwargs['fx'] = fx
|
||||||
return json_encode(self.wallet.get_detailed_history(**kwargs))
|
return json_encode(wallet.get_detailed_history(**kwargs))
|
||||||
|
|
||||||
@command('w')
|
@command('w')
|
||||||
async def lightning_history(self, show_fiat=False):
|
async def lightning_history(self, show_fiat=False, wallet=None):
|
||||||
""" lightning history """
|
""" lightning history """
|
||||||
lightning_history = self.wallet.lnworker.get_history() if self.wallet.lnworker else []
|
lightning_history = wallet.lnworker.get_history() if wallet.lnworker else []
|
||||||
return json_encode(lightning_history)
|
return json_encode(lightning_history)
|
||||||
|
|
||||||
@command('w')
|
@command('w')
|
||||||
async def setlabel(self, key, label):
|
async def setlabel(self, key, label, wallet=None):
|
||||||
"""Assign a label to an item. Item may be a bitcoin address or a
|
"""Assign a label to an item. Item may be a bitcoin address or a
|
||||||
transaction ID"""
|
transaction ID"""
|
||||||
self.wallet.set_label(key, label)
|
wallet.set_label(key, label)
|
||||||
|
|
||||||
@command('w')
|
@command('w')
|
||||||
async def listcontacts(self):
|
async def listcontacts(self, wallet=None):
|
||||||
"""Show your list of contacts"""
|
"""Show your list of contacts"""
|
||||||
return self.wallet.contacts
|
return wallet.contacts
|
||||||
|
|
||||||
@command('w')
|
@command('w')
|
||||||
async def getalias(self, key):
|
async def getalias(self, key, wallet=None):
|
||||||
"""Retrieve alias. Lookup in your list of contacts, and for an OpenAlias DNS record."""
|
"""Retrieve alias. Lookup in your list of contacts, and for an OpenAlias DNS record."""
|
||||||
return self.wallet.contacts.resolve(key)
|
return wallet.contacts.resolve(key)
|
||||||
|
|
||||||
@command('w')
|
@command('w')
|
||||||
async def searchcontacts(self, query):
|
async def searchcontacts(self, query, wallet=None):
|
||||||
"""Search through contacts, return matching entries. """
|
"""Search through contacts, return matching entries. """
|
||||||
results = {}
|
results = {}
|
||||||
for key, value in self.wallet.contacts.items():
|
for key, value in wallet.contacts.items():
|
||||||
if query.lower() in key.lower():
|
if query.lower() in key.lower():
|
||||||
results[key] = value
|
results[key] = value
|
||||||
return results
|
return results
|
||||||
|
|
||||||
@command('w')
|
@command('w')
|
||||||
async def listaddresses(self, receiving=False, change=False, labels=False, frozen=False, unused=False, funded=False, balance=False):
|
async def listaddresses(self, receiving=False, change=False, labels=False, frozen=False, unused=False, funded=False, balance=False, wallet=None):
|
||||||
"""List wallet addresses. Returns the list of all addresses in your wallet. Use optional arguments to filter the results."""
|
"""List wallet addresses. Returns the list of all addresses in your wallet. Use optional arguments to filter the results."""
|
||||||
out = []
|
out = []
|
||||||
for addr in self.wallet.get_addresses():
|
for addr in wallet.get_addresses():
|
||||||
if frozen and not self.wallet.is_frozen_address(addr):
|
if frozen and not wallet.is_frozen_address(addr):
|
||||||
continue
|
continue
|
||||||
if receiving and self.wallet.is_change(addr):
|
if receiving and wallet.is_change(addr):
|
||||||
continue
|
continue
|
||||||
if change and not self.wallet.is_change(addr):
|
if change and not wallet.is_change(addr):
|
||||||
continue
|
continue
|
||||||
if unused and self.wallet.is_used(addr):
|
if unused and wallet.is_used(addr):
|
||||||
continue
|
continue
|
||||||
if funded and self.wallet.is_empty(addr):
|
if funded and wallet.is_empty(addr):
|
||||||
continue
|
continue
|
||||||
item = addr
|
item = addr
|
||||||
if labels or balance:
|
if labels or balance:
|
||||||
item = (item,)
|
item = (item,)
|
||||||
if balance:
|
if balance:
|
||||||
item += (format_satoshis(sum(self.wallet.get_addr_balance(addr))),)
|
item += (format_satoshis(sum(wallet.get_addr_balance(addr))),)
|
||||||
if labels:
|
if labels:
|
||||||
item += (repr(self.wallet.labels.get(addr, '')),)
|
item += (repr(wallet.labels.get(addr, '')),)
|
||||||
out.append(item)
|
out.append(item)
|
||||||
return out
|
return out
|
||||||
|
|
||||||
@@ -660,8 +664,8 @@ class Commands:
|
|||||||
async def gettransaction(self, txid):
|
async def gettransaction(self, txid):
|
||||||
"""Retrieve a transaction. """
|
"""Retrieve a transaction. """
|
||||||
tx = None
|
tx = None
|
||||||
if self.wallet:
|
if wallet:
|
||||||
tx = self.wallet.db.get_transaction(txid)
|
tx = wallet.db.get_transaction(txid)
|
||||||
if tx is None:
|
if tx is None:
|
||||||
raw = await self.network.get_transaction(txid)
|
raw = await self.network.get_transaction(txid)
|
||||||
if raw:
|
if raw:
|
||||||
@@ -690,7 +694,7 @@ class Commands:
|
|||||||
raise Exception(f"pubkey must be a hex string instead of {repr(pubkey)}")
|
raise Exception(f"pubkey must be a hex string instead of {repr(pubkey)}")
|
||||||
if not isinstance(encrypted, (str, bytes, bytearray)):
|
if not isinstance(encrypted, (str, bytes, bytearray)):
|
||||||
raise Exception(f"encrypted must be a string-like object instead of {repr(encrypted)}")
|
raise Exception(f"encrypted must be a string-like object instead of {repr(encrypted)}")
|
||||||
decrypted = self.wallet.decrypt_message(pubkey, encrypted, password)
|
decrypted = wallet.decrypt_message(pubkey, encrypted, password)
|
||||||
return decrypted.decode('utf-8')
|
return decrypted.decode('utf-8')
|
||||||
|
|
||||||
def _format_request(self, out):
|
def _format_request(self, out):
|
||||||
@@ -700,9 +704,9 @@ class Commands:
|
|||||||
return out
|
return out
|
||||||
|
|
||||||
@command('w')
|
@command('w')
|
||||||
async def getrequest(self, key):
|
async def getrequest(self, key, wallet=None):
|
||||||
"""Return a payment request"""
|
"""Return a payment request"""
|
||||||
r = self.wallet.get_request(key)
|
r = wallet.get_request(key)
|
||||||
if not r:
|
if not r:
|
||||||
raise Exception("Request not found")
|
raise Exception("Request not found")
|
||||||
return self._format_request(r)
|
return self._format_request(r)
|
||||||
@@ -713,9 +717,9 @@ class Commands:
|
|||||||
# pass
|
# pass
|
||||||
|
|
||||||
@command('w')
|
@command('w')
|
||||||
async def listrequests(self, pending=False, expired=False, paid=False):
|
async def listrequests(self, pending=False, expired=False, paid=False, wallet=None):
|
||||||
"""List the payment requests you made."""
|
"""List the payment requests you made."""
|
||||||
out = self.wallet.get_sorted_requests(self.config)
|
out = wallet.get_sorted_requests(self.config)
|
||||||
if pending:
|
if pending:
|
||||||
f = PR_UNPAID
|
f = PR_UNPAID
|
||||||
elif expired:
|
elif expired:
|
||||||
@@ -729,62 +733,62 @@ class Commands:
|
|||||||
return list(map(self._format_request, out))
|
return list(map(self._format_request, out))
|
||||||
|
|
||||||
@command('w')
|
@command('w')
|
||||||
async def createnewaddress(self):
|
async def createnewaddress(self, wallet=None):
|
||||||
"""Create a new receiving address, beyond the gap limit of the wallet"""
|
"""Create a new receiving address, beyond the gap limit of the wallet"""
|
||||||
return self.wallet.create_new_address(False)
|
return wallet.create_new_address(False)
|
||||||
|
|
||||||
@command('w')
|
@command('w')
|
||||||
async def getunusedaddress(self):
|
async def getunusedaddress(self, wallet=None):
|
||||||
"""Returns the first unused address of the wallet, or None if all addresses are used.
|
"""Returns the first unused address of the wallet, or None if all addresses are used.
|
||||||
An address is considered as used if it has received a transaction, or if it is used in a payment request."""
|
An address is considered as used if it has received a transaction, or if it is used in a payment request."""
|
||||||
return self.wallet.get_unused_address()
|
return wallet.get_unused_address()
|
||||||
|
|
||||||
@command('w')
|
@command('w')
|
||||||
async def addrequest(self, amount, memo='', expiration=None, force=False):
|
async def addrequest(self, amount, memo='', expiration=None, force=False, wallet=None):
|
||||||
"""Create a payment request, using the first unused address of the wallet.
|
"""Create a payment request, using the first unused address of the wallet.
|
||||||
The address will be considered as used after this operation.
|
The address will be considered as used after this operation.
|
||||||
If no payment is received, the address will be considered as unused if the payment request is deleted from the wallet."""
|
If no payment is received, the address will be considered as unused if the payment request is deleted from the wallet."""
|
||||||
addr = self.wallet.get_unused_address()
|
addr = wallet.get_unused_address()
|
||||||
if addr is None:
|
if addr is None:
|
||||||
if force:
|
if force:
|
||||||
addr = self.wallet.create_new_address(False)
|
addr = wallet.create_new_address(False)
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
amount = satoshis(amount)
|
amount = satoshis(amount)
|
||||||
expiration = int(expiration) if expiration else None
|
expiration = int(expiration) if expiration else None
|
||||||
req = self.wallet.make_payment_request(addr, amount, memo, expiration)
|
req = wallet.make_payment_request(addr, amount, memo, expiration)
|
||||||
self.wallet.add_payment_request(req, self.config)
|
wallet.add_payment_request(req, self.config)
|
||||||
out = self.wallet.get_request(addr)
|
out = wallet.get_request(addr)
|
||||||
return self._format_request(out)
|
return self._format_request(out)
|
||||||
|
|
||||||
@command('w')
|
@command('w')
|
||||||
async def addtransaction(self, tx):
|
async def addtransaction(self, tx, wallet=None):
|
||||||
""" Add a transaction to the wallet history """
|
""" Add a transaction to the wallet history """
|
||||||
tx = Transaction(tx)
|
tx = Transaction(tx)
|
||||||
if not self.wallet.add_transaction(tx.txid(), tx):
|
if not wallet.add_transaction(tx.txid(), tx, wallet=None):
|
||||||
return False
|
return False
|
||||||
self.wallet.storage.write()
|
wallet.storage.write()
|
||||||
return tx.txid()
|
return tx.txid()
|
||||||
|
|
||||||
@command('wp')
|
@command('wp')
|
||||||
async def signrequest(self, address, password=None):
|
async def signrequest(self, address, password=None, wallet=None):
|
||||||
"Sign payment request with an OpenAlias"
|
"Sign payment request with an OpenAlias"
|
||||||
alias = self.config.get('alias')
|
alias = self.config.get('alias')
|
||||||
if not alias:
|
if not alias:
|
||||||
raise Exception('No alias in your configuration')
|
raise Exception('No alias in your configuration')
|
||||||
alias_addr = self.wallet.contacts.resolve(alias)['address']
|
alias_addr = wallet.contacts.resolve(alias)['address']
|
||||||
self.wallet.sign_payment_request(address, alias, alias_addr, password)
|
wallet.sign_payment_request(address, alias, alias_addr, password)
|
||||||
|
|
||||||
@command('w')
|
@command('w')
|
||||||
async def rmrequest(self, address):
|
async def rmrequest(self, address, wallet=None):
|
||||||
"""Remove a payment request"""
|
"""Remove a payment request"""
|
||||||
return self.wallet.remove_payment_request(address, self.config)
|
return wallet.remove_payment_request(address, self.config)
|
||||||
|
|
||||||
@command('w')
|
@command('w')
|
||||||
async def clearrequests(self):
|
async def clearrequests(self, wallet=None):
|
||||||
"""Remove all payment requests"""
|
"""Remove all payment requests"""
|
||||||
for k in list(self.wallet.receive_requests.keys()):
|
for k in list(wallet.receive_requests.keys()):
|
||||||
self.wallet.remove_payment_request(k, self.config)
|
wallet.remove_payment_request(k, self.config)
|
||||||
|
|
||||||
@command('n')
|
@command('n')
|
||||||
async def notify(self, address: str, URL: str):
|
async def notify(self, address: str, URL: str):
|
||||||
@@ -795,9 +799,9 @@ class Commands:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
@command('wn')
|
@command('wn')
|
||||||
async def is_synchronized(self):
|
async def is_synchronized(self, wallet=None):
|
||||||
""" return wallet synchronization status """
|
""" return wallet synchronization status """
|
||||||
return self.wallet.is_up_to_date()
|
return wallet.is_up_to_date()
|
||||||
|
|
||||||
@command('n')
|
@command('n')
|
||||||
async def getfeerate(self, fee_method=None, fee_level=None):
|
async def getfeerate(self, fee_method=None, fee_level=None):
|
||||||
@@ -819,33 +823,33 @@ class Commands:
|
|||||||
return self.config.fee_per_kb(dyn=dyn, mempool=mempool, fee_level=fee_level)
|
return self.config.fee_per_kb(dyn=dyn, mempool=mempool, fee_level=fee_level)
|
||||||
|
|
||||||
@command('w')
|
@command('w')
|
||||||
async def removelocaltx(self, txid):
|
async def removelocaltx(self, txid, wallet=None):
|
||||||
"""Remove a 'local' transaction from the wallet, and its dependent
|
"""Remove a 'local' transaction from the wallet, and its dependent
|
||||||
transactions.
|
transactions.
|
||||||
"""
|
"""
|
||||||
if not is_hash256_str(txid):
|
if not is_hash256_str(txid):
|
||||||
raise Exception(f"{repr(txid)} is not a txid")
|
raise Exception(f"{repr(txid)} is not a txid")
|
||||||
height = self.wallet.get_tx_height(txid).height
|
height = wallet.get_tx_height(txid).height
|
||||||
to_delete = {txid}
|
to_delete = {txid}
|
||||||
if height != TX_HEIGHT_LOCAL:
|
if height != TX_HEIGHT_LOCAL:
|
||||||
raise Exception(f'Only local transactions can be removed. '
|
raise Exception(f'Only local transactions can be removed. '
|
||||||
f'This tx has height: {height} != {TX_HEIGHT_LOCAL}')
|
f'This tx has height: {height} != {TX_HEIGHT_LOCAL}')
|
||||||
to_delete |= self.wallet.get_depending_transactions(txid)
|
to_delete |= wallet.get_depending_transactions(txid)
|
||||||
for tx_hash in to_delete:
|
for tx_hash in to_delete:
|
||||||
self.wallet.remove_transaction(tx_hash)
|
wallet.remove_transaction(tx_hash)
|
||||||
self.wallet.storage.write()
|
wallet.storage.write()
|
||||||
|
|
||||||
@command('wn')
|
@command('wn')
|
||||||
async def get_tx_status(self, txid):
|
async def get_tx_status(self, txid, wallet=None):
|
||||||
"""Returns some information regarding the tx. For now, only confirmations.
|
"""Returns some information regarding the tx. For now, only confirmations.
|
||||||
The transaction must be related to the wallet.
|
The transaction must be related to the wallet.
|
||||||
"""
|
"""
|
||||||
if not is_hash256_str(txid):
|
if not is_hash256_str(txid):
|
||||||
raise Exception(f"{repr(txid)} is not a txid")
|
raise Exception(f"{repr(txid)} is not a txid")
|
||||||
if not self.wallet.db.get_transaction(txid):
|
if not wallet.db.get_transaction(txid):
|
||||||
raise Exception("Transaction not in wallet.")
|
raise Exception("Transaction not in wallet.")
|
||||||
return {
|
return {
|
||||||
"confirmations": self.wallet.get_tx_height(txid).conf,
|
"confirmations": wallet.get_tx_height(txid).conf,
|
||||||
}
|
}
|
||||||
|
|
||||||
@command('')
|
@command('')
|
||||||
@@ -855,38 +859,38 @@ class Commands:
|
|||||||
|
|
||||||
# lightning network commands
|
# lightning network commands
|
||||||
@command('wn')
|
@command('wn')
|
||||||
async def add_peer(self, connection_string, timeout=20):
|
async def add_peer(self, connection_string, timeout=20, wallet=None):
|
||||||
await self.lnworker.add_peer(connection_string)
|
await wallet.lnworker.add_peer(connection_string)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@command('wpn')
|
@command('wpn')
|
||||||
async def open_channel(self, connection_string, amount, channel_push=0, password=None):
|
async def open_channel(self, connection_string, amount, channel_push=0, password=None, wallet=None):
|
||||||
chan = await self.lnworker._open_channel_coroutine(connection_string, satoshis(amount), satoshis(channel_push), password)
|
chan = await wallet.lnworker._open_channel_coroutine(connection_string, satoshis(amount), satoshis(channel_push), password)
|
||||||
return chan.funding_outpoint.to_str()
|
return chan.funding_outpoint.to_str()
|
||||||
|
|
||||||
@command('wn')
|
@command('wn')
|
||||||
async def lnpay(self, invoice, attempts=1, timeout=10):
|
async def lnpay(self, invoice, attempts=1, timeout=10, wallet=None):
|
||||||
return await self.lnworker._pay(invoice, attempts=attempts)
|
return await wallet.lnworker._pay(invoice, attempts=attempts)
|
||||||
|
|
||||||
@command('wn')
|
@command('wn')
|
||||||
async def addinvoice(self, requested_amount, message, expiration=3600):
|
async def addinvoice(self, requested_amount, message, expiration=3600, wallet=None):
|
||||||
# using requested_amount because it is documented in param_descriptions
|
# using requested_amount because it is documented in param_descriptions
|
||||||
payment_hash = await self.lnworker._add_invoice_coro(satoshis(requested_amount), message, expiration)
|
payment_hash = await wallet.lnworker._add_invoice_coro(satoshis(requested_amount), message, expiration)
|
||||||
invoice, direction, is_paid = self.lnworker.invoices[bh2u(payment_hash)]
|
invoice, direction, is_paid = wallet.lnworker.invoices[bh2u(payment_hash)]
|
||||||
return invoice
|
return invoice
|
||||||
|
|
||||||
@command('w')
|
@command('w')
|
||||||
async def nodeid(self):
|
async def nodeid(self, wallet=None):
|
||||||
listen_addr = self.config.get('lightning_listen')
|
listen_addr = self.config.get('lightning_listen')
|
||||||
return bh2u(self.lnworker.node_keypair.pubkey) + (('@' + listen_addr) if listen_addr else '')
|
return bh2u(wallet.lnworker.node_keypair.pubkey) + (('@' + listen_addr) if listen_addr else '')
|
||||||
|
|
||||||
@command('w')
|
@command('w')
|
||||||
async def list_channels(self):
|
async def list_channels(self, wallet=None):
|
||||||
return list(self.lnworker.list_channels())
|
return list(wallet.lnworker.list_channels())
|
||||||
|
|
||||||
@command('wn')
|
@command('wn')
|
||||||
async def dumpgraph(self):
|
async def dumpgraph(self, wallet=None):
|
||||||
return list(map(bh2u, self.lnworker.channel_db.nodes.keys()))
|
return list(map(bh2u, wallet.lnworker.channel_db.nodes.keys()))
|
||||||
|
|
||||||
@command('n')
|
@command('n')
|
||||||
async def inject_fees(self, fees):
|
async def inject_fees(self, fees):
|
||||||
@@ -899,11 +903,11 @@ class Commands:
|
|||||||
self.network.path_finder.blacklist.clear()
|
self.network.path_finder.blacklist.clear()
|
||||||
|
|
||||||
@command('w')
|
@command('w')
|
||||||
async def lightning_invoices(self):
|
async def lightning_invoices(self, wallet=None):
|
||||||
from .util import pr_tooltips
|
from .util import pr_tooltips
|
||||||
out = []
|
out = []
|
||||||
for payment_hash, (preimage, invoice, is_received, timestamp) in self.lnworker.invoices.items():
|
for payment_hash, (preimage, invoice, is_received, timestamp) in wallet.lnworker.invoices.items():
|
||||||
status = self.lnworker.get_invoice_status(payment_hash)
|
status = wallet.lnworker.get_invoice_status(payment_hash)
|
||||||
item = {
|
item = {
|
||||||
'date':timestamp_to_datetime(timestamp),
|
'date':timestamp_to_datetime(timestamp),
|
||||||
'direction': 'received' if is_received else 'sent',
|
'direction': 'received' if is_received else 'sent',
|
||||||
@@ -916,22 +920,22 @@ class Commands:
|
|||||||
return out
|
return out
|
||||||
|
|
||||||
@command('w')
|
@command('w')
|
||||||
async def lightning_history(self):
|
async def lightning_history(self, wallet=None):
|
||||||
return self.lnworker.get_history()
|
return wallet.lnworker.get_history()
|
||||||
|
|
||||||
@command('wn')
|
@command('wn')
|
||||||
async def close_channel(self, channel_point, force=False):
|
async def close_channel(self, channel_point, force=False, wallet=None):
|
||||||
txid, index = channel_point.split(':')
|
txid, index = channel_point.split(':')
|
||||||
chan_id, _ = channel_id_from_funding_tx(txid, int(index))
|
chan_id, _ = channel_id_from_funding_tx(txid, int(index))
|
||||||
coro = self.lnworker.force_close_channel(chan_id) if force else self.lnworker.close_channel(chan_id)
|
coro = wallet.lnworker.force_close_channel(chan_id) if force else wallet.lnworker.close_channel(chan_id)
|
||||||
return await coro
|
return await coro
|
||||||
|
|
||||||
@command('wn')
|
@command('wn')
|
||||||
async def get_channel_ctx(self, channel_point):
|
async def get_channel_ctx(self, channel_point, wallet=None):
|
||||||
""" return the current commitment transaction of a channel """
|
""" return the current commitment transaction of a channel """
|
||||||
txid, index = channel_point.split(':')
|
txid, index = channel_point.split(':')
|
||||||
chan_id, _ = channel_id_from_funding_tx(txid, int(index))
|
chan_id, _ = channel_id_from_funding_tx(txid, int(index))
|
||||||
chan = self.lnworker.channels[chan_id]
|
chan = wallet.lnworker.channels[chan_id]
|
||||||
tx = chan.force_close_tx()
|
tx = chan.force_close_tx()
|
||||||
return tx.as_dict()
|
return tx.as_dict()
|
||||||
|
|
||||||
@@ -1143,6 +1147,8 @@ def get_parser():
|
|||||||
p = subparsers.add_parser(cmdname, help=cmd.help, description=cmd.description)
|
p = subparsers.add_parser(cmdname, help=cmd.help, description=cmd.description)
|
||||||
add_global_options(p)
|
add_global_options(p)
|
||||||
for optname, default in zip(cmd.options, cmd.defaults):
|
for optname, default in zip(cmd.options, cmd.defaults):
|
||||||
|
if optname == 'wallet':
|
||||||
|
continue
|
||||||
a, help = command_options[optname]
|
a, help = command_options[optname]
|
||||||
b = '--' + optname
|
b = '--' + optname
|
||||||
action = "store_true" if default is False else 'store'
|
action = "store_true" if default is False else 'store'
|
||||||
@@ -1154,6 +1160,8 @@ def get_parser():
|
|||||||
p.add_argument(*args, dest=optname, action=action, default=default, help=help)
|
p.add_argument(*args, dest=optname, action=action, default=default, help=help)
|
||||||
|
|
||||||
for param in cmd.params:
|
for param in cmd.params:
|
||||||
|
if param == 'wallet':
|
||||||
|
continue
|
||||||
h = param_descriptions.get(param, '')
|
h = param_descriptions.get(param, '')
|
||||||
_type = arg_types.get(param, str)
|
_type = arg_types.get(param, str)
|
||||||
p.add_argument(param, help=h, type=_type)
|
p.add_argument(param, help=h, type=_type)
|
||||||
|
|||||||
@@ -339,7 +339,7 @@ class Daemon(Logger):
|
|||||||
self.methods = jsonrpcserver.methods.Methods()
|
self.methods = jsonrpcserver.methods.Methods()
|
||||||
self.methods.add(self.ping)
|
self.methods.add(self.ping)
|
||||||
self.methods.add(self.gui)
|
self.methods.add(self.gui)
|
||||||
self.cmd_runner = Commands(self.config, None, self.network, self)
|
self.cmd_runner = Commands(self.config, self.network, self)
|
||||||
for cmdname in known_commands:
|
for cmdname in known_commands:
|
||||||
self.methods.add(getattr(self.cmd_runner, cmdname))
|
self.methods.add(getattr(self.cmd_runner, cmdname))
|
||||||
self.methods.add(self.run_cmdline)
|
self.methods.add(self.run_cmdline)
|
||||||
@@ -435,8 +435,7 @@ class Daemon(Logger):
|
|||||||
wallet = self.wallets.get(path)
|
wallet = self.wallets.get(path)
|
||||||
if wallet is None:
|
if wallet is None:
|
||||||
return {'error': 'Wallet "%s" is not loaded. Use "electrum load_wallet"'%os.path.basename(path) }
|
return {'error': 'Wallet "%s" is not loaded. Use "electrum load_wallet"'%os.path.basename(path) }
|
||||||
else:
|
config_options['wallet'] = wallet
|
||||||
wallet = None
|
|
||||||
# arguments passed to function
|
# arguments passed to function
|
||||||
args = map(lambda x: config.get(x), cmd.params)
|
args = map(lambda x: config.get(x), cmd.params)
|
||||||
# decode json arguments
|
# decode json arguments
|
||||||
@@ -444,9 +443,8 @@ class Daemon(Logger):
|
|||||||
# options
|
# options
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
for x in cmd.options:
|
for x in cmd.options:
|
||||||
kwargs[x] = (config_options.get(x) if x in ['password', 'new_password'] else config.get(x))
|
kwargs[x] = (config_options.get(x) if x in ['wallet', 'password', 'new_password'] else config.get(x))
|
||||||
cmd_runner = Commands(config, wallet, self.network, self)
|
func = getattr(self.cmd_runner, cmd.name)
|
||||||
func = getattr(cmd_runner, cmd.name)
|
|
||||||
try:
|
try:
|
||||||
result = await func(*args, **kwargs)
|
result = await func(*args, **kwargs)
|
||||||
except TypeError as e:
|
except TypeError as e:
|
||||||
|
|||||||
@@ -211,6 +211,7 @@ async def run_offline_command(config, config_options, plugins):
|
|||||||
config_options['password'] = password
|
config_options['password'] = password
|
||||||
storage.decrypt(password)
|
storage.decrypt(password)
|
||||||
wallet = Wallet(storage)
|
wallet = Wallet(storage)
|
||||||
|
config_options['wallet'] = wallet
|
||||||
else:
|
else:
|
||||||
wallet = None
|
wallet = None
|
||||||
# check password
|
# check password
|
||||||
@@ -230,8 +231,8 @@ async def run_offline_command(config, config_options, plugins):
|
|||||||
# options
|
# options
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
for x in cmd.options:
|
for x in cmd.options:
|
||||||
kwargs[x] = (config_options.get(x) if x in ['password', 'new_password'] else config.get(x))
|
kwargs[x] = (config_options.get(x) if x in ['wallet', 'password', 'new_password'] else config.get(x))
|
||||||
cmd_runner = Commands(config, wallet, None)
|
cmd_runner = Commands(config, None, None)
|
||||||
func = getattr(cmd_runner, cmd.name)
|
func = getattr(cmd_runner, cmd.name)
|
||||||
result = await func(*args, **kwargs)
|
result = await func(*args, **kwargs)
|
||||||
# save wallet
|
# save wallet
|
||||||
|
|||||||
Reference in New Issue
Block a user