Source code for terra_sdk.core.gov.data

"""Gov module data types."""

from __future__ import annotations

import copy
from datetime import datetime
from typing import List, Union

import attr
from dateutil import parser
from terra_proto.cosmos.gov.v1beta1 import Proposal as Proposal_pb
from terra_proto.cosmos.gov.v1beta1 import TallyResult as TallyResult_pb
from terra_proto.cosmos.gov.v1beta1 import Vote as Vote_pb
from terra_proto.cosmos.gov.v1beta1 import VoteOption
from terra_proto.cosmos.gov.v1beta1 import WeightedVoteOption as WeightedVoteOption_pb

from terra_sdk.core import AccAddress, Coins
from terra_sdk.core.distribution import CommunityPoolSpendProposal
from terra_sdk.core.params import ParameterChangeProposal
from terra_sdk.core.upgrade import (
    CancelSoftwareUpgradeProposal,
    SoftwareUpgradeProposal,
)
from terra_sdk.util.json import JSONSerializable, dict_to_data

from .proposals import TextProposal

__all__ = ["Proposal", "Content", "VoteOption", "WeightedVoteOption"]

from ...util.converter import to_isoformat

Content = Union[
    TextProposal,
    CommunityPoolSpendProposal,
    ParameterChangeProposal,
    SoftwareUpgradeProposal,
    CancelSoftwareUpgradeProposal,
]


def Content_from_data(data: dict) -> Content:
    typ = data["@type"]
    if typ == TextProposal.type_url:
        return TextProposal.from_data(data)
    elif typ == CommunityPoolSpendProposal.type_url:
        return CommunityPoolSpendProposal.from_data(data)
    elif typ == ParameterChangeProposal.type_url:
        return ParameterChangeProposal.from_data(data)
    elif typ == SoftwareUpgradeProposal.type_url:
        return SoftwareUpgradeProposal.from_data(data)
    elif typ == CancelSoftwareUpgradeProposal.type_url:
        return CancelSoftwareUpgradeProposal.from_data(data)
    else:
        raise ValueError("content type is invalid")


@attr.s
class TallyResult(JSONSerializable):
    yes: str = attr.ib()
    abstain: str = attr.ib()
    no: str = attr.ib()
    no_with_veto: str = attr.ib()

    def to_amino(self) -> dict:
        return {
            "yes": self.yes,
            "abstain": self.abstain,
            "no": self.no,
            "no_with_veto": self.no_with_veto,
        }

    @classmethod
    def from_data(cls, data: dict) -> TallyResult:
        return cls(
            yes=data["yes"],
            abstain=data["abstain"],
            no=data["no"],
            no_with_veto=data["no_with_veto"],
        )

    def to_proto(self) -> TallyResult_pb:
        return TallyResult_pb(
            yes=self.yes,
            abstain=self.abstain,
            no=self.no,
            no_with_veto=self.no_with_veto,
        )


[docs]@attr.s class Proposal(JSONSerializable): """Contains information about a submitted proposal on the blockchain.""" proposal_id: int = attr.ib(converter=int) """Proposal's ID.""" content: Content = attr.ib() """Proposal contents.""" status: str = attr.ib() """Status of proposal.""" final_tally_result: TallyResult = attr.ib() """Final tallied result of the proposal (after vote).""" submit_time: datetime = attr.ib(converter=parser.parse) """Timestamp at which proposal was submitted.""" deposit_end_time: datetime = attr.ib(converter=parser.parse) """Time at which the deposit period ended, or will end.""" total_deposit: Coins = attr.ib(converter=Coins) """Total amount deposited for proposal""" voting_start_time: datetime = attr.ib(converter=parser.parse) """Time at which voting period started, or will start.""" voting_end_time: datetime = attr.ib(converter=parser.parse) """Time at which voting period ended, or will end."""
[docs] def to_data(self) -> dict: d = copy.deepcopy(self.__dict__) d["id"] = str(d["id"]) return dict_to_data(d)
def to_amino(self) -> dict: return { "proposal_id": str(self.proposal_id), "content": self.content.to_amino(), "status": self.status, "final_tally_result": self.final_tally_result.to_amino(), "submit_time": to_isoformat(self.submit_time), "deposit_end_time": to_isoformat(self.deposit_end_time), "total_deposit": self.total_deposit.to_amino(), "voting_start_time": to_isoformat(self.voting_start_time), "voting_end_time": to_isoformat(self.voting_end_time), } @classmethod def from_data(cls, data: dict) -> Proposal: return cls( proposal_id=data["proposal_id"], content=Content_from_data(data["content"]), status=data["status"], final_tally_result=data["final_tally_result"], submit_time=data["submit_time"], deposit_end_time=data["deposit_end_time"], total_deposit=Coins.from_data(data["total_deposit"]), voting_start_time=data["voting_start_time"], voting_end_time=data["voting_end_time"], ) def to_proto(self) -> Proposal_pb: return Proposal_pb( proposal_id=self.proposal_id, content=self.content.pack_any(), status=self.status, final_tally_result=self.final_tally_result.to_proto(), submit_time=self.submit_time, deposit_end_time=self.deposit_end_time, total_deposit=self.total_deposit.to_proto(), voting_start_time=self.voting_start_time, voting_end_time=self.voting_end_time, )
[docs]@attr.s class WeightedVoteOption(JSONSerializable): weight: str = attr.ib() option: VoteOption = attr.ib(converter=int) def to_amino(self) -> dict: return {"weight": self.weight, "option": self.option.name} @classmethod def from_data(cls, data: dict) -> WeightedVoteOption: return cls(option=data["option"], weight=data["weight"]) def to_proto(self) -> WeightedVoteOption_pb: return WeightedVoteOption_pb(option=self.option, weight=self.weight)
@attr.s class Vote(JSONSerializable): proposal_id: int = attr.ib(converter=int) voter: AccAddress = attr.ib() options: List[WeightedVoteOption] = attr.ib(converter=list) def to_amino(self) -> dict: return { "proposal_id": str(self.proposal_id), "voter": self.voter, "options": [opt.to_amino() for opt in self.options], } @classmethod def from_data(cls, data: dict) -> Vote: return cls( proposal_id=data["proposal_id"], voter=data["voter"], options=data["options"], ) def to_proto(self) -> Vote_pb: return Vote_pb( proposal_id=self.proposal_id, voter=self.voter, options=self.options )