Exemple #1
0
    def from_dict(cls: Type[Transaction], value: Dict[str,
                                                      Any]) -> Transaction:
        """
        Construct a new Transaction from a dictionary of parameters.

        Args:
            value: The value to construct the Transaction from.

        Returns:
            A new Transaction object, constructed using the given parameters.

        Raises:
            XRPLModelException: If the dictionary provided is invalid.
        """
        if cls.__name__ == "Transaction":
            # using `Transaction.from_dict` and not a subclass
            if "transaction_type" not in value:
                raise XRPLModelException(
                    "Transaction does not include transaction_type.")
            correct_type = cls.get_transaction_type(value["transaction_type"])
            return correct_type.from_dict(value)
        else:
            if "transaction_type" in value:
                if value["transaction_type"] != cls.__name__:
                    transaction_type = value["transaction_type"]
                    raise XRPLModelException(
                        f"Using wrong constructor: using f{cls.__name__} constructor "
                        f"with transaction type f{transaction_type}.")
                value = {**value}
                del value["transaction_type"]
            return cast(Transaction, super(Transaction, cls).from_dict(value))
Exemple #2
0
    def from_dict(cls: Type[Request], value: Dict[str, Any]) -> Request:
        """
        Construct a new Request from a dictionary of parameters.

        Args:
            value: The value to construct the Request from.

        Returns:
            A new Request object, constructed using the given parameters.

        Raises:
            XRPLModelException: If the dictionary provided is invalid.
        """
        if cls.__name__ == "Request":
            if "method" not in value:
                raise XRPLModelException("Request does not include method.")
            correct_type = cls.get_method(value["method"])
            return correct_type.from_dict(value)

        if "method" in value:
            method = value["method"]
            if _method_to_class_name(method) != cls.__name__ and not (
                    method == "submit"
                    and cls.__name__ in ("SignAndSubmit", "SubmitOnly")):
                raise XRPLModelException(
                    f"Using wrong constructor: using {cls.__name__} constructor "
                    f"with Request method {method}.")
            value = {**value}
            del value["method"]

        return cast(Request, super(Request, cls).from_dict(value))
Exemple #3
0
    def _from_dict_special_cases(
        cls: Type[BaseModel],
        param: str,
        param_type: Type[Any],
        param_value: Dict[str, Any],
    ) -> Union[str, Enum, BaseModel, Dict[str, Any]]:
        """Handles all the recursive/more complex cases for `from_dict`."""
        from xrpl.models.amounts import Amount, IssuedCurrencyAmount
        from xrpl.models.currencies import XRP, Currency, IssuedCurrency
        from xrpl.models.transactions.transaction import Transaction

        # TODO: figure out how to make Unions work generically (if possible)

        if param_type == Amount:
            # special case, Union
            if isinstance(param_value, str):
                return param_value
            if not isinstance(param_value, dict):
                raise XRPLModelException(
                    f"{param_type} requires a dictionary of params")
            return IssuedCurrencyAmount.from_dict(param_value)

        if param_type == Currency:
            # special case, Union
            if not isinstance(param_value, dict):
                raise XRPLModelException(
                    f"{param_type} requires a dictionary of params")
            if "currency" in param_value and "issuer" in param_value:
                return IssuedCurrency.from_dict(param_value)
            if "currency" in param_value:
                param_value_copy = {**param_value}
                del param_value_copy["currency"]
                return XRP.from_dict(param_value_copy)
            raise XRPLModelException(f"No valid type for {param}")

        if param_type == Transaction:
            # special case, multiple options (could be any Transaction type)
            if "transaction_type" not in param_value:
                raise XRPLModelException(
                    f"{param} not a valid parameter for {cls.__name__}")
            type_str = param_value["transaction_type"]
            # safely convert type string into the actual type
            transaction_type = Transaction.get_transaction_type(type_str)
            param_value_copy = {**param_value}
            del param_value_copy["transaction_type"]
            return transaction_type.from_dict(param_value_copy)

        if param_type in BaseModel.__subclasses__():
            # any other BaseModel
            if not isinstance(param_value, dict):
                raise XRPLModelException(
                    f"{param_type} requires a dictionary of params")
            # mypy doesn't know that the If checks that it's a subclass of BaseModel
            return param_type.from_dict(param_value)  # type: ignore

        if param_type in Enum.__subclasses__():
            # mypy doesn't know that the If checks that it's a subclass of Enum
            return param_type(param_value)  # type: ignore

        return param_value
Exemple #4
0
    def _from_dict_single_param(
        cls: Type[BaseModel],
        param: str,
        param_type: Type[Any],
        param_value: Dict[str, Any],
    ) -> Any:
        """Recursively handles each individual param in `from_dict`."""
        if type(param_value) == param_type:
            # the type of the param provided matches the type expected for the param
            return param_value

        if "xrpl.models" in param_type.__module__:  # any model defined in xrpl.models
            if not isinstance(param_value, dict):
                raise XRPLModelException(
                    f"{param_type} requires a dictionary of params")
            return cast(BaseModel, param_type).from_dict(param_value)

        if param_type in Enum.__subclasses__():  # an Enum
            return param_type(param_value)

        # param_type must be something from typing - e.g. List, Union, Any
        # there are no models that have Dict params
        if param_type == Any:
            # param_type is Any
            return param_value

        if param_type.__reduce__()[1][0] == List:
            # param_type is a List
            if not isinstance(param_value, List):
                raise XRPLModelException(
                    f"{param} expected a List, received a {type(param_value)}")
            list_type = param_type.__reduce__()[1][1]
            new_list = []
            for item in param_value:
                new_list.append(
                    cls._from_dict_single_param(param, list_type, item))
            return new_list

        if param_type.__reduce__()[1][0] == Union:
            # param_type is a Union
            for param_type_option in param_type.__args__:
                # iterate through the types Union-ed together
                try:
                    # try to use this Union-ed type to process param_value
                    return cls._from_dict_single_param(param,
                                                       param_type_option,
                                                       param_value)
                except XRPLModelException:
                    # this Union-ed type did not work
                    # move onto the next one
                    continue

        raise XRPLModelException(
            f"{param} expected a {param_type}, received a {type(param_value)}")
Exemple #5
0
    def from_dict(cls: Type[BaseModel], value: Dict[str, Any]) -> BaseModel:
        """
        Construct a new BaseModel from a dictionary of parameters.

        Args:
            value: The value to construct the BaseModel from.

        Returns:
            A new BaseModel object, constructed using the given parameters.

        Raises:
            XRPLModelException: If the dictionary provided is invalid.
        """
        # returns a dictionary mapping class params to their types
        class_types = get_type_hints(cls)

        args = {}
        for param in value:
            if param not in class_types:
                raise XRPLModelException(
                    f"{param} not a valid parameter for {cls.__name__}"
                )

            args[param] = cls._from_dict_single_param(
                param, class_types[param], value[param]
            )

        init = cls._get_only_init_args(args)
        # Ignore type-checking on this for now to simplify subclass constructors
        # which might pass non kwargs.
        return cls(**init)  # type: ignore
Exemple #6
0
    def get_transaction_type(cls: Type[Transaction],
                             transaction_type: str) -> Type[Transaction]:
        """
        Returns the correct transaction type based on the string name.

        Args:
            transaction_type: The String name of the Transaction object.

        Returns:
            The transaction class with the given name.

        Raises:
            XRPLModelException: If `transaction_type` is not a valid Transaction type.
        """
        import xrpl.models.transactions as transaction_models

        transaction_types: Dict[str, Type[Transaction]] = {
            t.value: getattr(transaction_models, t)
            for t in transaction_models.transaction.TransactionType
        }
        if transaction_type in transaction_types:
            return transaction_types[transaction_type]

        raise XRPLModelException(
            f"{transaction_type} is not a valid Transaction type")
Exemple #7
0
 def new_init(self: _Self, *args: List[Any], **kwargs: Dict[str,
                                                            Any]) -> None:
     if len(args) > 0:
         raise XRPLModelException(
             f"{type(self).__name__}.__init__ only allows keyword arguments. "
             f"Found the following positional arguments: {args}")
     original_init(self, **kwargs)  # type: ignore
Exemple #8
0
    def validate(self: BaseModel) -> None:
        """
        Raises if this object is invalid.

        Raises:
            XRPLModelException: if this object is invalid.
        """
        errors = self._get_errors()
        if len(errors) > 0:
            raise XRPLModelException(str(errors))
Exemple #9
0
    def get_hash(self: Transaction) -> str:
        """
        Hashes the Transaction object as the ledger does. Only valid for signed
        Transaction objects.

        Returns:
            The hash of the Transaction object.

        Raises:
            XRPLModelException: if the Transaction is unsigned.
        """
        if self.txn_signature is None:
            raise XRPLModelException(
                "Cannot get the hash from an unsigned Transaction.")
        prefix = hex(_TRANSACTION_HASH_PREFIX)[2:].upper()
        encoded_str = bytes.fromhex(prefix + encode(self.to_xrpl()))
        return sha512(encoded_str).digest().hex().upper()[:64]
Exemple #10
0
    def from_dict(cls: Type[XRP], value: Dict[str, Any]) -> XRP:
        """
        Construct a new XRP from a dictionary of parameters.

        Args:
            value: The value to construct the XRP from.

        Returns:
            A new XRP object, constructed using the given parameters.

        Raises:
            XRPLModelException: If the dictionary provided is invalid.
        """
        if len(value
               ) != 1 or "currency" not in value or value["currency"] != "XRP":
            raise XRPLModelException("Not a valid XRP type")
        return XRP()
Exemple #11
0
    def get_method(cls: Type[Request], method: str) -> Type[Request]:
        """
        Returns the correct request method based on the string name.

        Args:
            method: The String name of the Request object.

        Returns:
            The request class with the given name.

        Raises:
            XRPLModelException: If `method` is not a valid Request method.
        """
        import xrpl.models.requests as request_models

        request_methods: Dict[str, Type[Request]] = {}
        for r in RequestMethod:
            method_name = _method_to_class_name(r.name)
            request_methods[r.value] = getattr(request_models, method_name)

        if method in request_methods:
            return request_methods[method]

        raise XRPLModelException(f"{method} is not a valid Request method")
Exemple #12
0
    def get_transaction_type(cls: Type[Transaction],
                             transaction_type: str) -> Type[Transaction]:
        """
        Returns the correct transaction type based on the string name.

        Args:
            transaction_type: The String name of the Transaction object.

        Returns:
            The transaction class with the given name.

        Raises:
            XRPLModelException: If `transaction_type` is not a valid Transaction type.
        """
        if transaction_type == TransactionType.ACCOUNT_DELETE:
            from xrpl.models.transactions import AccountDelete

            return AccountDelete
        if transaction_type == TransactionType.ACCOUNT_SET:
            from xrpl.models.transactions import AccountSet

            return AccountSet
        if transaction_type == TransactionType.CHECK_CANCEL:
            from xrpl.models.transactions import CheckCancel

            return CheckCancel
        if transaction_type == TransactionType.CHECK_CASH:
            from xrpl.models.transactions import CheckCash

            return CheckCash
        if transaction_type == TransactionType.CHECK_CREATE:
            from xrpl.models.transactions import CheckCreate

            return CheckCreate
        if transaction_type == TransactionType.DEPOSIT_PREAUTH:
            from xrpl.models.transactions import DepositPreauth

            return DepositPreauth
        if transaction_type == TransactionType.ESCROW_CANCEL:
            from xrpl.models.transactions import EscrowCancel

            return EscrowCancel
        if transaction_type == TransactionType.ESCROW_CREATE:
            from xrpl.models.transactions import EscrowCreate

            return EscrowCreate
        if transaction_type == TransactionType.ESCROW_FINISH:
            from xrpl.models.transactions import EscrowFinish

            return EscrowFinish
        if transaction_type == TransactionType.OFFER_CANCEL:
            from xrpl.models.transactions import OfferCancel

            return OfferCancel
        if transaction_type == TransactionType.OFFER_CREATE:
            from xrpl.models.transactions import OfferCreate

            return OfferCreate
        if transaction_type == TransactionType.PAYMENT:
            from xrpl.models.transactions import Payment

            return Payment
        if transaction_type == TransactionType.PAYMENT_CHANNEL_CLAIM:
            from xrpl.models.transactions import PaymentChannelClaim

            return PaymentChannelClaim
        if transaction_type == TransactionType.PAYMENT_CHANNEL_CREATE:
            from xrpl.models.transactions import PaymentChannelCreate

            return PaymentChannelCreate
        if transaction_type == TransactionType.PAYMENT_CHANNEL_FUND:
            from xrpl.models.transactions import PaymentChannelFund

            return PaymentChannelFund
        if transaction_type == TransactionType.SET_REGULAR_KEY:
            from xrpl.models.transactions import SetRegularKey

            return SetRegularKey
        if transaction_type == TransactionType.SIGNER_LIST_SET:
            from xrpl.models.transactions import SignerListSet

            return SignerListSet
        if transaction_type == TransactionType.TRUST_SET:
            from xrpl.models.transactions import TrustSet

            return TrustSet

        raise XRPLModelException(
            f"{transaction_type} is not a valid Transaction type")
Exemple #13
0
    def _from_dict_single_param(
        cls: Type[BaseModel],
        param: str,
        param_type: Type[Any],
        param_value: Union[int, str, bool, BaseModel, Enum, List[Any],
                           Dict[str, Any]],
    ) -> Any:
        """Recursively handles each individual param in `from_dict`."""
        param_type_origin = get_origin(param_type)
        # returns `list` if a List, `Union` if a Union, None otherwise

        if param_type_origin is list and isinstance(param_value, list):
            # expected a List, received a List
            list_type = get_args(param_type)[0]
            return [
                cls._from_dict_single_param(param, list_type, item)
                for item in param_value
            ]

        if param_type_origin is Union:
            for param_type_option in get_args(param_type):
                # iterate through the types Union-ed together
                try:
                    # try to use this Union-ed type to process param_value
                    return cls._from_dict_single_param(param,
                                                       param_type_option,
                                                       param_value)
                except XRPLModelException:
                    # this Union-ed type did not work, move onto the next one
                    pass

        # no more collections (no params expect a Dict)

        if param_type is Any:
            # param_type is Any (e.g. will accept anything)
            return param_value

        if isinstance(param_type, type) and isinstance(param_value,
                                                       param_type):
            # expected an object, received the correct object
            return param_value

        if (isinstance(param_type, type) and issubclass(param_type, Enum)
                and param_value in list(param_type)):
            # expected an Enum and received a valid value for it.
            # for some reason required for string enums.
            return param_value

        if (isinstance(param_type, type) and issubclass(param_type, BaseModel)
                and isinstance(param_value, dict)):
            # expected an XRPL Model, received a Dict
            return cast(BaseModel, param_type).from_dict(param_value)

        # received something we didn't expect, raise an error
        if isinstance(param_type, type) and issubclass(param_type, BaseModel):
            error_message = (
                f"{param} expected a {param_type} or a Dict representing {param_type}, "
                f"received a {type(param_value)}")
        else:
            error_message = (
                f"{param} expected a {param_type}, received a {type(param_value)}"
            )
        raise XRPLModelException(error_message)