diff --git a/iota/multisig/commands/__init__.py b/iota/multisig/commands/__init__.py index ff7fa14..80470a7 100644 --- a/iota/multisig/commands/__init__.py +++ b/iota/multisig/commands/__init__.py @@ -1,7 +1,6 @@ # coding=utf-8 from __future__ import absolute_import, division, print_function, \ - unicode_literals - + unicode_literals from .create_multisig_address import * from .get_digests import * diff --git a/iota/multisig/commands/create_multisig_address.py b/iota/multisig/commands/create_multisig_address.py index 9b49eb9..06ff70c 100644 --- a/iota/multisig/commands/create_multisig_address.py +++ b/iota/multisig/commands/create_multisig_address.py @@ -1,53 +1,55 @@ # coding=utf-8 from __future__ import absolute_import, division, print_function, \ - unicode_literals + unicode_literals from typing import List import filters as f + from iota.commands import FilterCommand, RequestFilter from iota.crypto.types import Digest from iota.filters import Trytes from iota.multisig.crypto.addresses import MultisigAddressBuilder __all__ = [ - 'CreateMultisigAddressCommand', + 'CreateMultisigAddressCommand', ] class CreateMultisigAddressCommand(FilterCommand): - """ - Implements `create_multisig_address` multisig command. + """ + Implements `create_multisig_address` multisig command. + + References: - References: - :py:meth:`iota.multisig.api.MultisigIota.create_multisig_address` - """ - command = 'createMultisigAddress' + """ + command = 'createMultisigAddress' - def get_request_filter(self): - return CreateMultisigAddressRequestFilter() + def get_request_filter(self): + return CreateMultisigAddressRequestFilter() - def get_response_filter(self): - pass + def get_response_filter(self): + pass - def _execute(self, request): - digests = request['digests'] # type: List[Digest] + def _execute(self, request): + digests = request['digests'] # type: List[Digest] - builder = MultisigAddressBuilder() + builder = MultisigAddressBuilder() - for d in digests: - builder.add_digest(d) + for d in digests: + builder.add_digest(d) - return { - 'address': builder.get_address(), - } + return { + 'address': builder.get_address(), + } class CreateMultisigAddressRequestFilter(RequestFilter): - def __init__(self): - super(CreateMultisigAddressRequestFilter, self).__init__({ - 'digests': - f.Required - | f.Array - | f.FilterRepeater(f.Required | Trytes(result_type=Digest)), - }) + def __init__(self): + super(CreateMultisigAddressRequestFilter, self).__init__({ + 'digests': + f.Required | f.Array | f.FilterRepeater( + f.Required | Trytes(Digest), + ), + }) diff --git a/iota/multisig/commands/get_digests.py b/iota/multisig/commands/get_digests.py index 7438a8a..91256b9 100644 --- a/iota/multisig/commands/get_digests.py +++ b/iota/multisig/commands/get_digests.py @@ -1,80 +1,71 @@ # coding=utf-8 from __future__ import absolute_import, division, print_function, \ - unicode_literals + unicode_literals from typing import Optional import filters as f from iota.commands import FilterCommand, RequestFilter -from iota.crypto.addresses import AddressGenerator from iota.crypto.types import Seed -from iota.filters import Trytes +from iota.filters import SecurityLevel, Trytes from iota.multisig.commands.get_private_keys import GetPrivateKeysCommand __all__ = [ - 'GetDigestsCommand', + 'GetDigestsCommand', ] class GetDigestsCommand(FilterCommand): - """ - Implements `getDigests` multisig API command. + """ + Implements `getDigests` multisig API command. + + References: - References: - :py:meth:`iota.multisig.api.MultisigIota.get_digests` - """ - command = 'getDigests' + """ + command = 'getDigests' - def get_request_filter(self): - return GetDigestsRequestFilter() + def get_request_filter(self): + return GetDigestsRequestFilter() - def get_response_filter(self): - pass + def get_response_filter(self): + pass - def _execute(self, request): - count = request['count'] # type: Optional[int] - index = request['index'] # type: int - seed = request['seed'] # type: Seed - security_level = request['securityLevel'] # type: int + def _execute(self, request): + count = request['count'] # type: Optional[int] + index = request['index'] # type: int + seed = request['seed'] # type: Seed + security_level = request['securityLevel'] # type: int - gpk_result =\ - GetPrivateKeysCommand(self.adapter)( - seed = seed, - count = count, - index = index, - securityLevel = security_level, - ) + gpk_result = GetPrivateKeysCommand(self.adapter)( + seed=seed, + count=count, + index=index, + securityLevel=security_level, + ) - return { - 'digests': [key.get_digest() for key in gpk_result['keys']], - } + return { + 'digests': [key.get_digest() for key in gpk_result['keys']], + } class GetDigestsRequestFilter(RequestFilter): - def __init__(self): - super(GetDigestsRequestFilter, self).__init__( - { - # Optional Parameters - 'count': - f.Type(int) | f.Min(1) | f.Optional(default=1), - - 'index': - f.Type(int) | f.Min(0) | f.Optional(default=0), - - 'securityLevel': - f.Type(int) - | f.Min(1) - | f.Optional(default=AddressGenerator.DEFAULT_SECURITY_LEVEL), - - # Required Parameters - 'seed': - f.Required | Trytes(result_type=Seed), - }, - - allow_missing_keys = { - 'count', - 'index', - 'securityLevel', - }, - ) + def __init__(self): + super(GetDigestsRequestFilter, self).__init__( + { + # Optional Parameters + 'count': f.Type(int) | f.Min(1) | f.Optional(default=1), + 'index': f.Type(int) | f.Min(0) | f.Optional(default=0), + 'securityLevel': SecurityLevel, + + # Required Parameters + 'seed': f.Required | Trytes(Seed), + }, + + allow_missing_keys={ + 'count', + 'index', + 'securityLevel', + }, + ) diff --git a/iota/multisig/commands/get_private_keys.py b/iota/multisig/commands/get_private_keys.py index 0673b49..2a58abf 100644 --- a/iota/multisig/commands/get_private_keys.py +++ b/iota/multisig/commands/get_private_keys.py @@ -1,76 +1,71 @@ # coding=utf-8 from __future__ import absolute_import, division, print_function, \ - unicode_literals + unicode_literals from typing import Optional import filters as f from iota.commands import FilterCommand, RequestFilter -from iota.crypto.addresses import AddressGenerator from iota.crypto.signing import KeyGenerator from iota.crypto.types import Seed -from iota.filters import Trytes +from iota.filters import SecurityLevel, Trytes __all__ = [ - 'GetPrivateKeysCommand', + 'GetPrivateKeysCommand', ] class GetPrivateKeysCommand(FilterCommand): - """ - Implements `get_private_keys` multisig API command. + """ + Implements `get_private_keys` multisig API command. - References: - - :py:meth:`iota.multisig.MultisigIota.get_private_key` - - https://github.com/iotaledger/wiki/blob/master/multisigs.md - """ - command = 'getPrivateKeys' + References: - def get_request_filter(self): - return GetPrivateKeysRequestFilter() + - :py:meth:`iota.multisig.MultisigIota.get_private_key` + - https://github.com/iotaledger/wiki/blob/master/multisigs.md + """ + command = 'getPrivateKeys' - def get_response_filter(self): - pass + def get_request_filter(self): + return GetPrivateKeysRequestFilter() - def _execute(self, request): - count = request['count'] # type: Optional[int] - index = request['index'] # type: int - seed = request['seed'] # type: Seed - security_level = request['securityLevel'] # type: int + def get_response_filter(self): + pass - generator = KeyGenerator(seed) + def _execute(self, request): + count = request['count'] # type: Optional[int] + index = request['index'] # type: int + seed = request['seed'] # type: Seed + security_level = request['securityLevel'] # type: int - return { - 'keys': - generator.get_keys(start=index, count=count, iterations=security_level), - } + generator = KeyGenerator(seed) + + return { + 'keys': generator.get_keys( + start=index, + count=count, + iterations=security_level, + ), + } class GetPrivateKeysRequestFilter(RequestFilter): - def __init__(self): - super(GetPrivateKeysRequestFilter, self).__init__( - { - # Optional Parameters - 'count': - f.Type(int) | f.Min(1) | f.Optional(default=1), - - 'index': - f.Type(int) | f.Min(0) | f.Optional(default=0), - - 'securityLevel': - f.Type(int) - | f.Min(1) - | f.Optional(default=AddressGenerator.DEFAULT_SECURITY_LEVEL), - - # Required Parameters - 'seed': - f.Required | Trytes(result_type=Seed), - }, - - allow_missing_keys = { - 'count', - 'index', - 'securityLevel', - }, - ) + def __init__(self): + super(GetPrivateKeysRequestFilter, self).__init__( + { + # Optional Parameters + 'count': f.Type(int) | f.Min(1) | f.Optional(default=1), + 'index': f.Type(int) | f.Min(0) | f.Optional(default=0), + 'securityLevel': SecurityLevel, + + # Required Parameters + 'seed': f.Required | Trytes(Seed), + }, + + allow_missing_keys={ + 'count', + 'index', + 'securityLevel', + }, + ) diff --git a/iota/multisig/commands/prepare_multisig_transfer.py b/iota/multisig/commands/prepare_multisig_transfer.py index e842cd7..7d43c2c 100644 --- a/iota/multisig/commands/prepare_multisig_transfer.py +++ b/iota/multisig/commands/prepare_multisig_transfer.py @@ -1,6 +1,6 @@ # coding=utf-8 from __future__ import absolute_import, division, print_function, \ - unicode_literals + unicode_literals from typing import List, Optional @@ -15,131 +15,128 @@ from iota.multisig.types import MultisigAddress __all__ = [ - 'PrepareMultisigTransferCommand', + 'PrepareMultisigTransferCommand', ] class PrepareMultisigTransferCommand(FilterCommand): - """ - Implements `prepare_multisig_transfer` multisig API command. + """ + Implements `prepare_multisig_transfer` multisig API command. - References: - - :py:meth:`iota.multisig.api.MultisigIota.prepare_multisig_transfer` - """ - command = 'prepareMultisigTransfer' - - def get_request_filter(self): - return PrepareMultisigTransferRequestFilter() - - def get_response_filter(self): - pass - - def _execute(self, request): - change_address = request['changeAddress'] # type: Optional[Address] - multisig_input = request['multisigInput'] # type: MultisigAddress - transfers = request['transfers'] # type: List[ProposedTransaction] - - bundle = ProposedMultisigBundle(transfers) - - want_to_spend = bundle.balance - if want_to_spend > 0: - gb_response =\ - GetBalancesCommand(self.adapter)( - addresses = [multisig_input], - ) - - multisig_input.balance = gb_response['balances'][0] - - if multisig_input.balance < want_to_spend: - raise with_context( - exc = - ValueError( - 'Insufficient balance; found {found}, need {need} ' - '(``exc.context`` has more info).'.format( - found = multisig_input.balance, - need = want_to_spend, - ), - ), - - # The structure of this context object is intended to match - # the one from ``PrepareTransferCommand``. - context = { - 'available_to_spend': multisig_input.balance, - 'confirmed_inputs': [multisig_input], - 'request': request, - 'want_to_spend': want_to_spend, - }, - ) - - bundle.add_inputs([multisig_input]) + References: - if bundle.balance < 0: - if change_address: - bundle.send_unspent_inputs_to(change_address) + - :py:meth:`iota.multisig.api.MultisigIota.prepare_multisig_transfer` + """ + command = 'prepareMultisigTransfer' + + def get_request_filter(self): + return PrepareMultisigTransferRequestFilter() + + def get_response_filter(self): + pass + + def _execute(self, request): + change_address = request['changeAddress'] # type: Optional[Address] + multisig_input = request['multisigInput'] # type: MultisigAddress + transfers = request['transfers'] # type: List[ProposedTransaction] + + bundle = ProposedMultisigBundle(transfers) + + want_to_spend = bundle.balance + if want_to_spend > 0: + gb_response = GetBalancesCommand(self.adapter)( + addresses=[multisig_input], + ) + + multisig_input.balance = gb_response['balances'][0] + + if multisig_input.balance < want_to_spend: + raise with_context( + exc=ValueError( + 'Insufficient balance; found {found}, need {need} ' + '(``exc.context`` has more info).'.format( + found=multisig_input.balance, + need=want_to_spend, + ), + ), + + # The structure of this context object is intended + # to match the one from ``PrepareTransferCommand``. + context={ + 'available_to_spend': multisig_input.balance, + 'confirmed_inputs': [multisig_input], + 'request': request, + 'want_to_spend': want_to_spend, + }, + ) + + bundle.add_inputs([multisig_input]) + + if bundle.balance < 0: + if change_address: + bundle.send_unspent_inputs_to(change_address) + else: + # + # Unlike :py:meth:`iota.api.Iota.prepare_transfer` + # where all of the inputs are owned by the same + # seed, creating a multisig transfer usually + # involves multiple people. + # + # It would be unfair to the participants of the + # transaction if we were to automatically generate a + # change address using the seed of whoever happened + # to invoke the + # :py:meth:`MultisigIota.prepare_multisig_transfer` + # method! + # + raise with_context( + exc=ValueError( + 'Bundle has unspent inputs, ' + 'but no change address specified.', + ), + + context={ + 'available_to_spend': multisig_input.balance, + 'balance': bundle.balance, + 'confirmed_inputs': [multisig_input], + 'request': request, + 'want_to_spend': want_to_spend, + }, + ) else: - # - # Unlike :py:meth:`iota.api.Iota.prepare_transfer` where all - # of the inputs are owned by the same seed, creating a - # multisig transfer usually involves multiple people. - # - # It would be unfair to the participants of the transaction - # if we were to automatically generate a change address using - # the seed of whoever happened to invoke the - # :py:meth:`MultisigIota.prepare_multisig_transfer` method! - # - raise with_context( - exc = - ValueError( - 'Bundle has unspent inputs, but no change address specified.', - ), - - context = { - 'available_to_spend': multisig_input.balance, - 'balance': bundle.balance, - 'confirmed_inputs': [multisig_input], - 'request': request, - 'want_to_spend': want_to_spend, - }, - ) - else: - raise with_context( - exc = - ValueError( - 'Use ``prepare_transfer`` ' - 'to create a bundle without spending IOTAs.', - ), + raise with_context( + exc=ValueError( + 'Use ``prepare_transfer`` ' + 'to create a bundle without spending IOTAs.', + ), - context = { - 'request': request, - }, - ) + context={ + 'request': request, + }, + ) - bundle.finalize() + bundle.finalize() - # Return the bundle with inputs unsigned. - return { - 'trytes': bundle.as_tryte_strings(), - } + # Return the bundle with inputs unsigned. + return { + 'trytes': bundle.as_tryte_strings(), + } class PrepareMultisigTransferRequestFilter(RequestFilter): - def __init__(self): - super(PrepareMultisigTransferRequestFilter, self).__init__( - { - 'changeAddress': - Trytes(result_type=Address), - - 'multisigInput': - f.Required - | f.Type(MultisigAddress), - - 'transfers': - f.Required - | f.Array - | f.FilterRepeater(f.Required | f.Type(ProposedTransaction)), - }, - - allow_missing_keys = { - 'changeAddress', - }, - ) + def __init__(self): + super(PrepareMultisigTransferRequestFilter, self).__init__( + { + 'changeAddress': Trytes(Address), + 'multisigInput': f.Required | f.Type(MultisigAddress), + + 'transfers': + f.Required | f.Array | f.FilterRepeater( + f.Required | f.Type(ProposedTransaction), + ), + }, + + allow_missing_keys={ + 'changeAddress', + }, + )