Convert --amount, --amount_everything to generic amount (int or str) in daemon.py.
Unpack the generic amount in transaction.py and account.py. Eliminate separate "everything" keyword args.
This commit is contained in:
parent
07e8ab37e9
commit
cfefe99ecb
5 changed files with 106 additions and 88 deletions
lbry
tests/unit/wallet
|
@ -11,7 +11,7 @@ import random
|
||||||
import tracemalloc
|
import tracemalloc
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from urllib.parse import urlencode, quote
|
from urllib.parse import urlencode, quote
|
||||||
from typing import Callable, Optional, List
|
from typing import Callable, Optional, List, Union
|
||||||
from binascii import hexlify, unhexlify
|
from binascii import hexlify, unhexlify
|
||||||
from traceback import format_exc
|
from traceback import format_exc
|
||||||
from functools import wraps, partial
|
from functools import wraps, partial
|
||||||
|
@ -25,7 +25,7 @@ from lbry.wallet import (
|
||||||
Wallet, ENCRYPT_ON_DISK, SingleKey, HierarchicalDeterministic,
|
Wallet, ENCRYPT_ON_DISK, SingleKey, HierarchicalDeterministic,
|
||||||
Transaction, Output, Input, Account, database
|
Transaction, Output, Input, Account, database
|
||||||
)
|
)
|
||||||
from lbry.wallet.dewies import dewies_to_lbc, lbc_to_dewies, dict_values_to_lbc
|
from lbry.wallet.dewies import dewies_to_lbc, lbc_to_dewies, dict_values_to_lbc, AMOUNT_EVERYTHING
|
||||||
from lbry.wallet.constants import TXO_TYPES, CLAIM_TYPE_NAMES
|
from lbry.wallet.constants import TXO_TYPES, CLAIM_TYPE_NAMES
|
||||||
from lbry.wallet.bip32 import PrivateKey
|
from lbry.wallet.bip32 import PrivateKey
|
||||||
from lbry.crypto.base58 import Base58
|
from lbry.crypto.base58 import Base58
|
||||||
|
@ -1569,34 +1569,17 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
account = wallet.get_account_or_default(change_account_id)
|
account = wallet.get_account_or_default(change_account_id)
|
||||||
accounts = wallet.get_accounts_or_all(funding_account_ids)
|
accounts = wallet.get_accounts_or_all(funding_account_ids)
|
||||||
|
|
||||||
amount = self.get_dewies_or_error('amount', amount, everything=amount_everything)
|
amount = self.get_amount_or_error('amount', amount, everything=amount_everything)
|
||||||
|
|
||||||
if addresses is None:
|
if addresses is None:
|
||||||
raise InputValueIsNoneError('addresses')
|
raise InputValueIsNoneError('addresses')
|
||||||
if addresses and not isinstance(addresses, list):
|
if addresses and not isinstance(addresses, list):
|
||||||
addresses = [addresses]
|
addresses = [addresses]
|
||||||
|
|
||||||
outputs = []
|
|
||||||
for address in addresses:
|
for address in addresses:
|
||||||
self.valid_address_or_error(address, allow_script_address=True)
|
self.valid_address_or_error(address, allow_script_address=True)
|
||||||
if self.ledger.is_pubkey_address(address):
|
|
||||||
outputs.append(
|
|
||||||
Output.pay_pubkey_hash(
|
|
||||||
amount, self.ledger.address_to_hash160(address)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
elif self.ledger.is_script_address(address):
|
|
||||||
outputs.append(
|
|
||||||
Output.pay_script_hash(
|
|
||||||
amount, self.ledger.address_to_hash160(address)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
raise ValueError(f"Unsupported address: '{address}'") # TODO: use error from lbry.error
|
|
||||||
|
|
||||||
tx = await Transaction.create(
|
tx = await Transaction.pay(amount, addresses, accounts, account)
|
||||||
[], outputs, accounts, account, everything=amount_everything
|
|
||||||
)
|
|
||||||
if not preview:
|
if not preview:
|
||||||
await self.broadcast_or_release(tx, blocking)
|
await self.broadcast_or_release(tx, blocking)
|
||||||
self.component_manager.loop.create_task(self.analytics_manager.send_credits_sent())
|
self.component_manager.loop.create_task(self.analytics_manager.send_credits_sent())
|
||||||
|
@ -1868,7 +1851,7 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
wallet = self.wallet_manager.get_wallet_or_default(wallet_id)
|
wallet = self.wallet_manager.get_wallet_or_default(wallet_id)
|
||||||
to_account = wallet.get_account_or_default(to_account)
|
to_account = wallet.get_account_or_default(to_account)
|
||||||
from_account = wallet.get_account_or_default(from_account)
|
from_account = wallet.get_account_or_default(from_account)
|
||||||
amount = self.get_dewies_or_error('amount', amount, everything=everything,
|
amount = self.get_amount_or_error('amount', amount, everything=everything,
|
||||||
default_value=0, argument_everything='everything')
|
default_value=0, argument_everything='everything')
|
||||||
if not isinstance(outputs, int):
|
if not isinstance(outputs, int):
|
||||||
# TODO: use error from lbry.error
|
# TODO: use error from lbry.error
|
||||||
|
@ -1877,8 +1860,7 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
# TODO: use error from lbry.error
|
# TODO: use error from lbry.error
|
||||||
raise ValueError("Using --everything along with --outputs is not supported.")
|
raise ValueError("Using --everything along with --outputs is not supported.")
|
||||||
return from_account.fund(
|
return from_account.fund(
|
||||||
to_account=to_account, amount=amount, everything=everything,
|
to_account=to_account, amount=amount, outputs=outputs, broadcast=broadcast
|
||||||
outputs=outputs, broadcast=broadcast
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@requires("wallet")
|
@requires("wallet")
|
||||||
|
@ -2770,7 +2752,7 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
account = wallet.get_account_or_default(account_id)
|
account = wallet.get_account_or_default(account_id)
|
||||||
funding_accounts = wallet.get_accounts_or_all(funding_account_ids)
|
funding_accounts = wallet.get_accounts_or_all(funding_account_ids)
|
||||||
self.valid_channel_name_or_error(name)
|
self.valid_channel_name_or_error(name)
|
||||||
amount = self.get_dewies_or_error('bid', bid, positive_value=True, everything=bid_everything)
|
amount = self.get_amount_or_error('bid', bid, positive_value=True, everything=bid_everything)
|
||||||
claim_address = await self.get_receiving_address(claim_address, account)
|
claim_address = await self.get_receiving_address(claim_address, account)
|
||||||
|
|
||||||
existing_channels = await self.ledger.get_channels(accounts=wallet.accounts, claim_name=name)
|
existing_channels = await self.ledger.get_channels(accounts=wallet.accounts, claim_name=name)
|
||||||
|
@ -2785,8 +2767,7 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
claim = Claim()
|
claim = Claim()
|
||||||
claim.channel.update(**kwargs)
|
claim.channel.update(**kwargs)
|
||||||
tx = await Transaction.claim_create(
|
tx = await Transaction.claim_create(
|
||||||
name, claim, amount, claim_address, funding_accounts, funding_accounts[0],
|
name, claim, amount, claim_address, funding_accounts, funding_accounts[0]
|
||||||
everything=bid_everything
|
|
||||||
)
|
)
|
||||||
txo = tx.outputs[0]
|
txo = tx.outputs[0]
|
||||||
txo.set_channel_private_key(
|
txo.set_channel_private_key(
|
||||||
|
@ -2925,7 +2906,7 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
f"A claim with id '{claim_id}' was found but it is not a channel."
|
f"A claim with id '{claim_id}' was found but it is not a channel."
|
||||||
)
|
)
|
||||||
|
|
||||||
amount = self.get_dewies_or_error('bid', bid, positive_value=True, everything=bid_everything,
|
amount = self.get_amount_or_error('bid', bid, positive_value=True, everything=bid_everything,
|
||||||
default_value=old_txo.amount)
|
default_value=old_txo.amount)
|
||||||
|
|
||||||
if claim_address is not None:
|
if claim_address is not None:
|
||||||
|
@ -2940,8 +2921,7 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
claim = Claim.from_bytes(old_txo.claim.to_bytes())
|
claim = Claim.from_bytes(old_txo.claim.to_bytes())
|
||||||
claim.channel.update(**kwargs)
|
claim.channel.update(**kwargs)
|
||||||
tx = await Transaction.claim_update(
|
tx = await Transaction.claim_update(
|
||||||
old_txo, claim, amount, claim_address, funding_accounts, funding_accounts[0],
|
old_txo, claim, amount, claim_address, funding_accounts, funding_accounts[0]
|
||||||
everything=bid_everything
|
|
||||||
)
|
)
|
||||||
new_txo = tx.outputs[0]
|
new_txo = tx.outputs[0]
|
||||||
|
|
||||||
|
@ -3369,7 +3349,7 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
account = wallet.get_account_or_default(account_id)
|
account = wallet.get_account_or_default(account_id)
|
||||||
funding_accounts = wallet.get_accounts_or_all(funding_account_ids)
|
funding_accounts = wallet.get_accounts_or_all(funding_account_ids)
|
||||||
channel = await self.get_channel_or_none(wallet, channel_account_id, channel_id, channel_name, for_signing=True)
|
channel = await self.get_channel_or_none(wallet, channel_account_id, channel_id, channel_name, for_signing=True)
|
||||||
amount = self.get_dewies_or_error('bid', bid, positive_value=True, everything=bid_everything)
|
amount = self.get_amount_or_error('bid', bid, positive_value=True, everything=bid_everything)
|
||||||
claim_address = await self.get_receiving_address(claim_address, account)
|
claim_address = await self.get_receiving_address(claim_address, account)
|
||||||
claims = await account.get_claims(claim_name=name)
|
claims = await account.get_claims(claim_name=name)
|
||||||
if len(claims) > 0:
|
if len(claims) > 0:
|
||||||
|
@ -3389,8 +3369,7 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
claim.repost.update(**kwargs)
|
claim.repost.update(**kwargs)
|
||||||
claim.repost.reference.claim_id = claim_id
|
claim.repost.reference.claim_id = claim_id
|
||||||
tx = await Transaction.claim_create(
|
tx = await Transaction.claim_create(
|
||||||
name, claim, amount, claim_address, funding_accounts, funding_accounts[0], channel,
|
name, claim, amount, claim_address, funding_accounts, funding_accounts[0], channel
|
||||||
everything=bid_everything
|
|
||||||
)
|
)
|
||||||
new_txo = tx.outputs[0]
|
new_txo = tx.outputs[0]
|
||||||
|
|
||||||
|
@ -3525,7 +3504,7 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
account = wallet.get_account_or_default(account_id)
|
account = wallet.get_account_or_default(account_id)
|
||||||
funding_accounts = wallet.get_accounts_or_all(funding_account_ids)
|
funding_accounts = wallet.get_accounts_or_all(funding_account_ids)
|
||||||
channel = await self.get_channel_or_none(wallet, channel_account_id, channel_id, channel_name, for_signing=True)
|
channel = await self.get_channel_or_none(wallet, channel_account_id, channel_id, channel_name, for_signing=True)
|
||||||
amount = self.get_dewies_or_error('bid', bid, positive_value=True, everything=bid_everything)
|
amount = self.get_amount_or_error('bid', bid, positive_value=True, everything=bid_everything)
|
||||||
claim_address = await self.get_receiving_address(claim_address, account)
|
claim_address = await self.get_receiving_address(claim_address, account)
|
||||||
kwargs['fee_address'] = self.get_fee_address(kwargs, claim_address)
|
kwargs['fee_address'] = self.get_fee_address(kwargs, claim_address)
|
||||||
|
|
||||||
|
@ -3550,8 +3529,7 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
else:
|
else:
|
||||||
claim.stream.update(**kwargs)
|
claim.stream.update(**kwargs)
|
||||||
tx = await Transaction.claim_create(
|
tx = await Transaction.claim_create(
|
||||||
name, claim, amount, claim_address, funding_accounts, funding_accounts[0], channel,
|
name, claim, amount, claim_address, funding_accounts, funding_accounts[0], channel
|
||||||
everything=bid_everything
|
|
||||||
)
|
)
|
||||||
new_txo = tx.outputs[0]
|
new_txo = tx.outputs[0]
|
||||||
|
|
||||||
|
@ -3735,7 +3713,7 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
f"A claim with id '{claim_id}' was found but it is not a stream or repost claim."
|
f"A claim with id '{claim_id}' was found but it is not a stream or repost claim."
|
||||||
)
|
)
|
||||||
|
|
||||||
amount = self.get_dewies_or_error('bid', bid, positive_value=True, everything=bid_everything,
|
amount = self.get_amount_or_error('bid', bid, positive_value=True, everything=bid_everything,
|
||||||
default_value=old_txo.amount)
|
default_value=old_txo.amount)
|
||||||
|
|
||||||
if claim_address is not None:
|
if claim_address is not None:
|
||||||
|
@ -3783,8 +3761,7 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
claim.clear_signature()
|
claim.clear_signature()
|
||||||
tx = await Transaction.claim_update(
|
tx = await Transaction.claim_update(
|
||||||
old_txo, claim, amount, claim_address, funding_accounts, funding_accounts[0],
|
old_txo, claim, amount, claim_address, funding_accounts, funding_accounts[0],
|
||||||
channel if not clear_channel else None,
|
channel if not clear_channel else None
|
||||||
everything=bid_everything
|
|
||||||
)
|
)
|
||||||
|
|
||||||
new_txo = tx.outputs[0]
|
new_txo = tx.outputs[0]
|
||||||
|
@ -4028,7 +4005,7 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
funding_accounts = wallet.get_accounts_or_all(funding_account_ids)
|
funding_accounts = wallet.get_accounts_or_all(funding_account_ids)
|
||||||
self.valid_collection_name_or_error(name)
|
self.valid_collection_name_or_error(name)
|
||||||
channel = await self.get_channel_or_none(wallet, channel_account_id, channel_id, channel_name, for_signing=True)
|
channel = await self.get_channel_or_none(wallet, channel_account_id, channel_id, channel_name, for_signing=True)
|
||||||
amount = self.get_dewies_or_error('bid', bid, positive_value=True, everything=bid_everything)
|
amount = self.get_amount_or_error('bid', bid, positive_value=True, everything=bid_everything)
|
||||||
|
|
||||||
claim_address = await self.get_receiving_address(claim_address, account)
|
claim_address = await self.get_receiving_address(claim_address, account)
|
||||||
|
|
||||||
|
@ -4046,8 +4023,7 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
claim = Claim()
|
claim = Claim()
|
||||||
claim.collection.update(claims=claims, **kwargs)
|
claim.collection.update(claims=claims, **kwargs)
|
||||||
tx = await Transaction.claim_create(
|
tx = await Transaction.claim_create(
|
||||||
name, claim, amount, claim_address, funding_accounts, funding_accounts[0], channel,
|
name, claim, amount, claim_address, funding_accounts, funding_accounts[0], channel
|
||||||
everything=bid_everything
|
|
||||||
)
|
)
|
||||||
new_txo = tx.outputs[0]
|
new_txo = tx.outputs[0]
|
||||||
|
|
||||||
|
@ -4176,7 +4152,7 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
f"A claim with id '{claim_id}' was found but it is not a collection."
|
f"A claim with id '{claim_id}' was found but it is not a collection."
|
||||||
)
|
)
|
||||||
|
|
||||||
amount = self.get_dewies_or_error('bid', bid, positive_value=True, everything=bid_everything,
|
amount = self.get_amount_or_error('bid', bid, positive_value=True, everything=bid_everything,
|
||||||
default_value=old_txo.amount)
|
default_value=old_txo.amount)
|
||||||
|
|
||||||
if claim_address is not None:
|
if claim_address is not None:
|
||||||
|
@ -4198,8 +4174,7 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
claim = Claim.from_bytes(old_txo.claim.to_bytes())
|
claim = Claim.from_bytes(old_txo.claim.to_bytes())
|
||||||
claim.collection.update(**kwargs)
|
claim.collection.update(**kwargs)
|
||||||
tx = await Transaction.claim_update(
|
tx = await Transaction.claim_update(
|
||||||
old_txo, claim, amount, claim_address, funding_accounts, funding_accounts[0], channel,
|
old_txo, claim, amount, claim_address, funding_accounts, funding_accounts[0], channel
|
||||||
everything=bid_everything
|
|
||||||
)
|
)
|
||||||
new_txo = tx.outputs[0]
|
new_txo = tx.outputs[0]
|
||||||
|
|
||||||
|
@ -4362,7 +4337,7 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
assert not wallet.is_locked, "Cannot spend funds with locked wallet, unlock first."
|
assert not wallet.is_locked, "Cannot spend funds with locked wallet, unlock first."
|
||||||
funding_accounts = wallet.get_accounts_or_all(funding_account_ids)
|
funding_accounts = wallet.get_accounts_or_all(funding_account_ids)
|
||||||
channel = await self.get_channel_or_none(wallet, channel_account_id, channel_id, channel_name, for_signing=True)
|
channel = await self.get_channel_or_none(wallet, channel_account_id, channel_id, channel_name, for_signing=True)
|
||||||
amount = self.get_dewies_or_error('amount', amount, everything=amount_everything)
|
amount = self.get_amount_or_error('amount', amount, everything=amount_everything)
|
||||||
|
|
||||||
claim = await self.ledger.get_claim_by_claim_id(claim_id)
|
claim = await self.ledger.get_claim_by_claim_id(claim_id)
|
||||||
claim_address = claim.get_address(self.ledger)
|
claim_address = claim.get_address(self.ledger)
|
||||||
|
@ -4372,7 +4347,7 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
|
|
||||||
tx = await Transaction.support(
|
tx = await Transaction.support(
|
||||||
claim.claim_name, claim_id, amount, claim_address, funding_accounts, funding_accounts[0], channel,
|
claim.claim_name, claim_id, amount, claim_address, funding_accounts, funding_accounts[0], channel,
|
||||||
comment=comment, everything=amount_everything
|
comment=comment
|
||||||
)
|
)
|
||||||
new_txo = tx.outputs[0]
|
new_txo = tx.outputs[0]
|
||||||
|
|
||||||
|
@ -5493,25 +5468,29 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
raise ValueError(f"Couldn't find channel with channel_{key} '{value}'.")
|
raise ValueError(f"Couldn't find channel with channel_{key} '{value}'.")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_dewies_or_error(argument: str, lbc: Optional[str],
|
def get_dewies_or_error(argument: str, lbc: str, positive_value: bool = False) -> int:
|
||||||
|
try:
|
||||||
|
dewies = lbc_to_dewies(lbc)
|
||||||
|
if positive_value and dewies <= 0:
|
||||||
|
# TODO: use error from lbry.error
|
||||||
|
raise ValueError(f"'{argument}' value must be greater than 0.0")
|
||||||
|
return dewies
|
||||||
|
except ValueError as e:
|
||||||
|
# TODO: use error from lbry.error
|
||||||
|
raise ValueError(f"Invalid value for '{argument}': {e.args[0]}")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_amount_or_error(argument: str, lbc: Optional[str],
|
||||||
positive_value: bool = False, everything: bool = False,
|
positive_value: bool = False, everything: bool = False,
|
||||||
default_value: Optional[int] = None,
|
default_value: Optional[int] = None,
|
||||||
argument_everything: Optional[str] = None) -> int:
|
argument_everything: Optional[str] = None) -> Union[int, str]:
|
||||||
if everything:
|
if everything:
|
||||||
if lbc is not None:
|
if lbc is not None:
|
||||||
argument_everything = argument_everything or argument + '_everything'
|
argument_everything = argument_everything or argument + '_everything'
|
||||||
raise ConflictingInputValueError(argument, argument_everything)
|
raise ConflictingInputValueError(argument, argument_everything)
|
||||||
return 0
|
return AMOUNT_EVERYTHING
|
||||||
elif lbc is not None:
|
elif lbc is not None:
|
||||||
try:
|
return Daemon.get_dewies_or_error(argument, lbc, positive_value=positive_value)
|
||||||
dewies = lbc_to_dewies(lbc)
|
|
||||||
if positive_value and dewies <= 0:
|
|
||||||
# TODO: use error from lbry.error
|
|
||||||
raise ValueError(f"'{argument}' value must be greater than 0.0")
|
|
||||||
return dewies
|
|
||||||
except ValueError as e:
|
|
||||||
# TODO: use error from lbry.error
|
|
||||||
raise ValueError(f"Invalid value for '{argument}': {e.args[0]}")
|
|
||||||
elif default_value is not None:
|
elif default_value is not None:
|
||||||
return default_value
|
return default_value
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -7,10 +7,11 @@ import asyncio
|
||||||
import random
|
import random
|
||||||
from hashlib import sha256
|
from hashlib import sha256
|
||||||
from string import hexdigits
|
from string import hexdigits
|
||||||
from typing import Type, Dict, Tuple, Optional, Any, List
|
from typing import Type, Dict, Tuple, Optional, Any, List, Union
|
||||||
|
|
||||||
from lbry.error import InvalidPasswordError
|
from lbry.error import InvalidPasswordError
|
||||||
from lbry.crypto.crypt import aes_encrypt, aes_decrypt
|
from lbry.crypto.crypt import aes_encrypt, aes_decrypt
|
||||||
|
from lbry.wallet.dewies import amount_to_dewies
|
||||||
|
|
||||||
from .bip32 import PrivateKey, PublicKey, KeyPath, from_extended_key_string
|
from .bip32 import PrivateKey, PublicKey, KeyPath, from_extended_key_string
|
||||||
from .mnemonic import Mnemonic
|
from .mnemonic import Mnemonic
|
||||||
|
@ -526,9 +527,10 @@ class Account:
|
||||||
def get_transaction_count(self, **constraints):
|
def get_transaction_count(self, **constraints):
|
||||||
return self.ledger.get_transaction_count(wallet=self.wallet, accounts=[self], **constraints)
|
return self.ledger.get_transaction_count(wallet=self.wallet, accounts=[self], **constraints)
|
||||||
|
|
||||||
async def fund(self, to_account, amount=None, everything=False,
|
async def fund(self, to_account, amount: Union[int, str],
|
||||||
outputs=1, broadcast=False, **constraints):
|
outputs=1, broadcast=False, **constraints):
|
||||||
assert self.ledger == to_account.ledger, 'Can only transfer between accounts of the same ledger.'
|
assert self.ledger == to_account.ledger, 'Can only transfer between accounts of the same ledger.'
|
||||||
|
dewies, everything = amount_to_dewies(amount)
|
||||||
if everything:
|
if everything:
|
||||||
utxos = await self.get_utxos(**constraints)
|
utxos = await self.get_utxos(**constraints)
|
||||||
await self.ledger.reserve_outputs(utxos)
|
await self.ledger.reserve_outputs(utxos)
|
||||||
|
@ -538,13 +540,13 @@ class Account:
|
||||||
funding_accounts=[self],
|
funding_accounts=[self],
|
||||||
change_account=to_account
|
change_account=to_account
|
||||||
)
|
)
|
||||||
elif amount > 0:
|
elif dewies > 0:
|
||||||
to_address = await to_account.change.get_or_create_usable_address()
|
to_address = await to_account.change.get_or_create_usable_address()
|
||||||
to_hash160 = to_account.ledger.address_to_hash160(to_address)
|
to_hash160 = to_account.ledger.address_to_hash160(to_address)
|
||||||
tx = await Transaction.create(
|
tx = await Transaction.create(
|
||||||
inputs=[],
|
inputs=[],
|
||||||
outputs=[
|
outputs=[
|
||||||
Output.pay_pubkey_hash(amount//outputs, to_hash160)
|
Output.pay_pubkey_hash(dewies//outputs, to_hash160)
|
||||||
for _ in range(outputs)
|
for _ in range(outputs)
|
||||||
],
|
],
|
||||||
funding_accounts=[self],
|
funding_accounts=[self],
|
||||||
|
|
|
@ -1,6 +1,24 @@
|
||||||
import textwrap
|
import textwrap
|
||||||
|
from typing import Tuple, Union
|
||||||
from .util import coins_to_satoshis, satoshis_to_coins
|
from .util import coins_to_satoshis, satoshis_to_coins
|
||||||
|
|
||||||
|
# Symbolic amount EVERYTHING
|
||||||
|
AMOUNT_EVERYTHING = "EVERYTHING"
|
||||||
|
|
||||||
|
def amount_is_everything(amount: Union[int, str]) -> bool:
|
||||||
|
if isinstance(amount, str):
|
||||||
|
if amount != AMOUNT_EVERYTHING:
|
||||||
|
raise ValueError(f"The value '{amount}' for argument 'amount' is invalid.")
|
||||||
|
return True
|
||||||
|
elif isinstance(amount, int):
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
raise ValueError(f"The value '{amount}' for argument 'amount' is invalid.")
|
||||||
|
|
||||||
|
def amount_to_dewies(amount: Union[int, str]) -> Tuple[int, bool]:
|
||||||
|
everything = amount_is_everything(amount)
|
||||||
|
dewies = 0 if everything else amount
|
||||||
|
return dewies, everything
|
||||||
|
|
||||||
def lbc_to_dewies(lbc: str) -> int:
|
def lbc_to_dewies(lbc: str) -> int:
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -2,7 +2,7 @@ import struct
|
||||||
import logging
|
import logging
|
||||||
import typing
|
import typing
|
||||||
from binascii import hexlify, unhexlify
|
from binascii import hexlify, unhexlify
|
||||||
from typing import List, Iterable, Optional, Tuple
|
from typing import List, Iterable, Optional, Tuple, Union
|
||||||
|
|
||||||
from lbry.error import InsufficientFundsError
|
from lbry.error import InsufficientFundsError
|
||||||
from lbry.crypto.hash import hash160, sha256
|
from lbry.crypto.hash import hash160, sha256
|
||||||
|
@ -12,6 +12,7 @@ from lbry.schema.claim import Claim
|
||||||
from lbry.schema.base import Signable
|
from lbry.schema.base import Signable
|
||||||
from lbry.schema.purchase import Purchase
|
from lbry.schema.purchase import Purchase
|
||||||
from lbry.schema.support import Support
|
from lbry.schema.support import Support
|
||||||
|
from lbry.wallet.dewies import amount_to_dewies
|
||||||
|
|
||||||
from .script import InputScript, OutputScript
|
from .script import InputScript, OutputScript
|
||||||
from .constants import COIN, DUST, NULL_HASH32
|
from .constants import COIN, DUST, NULL_HASH32
|
||||||
|
@ -793,8 +794,8 @@ class Transaction:
|
||||||
@classmethod
|
@classmethod
|
||||||
async def create(cls, inputs: Iterable[Input], outputs: Iterable[Output],
|
async def create(cls, inputs: Iterable[Input], outputs: Iterable[Output],
|
||||||
funding_accounts: Iterable['Account'], change_account: 'Account',
|
funding_accounts: Iterable['Account'], change_account: 'Account',
|
||||||
everything: bool = False,
|
sign: bool = True,
|
||||||
sign: bool = True):
|
*, everything: bool = False):
|
||||||
""" Find optimal set of inputs when only outputs are provided; add change
|
""" Find optimal set of inputs when only outputs are provided; add change
|
||||||
outputs if only inputs are provided or if inputs are greater than outputs. """
|
outputs if only inputs are provided or if inputs are greater than outputs. """
|
||||||
|
|
||||||
|
@ -915,34 +916,50 @@ class Transaction:
|
||||||
self._reset()
|
self._reset()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def pay(cls, amount: int, address: bytes, funding_accounts: List['Account'], change_account: 'Account',
|
def pay(cls, amount: Union[int, str], addresses: List[bytes],
|
||||||
everything: bool = False):
|
funding_accounts: List['Account'], change_account: 'Account'):
|
||||||
ledger, _ = cls.ensure_all_have_same_ledger_and_wallet(funding_accounts, change_account)
|
ledger, _ = cls.ensure_all_have_same_ledger_and_wallet(funding_accounts, change_account)
|
||||||
output = Output.pay_pubkey_hash(amount, ledger.address_to_hash160(address))
|
dewies, everything = amount_to_dewies(amount)
|
||||||
return cls.create([], [output], funding_accounts, change_account, everything=everything)
|
outputs = []
|
||||||
|
for address in addresses:
|
||||||
|
if ledger.is_pubkey_address(address):
|
||||||
|
outputs.append(
|
||||||
|
Output.pay_pubkey_hash(
|
||||||
|
dewies, ledger.address_to_hash160(address)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
elif ledger.is_script_address(address):
|
||||||
|
outputs.append(
|
||||||
|
Output.pay_script_hash(
|
||||||
|
dewies, ledger.address_to_hash160(address)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Unsupported address: '{address}'") # TODO: use error from lbry.error
|
||||||
|
return cls.create([], outputs, funding_accounts, change_account, everything=everything)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def claim_create(
|
def claim_create(
|
||||||
cls, name: str, claim: Claim, amount: int, holding_address: str,
|
cls, name: str, claim: Claim, amount: Union[int, str], holding_address: str,
|
||||||
funding_accounts: List['Account'], change_account: 'Account', signing_channel: Output = None,
|
funding_accounts: List['Account'], change_account: 'Account', signing_channel: Output = None):
|
||||||
everything: bool = False):
|
|
||||||
ledger, _ = cls.ensure_all_have_same_ledger_and_wallet(funding_accounts, change_account)
|
ledger, _ = cls.ensure_all_have_same_ledger_and_wallet(funding_accounts, change_account)
|
||||||
|
dewies, everything = amount_to_dewies(amount)
|
||||||
claim_output = Output.pay_claim_name_pubkey_hash(
|
claim_output = Output.pay_claim_name_pubkey_hash(
|
||||||
amount, name, claim, ledger.address_to_hash160(holding_address)
|
dewies, name, claim, ledger.address_to_hash160(holding_address)
|
||||||
)
|
)
|
||||||
if signing_channel is not None:
|
if signing_channel is not None:
|
||||||
claim_output.sign(signing_channel, b'placeholder txid:nout')
|
claim_output.sign(signing_channel, b'placeholder txid:nout')
|
||||||
return cls.create([], [claim_output], funding_accounts, change_account,
|
return cls.create([], [claim_output], funding_accounts, change_account,
|
||||||
everything=everything, sign=False)
|
sign=False, everything=everything)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def claim_update(
|
def claim_update(
|
||||||
cls, previous_claim: Output, claim: Claim, amount: int, holding_address: str,
|
cls, previous_claim: Output, claim: Claim, amount: Union[int, str], holding_address: str,
|
||||||
funding_accounts: List['Account'], change_account: 'Account', signing_channel: Output = None,
|
funding_accounts: List['Account'], change_account: 'Account', signing_channel: Output = None):
|
||||||
everything: bool = False):
|
|
||||||
ledger, _ = cls.ensure_all_have_same_ledger_and_wallet(funding_accounts, change_account)
|
ledger, _ = cls.ensure_all_have_same_ledger_and_wallet(funding_accounts, change_account)
|
||||||
|
dewies, everything = amount_to_dewies(amount)
|
||||||
updated_claim = Output.pay_update_claim_pubkey_hash(
|
updated_claim = Output.pay_update_claim_pubkey_hash(
|
||||||
amount, previous_claim.claim_name, previous_claim.claim_id,
|
dewies, previous_claim.claim_name, previous_claim.claim_id,
|
||||||
claim, ledger.address_to_hash160(holding_address)
|
claim, ledger.address_to_hash160(holding_address)
|
||||||
)
|
)
|
||||||
if signing_channel is not None:
|
if signing_channel is not None:
|
||||||
|
@ -951,35 +968,37 @@ class Transaction:
|
||||||
updated_claim.clear_signature()
|
updated_claim.clear_signature()
|
||||||
return cls.create(
|
return cls.create(
|
||||||
[Input.spend(previous_claim)], [updated_claim], funding_accounts, change_account,
|
[Input.spend(previous_claim)], [updated_claim], funding_accounts, change_account,
|
||||||
everything=everything, sign=False
|
sign=False, everything=everything
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def support(cls, claim_name: str, claim_id: str, amount: int, holding_address: str,
|
def support(cls, claim_name: str, claim_id: str, amount: Union[int, str], holding_address: str,
|
||||||
funding_accounts: List['Account'], change_account: 'Account', signing_channel: Output = None,
|
funding_accounts: List['Account'], change_account: 'Account', signing_channel: Output = None,
|
||||||
comment: str = None, everything: bool = False):
|
comment: str = None):
|
||||||
ledger, _ = cls.ensure_all_have_same_ledger_and_wallet(funding_accounts, change_account)
|
ledger, _ = cls.ensure_all_have_same_ledger_and_wallet(funding_accounts, change_account)
|
||||||
|
dewies, everything = amount_to_dewies(amount)
|
||||||
if signing_channel is not None or comment is not None:
|
if signing_channel is not None or comment is not None:
|
||||||
support = Support()
|
support = Support()
|
||||||
if comment is not None:
|
if comment is not None:
|
||||||
support.comment = comment
|
support.comment = comment
|
||||||
support_output = Output.pay_support_data_pubkey_hash(
|
support_output = Output.pay_support_data_pubkey_hash(
|
||||||
amount, claim_name, claim_id, support, ledger.address_to_hash160(holding_address)
|
dewies, claim_name, claim_id, support, ledger.address_to_hash160(holding_address)
|
||||||
)
|
)
|
||||||
if signing_channel is not None:
|
if signing_channel is not None:
|
||||||
support_output.sign(signing_channel, b'placeholder txid:nout')
|
support_output.sign(signing_channel, b'placeholder txid:nout')
|
||||||
else:
|
else:
|
||||||
support_output = Output.pay_support_pubkey_hash(
|
support_output = Output.pay_support_pubkey_hash(
|
||||||
amount, claim_name, claim_id, ledger.address_to_hash160(holding_address)
|
dewies, claim_name, claim_id, ledger.address_to_hash160(holding_address)
|
||||||
)
|
)
|
||||||
return cls.create([], [support_output], funding_accounts, change_account,
|
return cls.create([], [support_output], funding_accounts, change_account,
|
||||||
everything=everything, sign=False)
|
sign=False, everything=everything)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def purchase(cls, claim_id: str, amount: int, merchant_address: bytes,
|
def purchase(cls, claim_id: str, amount: int, merchant_address: bytes,
|
||||||
funding_accounts: List['Account'], change_account: 'Account'):
|
funding_accounts: List['Account'], change_account: 'Account'):
|
||||||
ledger, _ = cls.ensure_all_have_same_ledger_and_wallet(funding_accounts, change_account)
|
ledger, _ = cls.ensure_all_have_same_ledger_and_wallet(funding_accounts, change_account)
|
||||||
payment = Output.pay_pubkey_hash(amount, ledger.address_to_hash160(merchant_address))
|
dewies, _ = amount_to_dewies(amount)
|
||||||
|
payment = Output.pay_pubkey_hash(dewies, ledger.address_to_hash160(merchant_address))
|
||||||
data = Output.add_purchase_data(Purchase(claim_id))
|
data = Output.add_purchase_data(Purchase(claim_id))
|
||||||
return cls.create([], [payment, data], funding_accounts, change_account)
|
return cls.create([], [payment, data], funding_accounts, change_account)
|
||||||
|
|
||||||
|
|
|
@ -374,8 +374,8 @@ class TransactionIOBalancing(AsyncioTestCase):
|
||||||
def txi(self, txo):
|
def txi(self, txo):
|
||||||
return Input.spend(txo)
|
return Input.spend(txo)
|
||||||
|
|
||||||
def tx(self, inputs, outputs, everything: bool = False):
|
def tx(self, inputs, outputs, **kwargs):
|
||||||
return Transaction.create(inputs, outputs, [self.account], self.account, everything=everything)
|
return Transaction.create(inputs, outputs, [self.account], self.account, **kwargs)
|
||||||
|
|
||||||
async def create_utxos(self, amounts):
|
async def create_utxos(self, amounts):
|
||||||
utxos = [self.txo(amount) for amount in amounts]
|
utxos = [self.txo(amount) for amount in amounts]
|
||||||
|
|
Loading…
Add table
Reference in a new issue