Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed Multisig ADO Submission #4

Open
daniel-wehbe opened this issue Feb 5, 2024 · 0 comments
Open

Fixed Multisig ADO Submission #4

daniel-wehbe opened this issue Feb 5, 2024 · 0 comments
Labels
ADO Submission Submission of an ADO

Comments

@daniel-wehbe
Copy link
Contributor

daniel-wehbe commented Feb 5, 2024

Welcome to the ADO Submission Template. We will be walking through an example of an ADO and the required information to be able to submit for inclusion within the Andromeda Operating System (aOS).

Contact Information

Contract Summary(Details of the contract and specific functionality to be included)
The Fixed Multisig ADO is designed to allow the execution of some action/actions (CosmosMsg) on another smart contract or wallet by the process of voting. The overall purpose of the ADO is to handle multi-ownership scenarios, whether on a wallet or another smart contract.
A fixed set of addresses are specified that are allowed to vote. For each Address a specific weight can be assigned. Proposals can be started by any of the voters to execute some action. The owner of the ADO sets a threshold to be met for a proposal to pass. Once passed the action can now be executed by anyone.

Example: 3 people have equal (same weight) ownership on a wallet. To remove the risk of having one of them suddenly take the funds out of the wallet, they can use a this multisig ADO to oversee it. In that case, they can agree that 2/3 votes are needed to move any of the funds meaning the majority is agreeing on the fund transfer.

External Reference Links(Link to something that might provide additional information about this ADO and its use cases if applicable)
An article that explains the idea of a multisig smart contract

Contract Flow Breakdown(Step by step explanation of how the ADO from start to finish. Workflow diagram is encouraged)

  1. We store the addresses allowed to vote along with their weights, a threshold that needs to be exceeded for a proposal to be considered "passing", and a maximum voting period that can be set for a proposal. All of this is specified when instantiating the contract and stored within the ADO.
  2. An address from the voter set makes a proposal by calling the Propose execute message(more details on that in the messages section) . Each proposal is assigned an Id as multiple proposals can be ongoing at the same time.
  3. Once the proposal is up, the voter set can now start voting. The address that started the proposal will have their vote automatically cast as a "yes". Other voters can either vote "yes", "no", or "abstain" meaning they have voted but will not effect the results.
  4. Each time a new voter casts their vote, the "yes" votes are compared with the threshold. If the votes reach the threshold, the state of the proposal is changed to "passed" and the messages can be executed immediately. In case, any of the messages errors (due to gas or funds ect...) the state of the proposal will remain passed and the user can try executing the messages again.
  5. When the time alloted for voting passes, voters can no longer vote. If the proposal has passed, the messages can be executed even after the proposal time has expired.
  6. In case the proposal did not pass and the time limit for it has passed, anyone can call a close message to close the proposal and remove it from the ADOs storage.

Under what category would you include the ADO(non-fungible-tokens, finance, ecosystem etc..)
Ecosystem

Messages

Instantiation (What is specified and stored at instantiation)

pub struct InstantiateMsg {
    pub voters: Vec<Voter>,
    pub threshold: Threshold,
    pub max_voting_period: Duration,
    pub kernel_address: String,
    pub owner: Option<String>,
}

voters: A vector of the struct Voter. Defines set of addresses allowed to vote. Each address has a weight for their vote. A weight of 0 can be set for a voter allowing them to start proposals without having any voting power.

#[cw_serde]
pub struct Voter {
    pub addr: String,
    pub weight: u64,
}

addr: The address of the voter.
weight: The weight of the voter

Theshold: The threshold needed for a proposal to pass. There are three types of thresholds to choose from.

pub enum Threshold {
    /// Declares that a fixed weight of Yes votes is needed to pass.
    /// See `ThresholdResponse.AbsoluteCount` in the cw3 spec for details.
    AbsoluteCount { weight: u64 },

    /// Declares a percentage of the total weight that must cast Yes votes in order for
    /// a proposal to pass.
    /// See `ThresholdResponse.AbsolutePercentage` in the cw3 spec for details.
    AbsolutePercentage { percentage: Decimal },

    /// Declares a `quorum` of the total votes that must participate in the election in order
    /// for the vote to be considered at all.
    /// See `ThresholdResponse.ThresholdQuorum` in the cw3 spec for details.
    ThresholdQuorum { threshold: Decimal, quorum: Decimal },
}

max_voting_period: Specifies a Duration which indicates maximum duration a proposal can be up for. The max duration can be either a block height, or a time specified in seconds.

pub enum Duration {
    Height(u64),
    /// Time in seconds
    Time(u64),
}

Execute Messages (What are the messages that can be executed, what do they do, and who can call each message)

  1. Propose: Message to start a proposal. Only addresses that were specified as voters are allowed to start a proposal. Multiple proposals can be running at the same time. When a proposal is made, it is assigned an Id which starts 1 and increments for each new proposal.
  Propose {
        title: String,
        description: String,
        msgs: Vec<CosmosMsg<Empty>>,
        latest: Option<Expiration>,
    }

title: The title for the proposal.
description: A description on what is being proposed.
msgs: A vector of CosmosMsg containing all the messages to be executed in case the proposal passes.
latest: Optional expiration for the proposal. If not specified, the max_voting_period specified at instantiation is used.

  1. Vote: Casts a vote on the specified proposal. Only available to the voter set.
 Vote {
        proposal_id: u64,
        vote: Vote,
    }

proposal_id: The Id of the proposal to vote on.
vote: The vote to cast on the proposal.


pub enum Vote {
    /// Marks support for the proposal.
    Yes,
    /// Marks opposition to the proposal.
    No,
    /// Marks participation but does not count towards the ratio of support / opposed
    Abstain,
    /// Veto is generally to be treated as a No vote. Some implementations may allow certain
    /// voters to be able to Veto, or them to be counted stronger than No in some way.
    Veto,
}
  1. Execute: Executes the messages of the proposal that has passed. Executable by any address.
Execute {
        proposal_id: u64,
    },

proposal_id: The Id of the proposal to execute the messages for.

  1. Close: Closes a proposal in case it has expired and did not pass.
Close {
        proposal_id: u64,
    },

proposal_id: The Id of the proposal to close.

Query Messages (What are the messages that can be queried, what does each return)

  1. Threshold: Returns the set threshold for proposal to be considered passing.
Threshold {},
  1. Proposal: Returns the proposal information for the specified proposal Id.
Proposal { proposal_id: u64 },

proposal_id: The Id of the proposal to get the information for.

  1. ListProposals: Returns the proposal information for multiple proposals at a time. Uses pagination to specify which proposals to list.
ListProposals {
        start_after: Option<u64>,
        limit: Option<u32>,
    }

start_after: Optional proposal Id to start after. If 3 is specified for example, then proposal with Ids greater than 3 will be fetched.
limit: Optional limit to the number of proposals to fetch information for. Defaults to 10 and can be set to a maximum of 30.

  1. ReverseProposals: Returns the proposal information for multiple proposals at a time. Uses pagination to specify which proposals to list. Similar to ListProposals, but fetches the proposals before a specified Id instead of after.
ReverseProposals {
       start_before: Option<u64>,
       limit: Option<u32>,
   },

start_before: Optional proposal Id to start before. If 3 is specified for example, then proposal with Ids less than 3 will be fetched.
limit: Optional limit to the number of proposals to fetch information for. Defaults to 10 and can be set to a maximum of 30.

  1. Vote: Returns the vote of the specified address for the specified proposal.
Vote { proposal_id: u64, voter: String },

proposal_id: The Id of the proposal to get the vote for.
voter: The address of the voter to get the vote for.

  1. ListVotes: Returns the voting information for the specified proposal for multiple voters at a time. Uses pagination to specify which votes to list.
 ListVotes {
        proposal_id: u64,
        start_after: Option<String>,
        limit: Option<u32>,
    }

proposal_id: The Id of the proposal to get voting information for.
start_after: Optional address to start after.
limit: Optional limit to the number of Votes to fetch. Defaults to 10 and can be set to a maximum of 30.

  1. Voter: Returns the weight of the specified voter.
 Voter { address: String },

address: The address of the voter to get the weight for.

  1. ListVoters: Returns the address and weight of the voters for the ADO. Can be used with pagination.
ListVoters {
        start_after: Option<String>,
        limit: Option<u32>,
    },

start_after: Optional address to start after.
limit:Optional limit to specify the number of Voters returned. Defaults to 10 and can be set to a maximum of 30.


Possible Next Iterations/Future Work
Another version of this ADO can also be considered being a flexible-multisig where multiple weights/thresholds can be assigned.

Possible Concers/Risks (Security,speed,safety,logic)
-Addresses should not be allowed to change their vote in order to stop people from changing last second.
-Having a way to simulate the msgs in a proposal before submitting it would prevent msgs that will result with an error. Having a message that will error would nullify the proposal and a new one must be made with correct messages instead.

Other ADO’s to Pair With (Does this ADO work with another existing ADO? If so, which and how? Does it need to be part of an App?)
This ADO can work with any ADO and execute messages on that ADO, given the proper permissioning rights from the ADO. There is not specific ADO it has to work with. Can also work with wallets. It is not necessary to have it be part of an App although it might make more sense depending on the use case.

Credits/Associations(Is this ADO inspired by another from the ecosystem? Was it prepared with another partnering group or developers?)

This ADO is based on the CW3-fixed-multisig contract from the cw-plus repo.

Dependencies

Cargo Dependencies Used

The dependencies are listed in the Cargo.toml file under the dependencies section.

Third Party Dependencies(Does this ADO require any third party integrations such as oracles,protocols,specific wallet, or anything off chain)
No third party integrations needed.

Compatibility(To which chains is the ADO compatable. List the included and excluded chains. Does it require a specific sdk module? If so specify.)
Compatible with all chains.


Additional Sections/Material Needed

Make sure you have the following in your PR:

  1. Clear and neat ReadMe file that includes a summary of the ADO and documentation on how to use it
  2. ADO should contain unit tests. Testing should cover both positive and negative testing with 90% coverage. Any additional testing (on-chain or other) is also encouraged but not required.
  3. ADO should contain an updated schema file (Schema generation crate)

Usage Guide

Provide a full exmample of the ADO usage. Include the messages called and the JSON used to call these messages.

Example: We have 3 users that want to operate a wallet with shared ownership. They will use this ADO to do so. A proposal should pass in case 2 out of the 3 users vote with a "yes". The max duration for a proposal can be set to 10 days.

Instantiating the ADO:

{"voters":[{"addr":"andr1f9q5dhg5q434jyjes002fvkcuk062tnt0wdzl8","weight":1},{"addr":"andr1cp9vxvplgjf508thtacvxeh6qxqsx67gseqcd5","weight":1},{"addr":"andr1e9qgel058tvgryvsu8uhta0u4sswajre3cjhav","weight":1}],"threshold":{"absolute_count":{"weight":2}},"max_voting_period":{"time":864000},"kernel_address":"andr12h2acqz3r92e8dg9t3p3r76lueqymuzjga0f3crv7l2f6k9qwjvs65lut0"}

One day, one of the voters wants to propose sending 10000uandr to some other address (The tokens would be in the ADOs balance). To do so, he has to start a proposal:

{"propose":{"title":"Sending 10000uandr","description":"Proposing sending 10000 uandr to address andr10ys63nrmxd04lktg6kwmkj9dsl9ytcw6vdfgyc which is the address of john. These funds are for the work he has done for us in the past month","msgs":[{"bank":{"send":{"to_address":"andr10ys63nrmxd04lktg6kwmkj9dsl9ytcw6vdfgyc","amount":[{"denom":"uandr","amount":"10000"}]}}}]}}

Now that the proposal is up, a voter can call the Vote execute message. Here the Id is 1 as this is the first proposal of the ADO:

{"vote":{"proposal_id": 1,"vote":"yes"}}

If 2 out of the 3 voters vote a "yes" before the end of the proposal duration, then we can now execute the message to send the funds by calling the Execute message.

{"execute":{"proposal_id":1}}
@daniel-wehbe daniel-wehbe added the ADO Submission Submission of an ADO label Feb 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ADO Submission Submission of an ADO
Projects
None yet
Development

No branches or pull requests

1 participant