Module multisig_view

Expand source code
import smartpy as sp


class MultisigView(sp.Contract):
    """Multiple members vote for arbitrary bytes.

    This contract can be originated with a list of addresses and a number of
    required votes. Any member can submit as many bytes as they want and vote
    for active proposals.

    Any bytes that reached the required votes can be confirmed via a view.
    """

    def __init__(self, members, required_votes):
        """Constructor

        Args:
            members (sp.TSet(sp.TAddress)): people who can submit and vote for
                lambda.
            required_votes (sp.TNat): number of votes required
        """
        assert required_votes <= len(members), "required_votes must be <= len(members)"
        self.init(
            proposals=sp.big_map(tkey=sp.TBytes, tvalue=sp.TBool),
            votes=sp.big_map(tkey=sp.TBytes, tvalue=sp.TSet(sp.TAddress)),
            members=sp.set(members, t=sp.TAddress),
            required_votes=required_votes,
        )

    @sp.entrypoint(new_syntax = True)
    def submit_proposal(self, bytes):
        """Submit a new proposal to the vote.

        Submitting a proposal does not imply casting a vote in favour of it.

        Args:
            bytes(sp.TBytes): bytes proposed to vote.
        Raises:
            `You are not a member`
        """
        assert self.data.members.contains(sp.sender), "You are not a member"
        self.data.proposals[bytes] = False
        self.data.votes[bytes] = sp.set()

    @sp.entrypoint(new_syntax = True)
    def vote_proposal(self, bytes):
        """Vote for a proposal.

        There is no vote against or pass. If one disagrees with a proposal they
        can avoid to vote. Warning: old non-voted proposals never become
        obsolete.

        Args:
            id(sp.TBytes): bytes of the proposal.
        Raises:
            `You are not a member`, `Proposal not found`
        """
        assert self.data.members.contains(sp.sender), "You are not a member"
        assert self.data.proposals.contains(bytes), "Proposal not found"
        self.data.votes[bytes].add(sp.sender)
        if sp.len(self.data.votes[bytes]) >= self.data.required_votes:
            self.data.proposals[bytes] = True

    @sp.onchain_view()
    def is_voted(self, id):
        """Returns a boolean indicated if the proposal has been voted.

        Args:
            id (sp.TBytes): bytes of the proposal
        Return:
            (sp.TBool): True if the proposal has been voted, False otherwise.
        """
        sp.result(self.data.proposals.get(id, message="Proposal not found"))


if "templates" not in __name__:

    @sp.add_test(name="MultisigView basic scenario", is_default=True)
    def basic_scenario():
        """A scenario with a vote on the multisigView contract.

        Tests:
        - Origination
        - Proposal submission
        - Proposal vote
        """
        sc = sp.test_scenario()
        sc.h1("Basic scenario.")

        member1 = sp.test_account("member1")
        member2 = sp.test_account("member2")
        member3 = sp.test_account("member3")
        members = [member1.address, member2.address, member3.address]

        sc.h2("Origination")
        c1 = MultisigView(members, required_votes=2)
        sc += c1

        sc.h2("submit_proposal")
        c1.submit_proposal(sp.bytes("0x42")).run(sender=member1)

        sc.h2("vote_proposal")
        c1.vote_proposal(sp.bytes("0x42")).run(member1)
        c1.vote_proposal(sp.bytes("0x42")).run(member2)

        # We can check that the proposal has been validated.
        sc.verify(c1.is_voted(sp.bytes("0x42")))

Classes

class MultisigView (members, required_votes)

Multiple members vote for arbitrary bytes.

This contract can be originated with a list of addresses and a number of required votes. Any member can submit as many bytes as they want and vote for active proposals.

Any bytes that reached the required votes can be confirmed via a view.

Constructor

Args

members (sp.TSet(sp.TAddress)): people who can submit and vote for
lambda.
required_votes : sp.TNat
number of votes required
Expand source code
class MultisigView(sp.Contract):
    """Multiple members vote for arbitrary bytes.

    This contract can be originated with a list of addresses and a number of
    required votes. Any member can submit as many bytes as they want and vote
    for active proposals.

    Any bytes that reached the required votes can be confirmed via a view.
    """

    def __init__(self, members, required_votes):
        """Constructor

        Args:
            members (sp.TSet(sp.TAddress)): people who can submit and vote for
                lambda.
            required_votes (sp.TNat): number of votes required
        """
        assert required_votes <= len(members), "required_votes must be <= len(members)"
        self.init(
            proposals=sp.big_map(tkey=sp.TBytes, tvalue=sp.TBool),
            votes=sp.big_map(tkey=sp.TBytes, tvalue=sp.TSet(sp.TAddress)),
            members=sp.set(members, t=sp.TAddress),
            required_votes=required_votes,
        )

    @sp.entrypoint(new_syntax = True)
    def submit_proposal(self, bytes):
        """Submit a new proposal to the vote.

        Submitting a proposal does not imply casting a vote in favour of it.

        Args:
            bytes(sp.TBytes): bytes proposed to vote.
        Raises:
            `You are not a member`
        """
        assert self.data.members.contains(sp.sender), "You are not a member"
        self.data.proposals[bytes] = False
        self.data.votes[bytes] = sp.set()

    @sp.entrypoint(new_syntax = True)
    def vote_proposal(self, bytes):
        """Vote for a proposal.

        There is no vote against or pass. If one disagrees with a proposal they
        can avoid to vote. Warning: old non-voted proposals never become
        obsolete.

        Args:
            id(sp.TBytes): bytes of the proposal.
        Raises:
            `You are not a member`, `Proposal not found`
        """
        assert self.data.members.contains(sp.sender), "You are not a member"
        assert self.data.proposals.contains(bytes), "Proposal not found"
        self.data.votes[bytes].add(sp.sender)
        if sp.len(self.data.votes[bytes]) >= self.data.required_votes:
            self.data.proposals[bytes] = True

    @sp.onchain_view()
    def is_voted(self, id):
        """Returns a boolean indicated if the proposal has been voted.

        Args:
            id (sp.TBytes): bytes of the proposal
        Return:
            (sp.TBool): True if the proposal has been voted, False otherwise.
        """
        sp.result(self.data.proposals.get(id, message="Proposal not found"))

Ancestors

  • smartpy.Contract

Methods

def submit_proposal(self, bytes)

Entrypoint. Submit a new proposal to the vote.

Submitting a proposal does not imply casting a vote in favour of it.

Args

bytes(sp.TBytes): bytes proposed to vote.

Raises

You are not a member

Expand source code
@sp.entrypoint(new_syntax = True)
def submit_proposal(self, bytes):
    """Submit a new proposal to the vote.

    Submitting a proposal does not imply casting a vote in favour of it.

    Args:
        bytes(sp.TBytes): bytes proposed to vote.
    Raises:
        `You are not a member`
    """
    assert self.data.members.contains(sp.sender), "You are not a member"
    self.data.proposals[bytes] = False
    self.data.votes[bytes] = sp.set()
def vote_proposal(self, bytes)

Entrypoint. Vote for a proposal.

There is no vote against or pass. If one disagrees with a proposal they can avoid to vote. Warning: old non-voted proposals never become obsolete.

Args

id(sp.TBytes): bytes of the proposal.

Raises

You are not a member, Proposal not found

Expand source code
@sp.entrypoint(new_syntax = True)
def vote_proposal(self, bytes):
    """Vote for a proposal.

    There is no vote against or pass. If one disagrees with a proposal they
    can avoid to vote. Warning: old non-voted proposals never become
    obsolete.

    Args:
        id(sp.TBytes): bytes of the proposal.
    Raises:
        `You are not a member`, `Proposal not found`
    """
    assert self.data.members.contains(sp.sender), "You are not a member"
    assert self.data.proposals.contains(bytes), "Proposal not found"
    self.data.votes[bytes].add(sp.sender)
    if sp.len(self.data.votes[bytes]) >= self.data.required_votes:
        self.data.proposals[bytes] = True
def is_voted(self, id)

Onchain view. Returns a boolean indicated if the proposal has been voted.

Args

id : sp.TBytes
bytes of the proposal

Return

(sp.TBool): True if the proposal has been voted, False otherwise.

Expand source code
@sp.onchain_view()
def is_voted(self, id):
    """Returns a boolean indicated if the proposal has been voted.

    Args:
        id (sp.TBytes): bytes of the proposal
    Return:
        (sp.TBool): True if the proposal has been voted, False otherwise.
    """
    sp.result(self.data.proposals.get(id, message="Proposal not found"))