Beispiel #1
0
class StdTx(JsonSerializable, JsonDeserializable):

    __schema__ = S.OBJECT(
        type=S.STRING_WITH_PATTERN(r"^core/StdTx\Z"),
        value=S.OBJECT(
            fee=StdFee.__schema__,
            msg=S.ARRAY(S.ANY(*(mt.__schema__ for mt in MSG_TYPES.values()))),
            signatures=S.ARRAY(StdSignature.__schema__),
            memo=S.STRING,
        ),
    )

    # NOTE: msg is not plural, and is NOT a typo. This may change later for consistency.
    fee: Optional[StdFee] = None
    msg: List[StdMsg] = field(default_factory=list)
    signatures: List[StdSignature] = field(default_factory=list)
    memo: str = ""

    def to_data(self) -> dict:
        return {
            "type": "core/StdTx",
            "value": dict(self.__dict__),
        }

    @classmethod
    def from_data(cls, data: dict) -> StdTx:
        data = data["value"]
        fee = StdFee.from_data(data["fee"])
        # deserialize the messages
        msg = []
        for m in data["msg"]:
            msg_type = MSG_TYPES[m["type"]]
            msg.append(msg_type.from_data(m))
        signatures = [StdSignature.from_data(s) for s in data["signatures"]]
        return cls(fee=fee, msg=msg, signatures=signatures, memo=data["memo"])
Beispiel #2
0
class MsgSubmitProposal(StdMsg):

    type = "gov/MsgSubmitProposal"
    action = "submit_proposal"

    __schema__ = S.OBJECT(
        type=S.STRING_WITH_PATTERN(r"^gov/MsgSubmitProposal\Z"),
        value=S.OBJECT(
            content=S.ANY(*(pt.__schema__ for pt in PROPOSAL_TYPES.values())),
            initial_deposit=Coins.__schema__,
            proposer=S.ACC_ADDRESS,
        ),
    )

    content: Type[Content]
    initial_deposit: Coins
    proposer: AccAddress

    def __post_init__(self):
        self.proposer = validate_acc_address(self.proposer)
        self.initial_deposit = Coins(self.initial_deposit)

    @classmethod
    def from_data(cls, data: dict) -> MsgSubmitProposal:
        data = data["value"]
        p_type = PROPOSAL_TYPES[data["content"]["type"]]
        content = p_type.from_data(data["content"])
        return cls(
            content=content,
            initial_deposit=Coins.from_data(data["initial_deposit"]),
            proposer=data["proposer"],
        )
Beispiel #3
0
class PublicKey(JsonSerializable, JsonDeserializable):

    __schema__ = S.OBJECT(
        type=S.STRING,
        value=S.ANY(
            S.STRING,
            S.OBJECT(
                threshold=S.STRING_INTEGER,
                pubkeys=S.ARRAY(S.OBJECT(type=S.STRING, value=S.STRING)),
            ),
        ),
    )

    type: str = "tendermint/PubKeySecp256k1"
    value: Any = None

    @classmethod
    def from_data(cls, data: dict) -> PublicKey:
        # TODO: apply None-coalescing feature to root JsonDeserializable
        # viz: JsonDeserializable
        if data is None:
            return None
        return cls(type=data["type"], value=data["value"])
Beispiel #4
0
class Coin(JsonSerializable, JsonDeserializable, Generic[T]):

    __schema__ = S.OBJECT(denom=S.STRING,
                          amount=S.ANY(S.STRING_INTEGER, Dec.__schema__))

    denom: str
    amount: T  # all get converted to int or Dec

    def __post_init__(self):
        s = self
        if (isinstance(s.amount, Dec) or isinstance(s.amount, Decimal)
                or isinstance(s.amount, float)
                or (isinstance(s.amount, str) and "." in str(s.amount)
                    or "E" in str(s.amount))):
            object.__setattr__(s, "amount", Dec(
                s.amount))  # must do this due to immutability
        else:
            try:
                object.__setattr__(s, "amount", int(s.amount))
            except ValueError:
                raise ValueError(
                    f"unacceptable value for Coin amount: {s.amount}")

    def __repr__(self) -> str:
        return f"Coin('{self.denom}', {self.amount!r})"

    @property
    def int_coin(self) -> Coin[int]:
        return Coin(self.denom, int(self.amount))

    @property
    def dec_coin(self) -> Coin[Dec]:
        return Coin(self.denom, Dec(self.amount))

    def __str__(self) -> str:
        return f"{self.amount}{self.denom}"

    @classmethod
    def from_str(cls, string: str) -> Coin:
        pattern = r"^(\-?[0-9]+(\.[0-9]+)?)([a-zA-Z]+)$"
        match = re.match(pattern, string)
        if match:
            return cls(match.group(3), match.group(1))
        else:
            raise ValueError(f"{string} could not be parsed into Coin")

    def __eq__(self, other: object) -> bool:
        if isinstance(other, Coin):
            return self.denom == other.denom and self.amount == other.amount
        else:
            return False

    def __add__(self, other) -> Union[Coin, Coins]:
        if other == 0:
            return Coin(self.denom, self.amount)
        if isinstance(other, Coins):
            return other + self
        if not isinstance(other, Coin):
            raise TypeError(
                f"unsupported operand types for +: 'Coin' and '{type(other)}'")
        if self.denom != other.denom:
            raise DenomIncompatibleError(
                f"unsupported Coin denoms for +: '{self.denom}' and '{other.denom}'"
            )
        cast = int
        if isinstance(self.amount, Dec) or isinstance(other.amount, Dec):
            cast = Dec
        return Coin(denom=self.denom, amount=cast(self.amount + other.amount))

    def __radd__(self, other) -> Union[Coin, Coins]:
        return self + other

    def __sub__(self, other: Coin) -> Coin[Union[int, Dec]]:
        if not isinstance(other, Coin):
            raise TypeError(
                f"unsupported operand types for -: 'Coin' and '{type(other)}'")
        if self.denom != other.denom:
            raise DenomIncompatibleError(
                f"unsupported Coin denoms for -: '{self.denom}' and '{other.denom}'"
            )
        cast = int
        if isinstance(self.amount, Dec) or isinstance(other.amount, Dec):
            cast = Dec
        return Coin(denom=self.denom, amount=cast(self.amount - other.amount))

    def __mul__(self, other) -> Coin[T]:
        return Coin(denom=self.denom, amount=(self.amount * other))

    def __rmul__(self, other) -> Coin[T]:
        return self * other

    def __truediv__(self, other) -> Coin[T]:
        cast = type(self.amount)
        return Coin(denom=self.denom, amount=cast(self.amount / other))

    def __floordiv__(self, other) -> Coin[T]:
        cast = type(self.amount)
        return Coin(denom=self.denom, amount=cast(self.amount // other))

    def __neg__(self) -> Coin[T]:
        return Coin(denom=self.denom, amount=(-self.amount))

    def __abs__(self) -> Coin[T]:
        return Coin(denom=self.denom, amount=abs(self.amount))

    def __pos__(self) -> Coin[T]:
        return abs(self)

    def __lt__(self, other: Coin) -> bool:
        if self.denom != other.denom:
            raise DenomIncompatibleError(
                f"incompatible Coin denoms for <: '{self.denom}' and '{other.denom}'"
            )
        return self.amount < other.amount

    def __gt__(self, other: Coin) -> bool:
        if self.denom != other.denom:
            raise DenomIncompatibleError(
                f"incompatible Coin denoms for >: '{self.denom}' and '{other.denom}'"
            )
        return self.amount > other.amount

    def __ge__(self, other: Coin) -> bool:
        return self > other or self == other

    def __le__(self, other: Coin) -> bool:
        return self < other or self == other

    def to_data(self) -> dict:
        return {"denom": str(self.denom), "amount": str(self.amount)}

    def _pretty_repr_(self, path="") -> str:
        return str(self)

    @classmethod
    def from_data(cls, data: Dict[str, str]) -> Coin:
        return cls(denom=data["denom"], amount=data["amount"])