Module multisig_lambda

Expand source code
import smartpy as sp

def main():
    operation_lambda: type = sp.lambda_(sp.unit, sp.unit, with_operations=True)

    class MultisigLambda(sp.Contract):
        """Multiple members vote for executing lambdas.

        This contract can be originated with a list of addresses and a number of
        required votes. Any member can submit as much lambdas as he wants and vote
        for active proposals. When a lambda reaches the required votes, its code is
        called and the output operations are executed. This allows this contract to
        do anything that a contract can do: transferring tokens, managing assets,
        administrating another contract...

        When a lambda is applied, all submitted lambdas until now are inactivated.
        The members can still submit new lambdas.

        def __init__(self, members, required_votes):

                members (sp.set of sp.address): people who can submit and vote
                    for lambda.
                required_votes (sp.nat): number of votes required
            assert required_votes <= sp.len(
            ), "required_votes must be <= len(members)"
   = sp.cast(
                sp.big_map(), sp.big_map[sp.nat, operation_lambda]
   = sp.cast(
                sp.big_map(), sp.big_map[sp.nat, sp.set[sp.address]]
   = 0
   = 0
   = sp.cast(members, sp.set[sp.address])
   = sp.cast(required_votes, sp.nat)

        def submit_lambda(self, lambda_):
            """Submit a new lambda to the vote.

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

                lambda_(sp.lambda with operations): lambda proposed to vote.
                `You are not a member`
            assert, "You are not a member"
  [] = lambda_
  [] = sp.set()
   += 1

        def vote_lambda(self, id):
            """Vote for a lambda.

                id(sp.nat): id of the lambda to vote for.
                `You are not a member`, `The lambda is inactive`, `Lambda not found`

            There is no vote against or pass. If someone disagrees with a lambda
            they can avoid to vote.
            assert, "You are not a member"
            assert id >=, "The lambda is inactive"
            assert, "Lambda not found"
            if sp.len([id]) >=

        def get_lambda(self, id):
            """Return the corresponding lambda.

                id (sp.nat): id of the lambda to get.

                pair of the lambda and a boolean showing if the lambda is active.
            return ([id], id >=

# if "templates" not in __name__:

def test():
    class Administrated(sp.Contract):
        def __init__(self, admin):
   = admin

        def set_value(self, value):
            assert sp.sender ==
   = value

@sp.add_test(name="MultisigLambda basic scenario", is_default=True)
def basic_scenario():
    """Use the multisigLambda as an administrator of an example contract.

    - Origination
    - Lambda submission
    - Lambda vote
    sc = sp.test_scenario([main, test])
    sc.h1("Basic scenario.")

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

    sc.h2("MultisigLambda: origination")
    c1 = main.MultisigLambda(members, 2)
    sc += c1

    sc.h2("Administrated: origination")
    c2 = test.Administrated(c1.address)
    sc += c2

    sc.h2("MultisigLambda: submit_lambda")

    def set_42(params):
        administrated = sp.contract(sp.TInt, c2.address, entrypoint="set_value")
        sp.transfer(, sp.tez(0), administrated.open_some())

    lambda_ = sp.build_lambda(set_42, with_operations=True)

    sc.h2("MultisigLambda: vote_lambda")

    # We can check that the administrated contract received the transfer.
    sc.verify( == 42)