DAO

It allows anyone to create a DAO, submit proposals, and execute actions on-chain.

  • Proposals are voted by depositing coins. 1 Coin is 1 Vote.

  • DAOs only supports 1 Coin type

The idea is to send capabilities to the DAO via sui::transfer::transfer.

  • Users can borrow the capabilities via successful proposals.

  • Developers must write custom modules that pass the AuthorizedWitness to borrow the capability when executing proposals.

  • DAO relies on open-source code to make sure the Modules that are executing proposals do what they agreed to do.

A Successful Proposal requires:

  • for_votes > agaisnt_votes

  • for_votes / total_votes > quorum rate

  • for_votes >= min_quorum_votes

Each Vote struct belongs to a specific Proposal via the vote.proposal_id field.

  • A voter can revoke his vote and recover his sui::coin::Coin if the Proposal is active.

  • A voter can recover his coins once the voting period ends.

  • A Vote created from ProposalA cannot be used in ProposalB.

Proposal States

Pending: Newly created proposal.

Active: Proposal is open for voting.

Defeated: The proposal did not pass.

Agree: The proposal passed.

Queued: The proposal was successful and now it is in a queue to be executed if it is executable. This gives time for people to adjust to the upcoming change.

Executable: It can be executed.

Finished: The proposal has been executed.

Structs

DAO

struct Dao<phantom OTW> has key, store {
    id: UID,
    voting_delay: u64, 
    voting_period: u64,
    voting_quorum_rate: u64,
    min_action_delay: u64, 
    min_quorum_votes: u64,
    treasury: ID,
    coin_type: TypeName,
    admin_id: ID
 }
  • voting_delay - Voters must wait `voting_delay` in milliseconds to start voting on new proposals.

  • voting_period- The voting duration of a proposal.

  • voting_quorum_rate

    • The minimum quorum rate to pass a proposal.

    • If 50% votes are needed, then the voting_quorum_rate should be 5_00_000_000.

    • It should be between (0, 1e9].

  • min_action_delay - How long the proposal should wait before it can be executed (in milliseconds).

  • min_quorum_votes - Minimum amount of votes for a Proposal to be successful even if it is higher than the against votes and the quorum rate.

  • treasury - The `sui::object::ID` of the Treasury.

  • coin_type - The CoinType that can vote on this DAO's proposal.

  • admin_id - The DaoAdmin.

Proposal

  struct Proposal<phantom DaoWitness: drop> has key, store {
    id: UID,
    proposer: address,
    start_time: u64,
    end_time: u64,
    for_votes: u64,
    against_votes: u64,
    eta: u64,  
    action_delay: u64, 
    quorum_votes: u64, 
    voting_quorum_rate: u64, 
    hash: String,
    authorized_witness: Option<TypeName>, 
    capability_id: Option<ID>,
    coin_type: TypeName
  }
  • proposer - The user who created the proposal.

  • start_time - When the users can start voting.

  • end_time - Users can no longer vote after the end_time.

  • for_votes- How many votes support the Proposal.

  • agaisnt_votes- How many votes disagree with the Proposal.

  • eta

    • It is calculated by adding end_time and action_delay. It assumes the Proposal will be executed as soon as possible.

    • Estimated Time of Arrival.

  • action_delay

    • Time Delay between a successful Proposal end_time and when it is allowed to be executed.

    • It allows users who disagree with the proposal to make changes.

  • quorum_votes - The minimum amount of for_votes for a Proposal to pass.

  • voting_quorum_rate - The minimum support rate for a Proposal to pass.

  • hash - The hash of the description of this proposal.

  • authorized_witness

    • The Witness that is allowed to call execute.

    • Not executable proposals do not have an authorized_witness.

  • capability_id

    • The sui::object::ID that this proposal needs to execute.

    • Not all proposals are executable.

  • coin_type - The CoinType of the DAO

Capability Request - Hot Potato

  struct CapabilityRequest {  
    capability_id: ID,
    dao_id: ID
  }
  • capability_id - The sui::object::ID of the borrowed Capability.

  • dao_id: The DAO that owns said Capability.

Vote

  struct Vote<phantom DaoWitness: drop, phantom CoinType> has  key, store {
    id: UID,
    balance: Balance<CoinType>,
    proposal_id: ID,
    end_time: u64,
    agree: bool
  } 
  • balance - The amount of Coin the user has used to vote for the Proposal.

  • proposal_id: The sui::object::ID of the Proposal.

  • end_time:

    • The end_time of the Proposal.

    • User can redeem back his balance after this timestamp.

  • agree - If it is a for or against vote.

Interface

new

It creates a DAO with Treasury.

public fun new<OTW: drop, CoinType: drop>(
    otw: OTW, 
    voting_delay: u64, 
    voting_period: u64, 
    voting_quorum_rate: u64, 
    min_action_delay: u64, 
    min_quorum_votes: u64,
    ctx: &mut TxContext
): (Dao<OTW>, DaoTreasury<OTW>)
  • @param otw: A One Time Witness to ensure that the Dao is unique.

  • @param voting_delay: The minimum waiting period between the creation of a proposal and the voting period.

  • @param voting_period: The duration of the voting period.

  • @param voting_quorum_rate: The minimum percentage of votes to pass a proposal. E.g. for_votes / total_votes. keep in mind (0, 1_000_000_000]

  • @param min_action_delay: The minimum delay required to execute a proposal after it passes.

  • @param min_quorum_votes: The minimum votes required for a Proposal to be successful.

  • @return Dao<OTW>

  • @return Treasury<OTW>

Aborts

  • otw is not a One Time Witness.

  • voting_quorum_rate is larger than 1_000_000_000

  • voting_quorum_rate is zero.

voting_delay

Returns the minimum voting delay of the Dao.

public fun voting_delay<DaoWitness>(self: &Dao<DaoWitness>): u64
  • @param self: a Dao

  • @return u64

voting_period

Returns the minimum voting period of the Dao.

public fun voting_period<DaoWitness>(self: &Dao<DaoWitness>): u64
  • @param self: a Dao

  • @return u64

dao_voting_quorum_rate

Returns the minimum voting quorum rate of the Dao.

public fun dao_voting_quorum_rate<DaoWitness>(self: &Dao<DaoWitness>): u64
  • @param self: a Dao

  • @return u64

min_action_delay

Returns the minimum action delay of the Dao.

public fun min_action_delay<DaoWitness>(self: &Dao<DaoWitness>): u64
  • @param self: a Dao

  • @return u64

min_quorum_votes

Returns the minimum votes required to pass a proposal.

public fun min_quorum_votes<DaoWitness>(self: &Dao<DaoWitness>): u64
  • @param self: a Dao

  • @return u64

treasury

Returns the sui::object::id of the Dao wrapped in an std::option.

public fun treasury<DaoWitness>(self: &Dao<DaoWitness>): ID
  • @param self: a Dao

  • @return ID

dao_coin_type

Returns the std::type_name of the Dao's coin type. This is the Coin that can be used to vote on proposals.

public fun dao_coin_type<DaoWitness>(self: &Dao<DaoWitness>): TypeName
  • @param self: a Dao

  • @return TypeName

admin

Returns the sui::object::ID of Dao's admin capability. It is used to update the Dao's settings and transfer coins from the treasury.

public fun admin<DaoWitness>(self: &Dao<DaoWitness>): ID
  • @param self: a Dao

  • @return ID

proposer

Returns the address of the user who created the proposal.

public fun proposer<DaoWitness: drop>(proposal: &Proposal<DaoWitness>): address
  • @param proposal: The Proposal

  • @return address

start_time

Returns start timestamp of the proposal.

public fun start_time<DaoWitness: drop>(proposal: &Proposal<DaoWitness>): u64
  • @param proposal: The Proposal.

  • @return u64

end_time

Returns end timestamp of the proposal.

public fun end_time<DaoWitness: drop>(proposal: &Proposal<DaoWitness>): u64
  • @param proposal: The Proposal.

  • @return u64

for_votes

Returns the number of votes that support this proposal.

public fun for_votes<DaoWitness: drop>(proposal: &Proposal<DaoWitness>): u64
  • @param proposal: The Proposal.

  • @return u64

agaisnt_votes

Returns the number of votes against this proposal.

public fun against_votes<DaoWitness: drop>(proposal: &Proposal<DaoWitness>): u64
  • @param proposal: The {Proposal}.

  • @return u64

eta

Returns an estimation of when a successful proposal will be executed.

public fun eta<DaoWitness: drop>(proposal: &Proposal<DaoWitness>): u64
  • @param proposal: The Proposal.

  • @return u64

action_delay

Returns the minimum time a successful proposal has to wait before it can be executed.

public fun action_delay<DaoWitness: drop>(proposal: &Proposal<DaoWitness>): u64
  • @param proposal: The Proposal.

  • @return u64

quorum_votes

Returns the minimum number of votes required for a successful proposal.

public fun quorum_votes<DaoWitness: drop>(proposal: &Proposal<DaoWitness>): u64
  • @param proposal: The Proposal.

  • @return u64

voting_quorum_rate

Returns the minimum rate for a proposal to pass. Formula: for_votes / total_votes. 100% is represented by 1_000_000_000.

public fun voting_quorum_rate<DaoWitness: drop>(proposal: &Proposal<DaoWitness>): u64
  • @param proposal: The Proposal.

  • @return u64

hash

Returns the hash of the description of the proposal.

public fun hash<DaoWitness: drop>(proposal: &Proposal<DaoWitness>): String
  • @param proposal: The Proposal.

  • @return vector<u8>

authorized_witness

Returns the std::type_name::TypeName of the Witness that can execute the proposal.

public fun authorized_witness<DaoWitness: drop>(proposal: &Proposal<DaoWitness>): Option<TypeName>
  • @param proposal: The Proposal.

  • @return TypeName

capability_id

Returns the sui::object::ID of the Capability that the proposal requires to execute.

public fun capability_id<DaoWitness: drop>(proposal: &Proposal<DaoWitness>): Option<ID>
  • @param proposal: The Proposal.

  • @return Option<ID>

coin_type

Returns the CoinType of the proposal. Votes must use this CoinType.

public fun coin_type<DaoWitness: drop>(proposal: &Proposal<DaoWitness>): TypeName
  • @param proposal: The Proposal.

  • @return TypeName

balance

Returns the number of votes.

public fun balance<DaoWitness: drop, CoinType>(vote: &Vote<DaoWitness,  CoinType>): u64
  • @param vote: The Vote<DaoWitness, CoinType>.

  • @return u64

proposal_id

Returns the Proposal sui::object::ID.

public fun proposal_id<DaoWitness: drop, CoinType>(vote: &Vote<DaoWitness,  CoinType>): ID
  • @param vote: The Vote<DaoWitness, CoinType>.

  • @return ID

vote_end_time

Returns the ending timestamp of the proposal. Users can withdraw their deposited coins afterward.

public fun vote_end_time<DaoWitness: drop, CoinType>(vote: &Vote<DaoWitness,  CoinType>): u64
  • @param vote: The Vote<DaoWitness, CoinType>.

  • @return u64

agree

Returns if it is a for or against vote.

public fun agree<DaoWitness: drop, CoinType>(vote: &Vote<DaoWitness,  CoinType>): bool
  • @param vote: The Vote<DaoWitness, CoinType>.

  • @return bool

state

Returns the proposal state.

public fun agree<DaoWitness: drop, CoinType>(vote: &Vote<DaoWitness,  CoinType>): bool
  • @param vote: The Vote<DaoWitness, CoinType>.

  • @return u8

propose

Creates a Proposal.

public fun propose<DaoWitness: drop>(
    dao: &mut Dao<DaoWitness>,
    c: &Clock,
    authorized_witness: Option<TypeName>,
    capability_id: Option<ID>,
    action_delay: u64,
    quorum_votes: u64,
    hash: String,
    ctx: &mut TxContext    
 ): Proposal<DaoWitness>
  • @param dao: The Dao.

  • @param c: The shared sui::clock::Clock object.

  • @param authorized_witness: The Witness required to execute this proposal.

  • @param capability_id: The sui::object::ID of the Capability that this proposal needs to be executed. If a proposal is not executable pass option::none()

  • @param action_delay: The minimum waiting period for a successful Proposal to be executed.

  • @param quorum_votes: The minimum waiting period for a successful Proposal to be executed.

  • @param hash: The hash of the proposal's description.

  • @return Proposal<DaoWitness>

Abort

  • action_delay < dao.min_action_delay.

  • quorum_votes < dao.min_quorum_votes.

  • hash is empty.

cast_vote

Allows a user to use coins to vote for a proposal, either against or for depending on agree.

  public fun cast_vote<DaoWitness: drop, CoinType>(
    proposal: &mut Proposal<DaoWitness>,
    c: &Clock,
    stake: Coin<CoinType>,
    agree: bool,
    ctx: &mut TxContext
  ): Vote<DaoWitness, CoinType>
  • @param proposal: The proposal the user is voting for.

  • @param c: The shared sui::clock::Clock object.

  • @param stake: The coin that the user will deposit to vote.

  • @param agree: Determines if the vote is for or against..

  • @return Vote<DaoWitness, CoinType>

Aborts

  • if the proposal is not ACTIVE

  • if the stake type does not match the proposal.coin_type

  • if a user tries to vote with a zero coin stake.

change_vote

Allows a user to change his vote for a proposal.

public fun change_vote<DaoWitness: drop, CoinType>(
    proposal: &mut Proposal<DaoWitness>,
    vote: &mut Vote<DaoWitness,  CoinType>,
    c: &Clock,
    ctx: &mut TxContext
 )
  • @param proposal: The proposal the user is voting for.

  • @param vote: The vote that will be changed.

  • @param c: The shared sui::clock::Clock object.

Aborts

  • if the proposal is not ACTIVE

  • if the vote does not belong to the proposal.

revoke_vote

Allows a user to revoke his vote for a proposal and get his coin back.

public fun revoke_vote<DaoWitness: drop, CoinType>(
    proposal: &mut Proposal<DaoWitness>,
    vote: Vote<DaoWitness, CoinType>,
    c: &Clock,
    ctx: &mut TxContext    
 ): Coin<CoinType>
  • @param proposal: The proposal the user is voting for.

  • @param vote: The vote that will be destroyed.

  • @param c: The shared sui::clock::Clock object.

  • @return Coin<CoinType>

Aborts

  • if the proposal is not ACTIVE

  • if the vote does not belong to the proposal.

unstake_vote

Allows a user to unstake his vote to get his coins back after the proposal has ended.

public fun unstake_vote<DaoWitness: drop, CoinType>(
    proposal: &Proposal<DaoWitness>,
    vote: Vote<DaoWitness, CoinType>,
    c: &Clock,
    ctx: &mut TxContext      
): Coin<CoinType>
  • @param proposal: The proposal the user is voting for.

  • @param vote: The vote that will be destroyed.

  • @param c: The shared sui::clock::Clock object.

  • @return Coin<CoinType>

Aborts

  • if the proposal has not ended.

  • if the vote type does not match the proposal.id

queue

Allows a successful proposal to be queued.

public fun queue<DaoWitness: drop>(
    proposal: &mut Proposal<DaoWitness>, 
    c: &Clock
 )
  • @param proposal: The proposal the user is voting for.

  • @param c: The shared sui::clock::Clock object.

Aborts

  • if the proposal state is not AGREED.

execute

Executes a proposal.

public fun execute<DaoWitness: drop, AuhorizedWitness: drop, Capability: key + store>(
    dao: &mut Dao<DaoWitness>,
    proposal: &mut Proposal<DaoWitness>, 
    _: AuhorizedWitness,
    receive_ticket: Receiving<Capability>,
    c: &Clock
): (Capability, CapabilityRequest)
  • @param dao: The Dao.

  • @param proposal: The proposal that will be executed.

  • @param _: The witness that is authorized to borrow the Capability.

  • @param receive_ticket: A receipt struct to borrow the Capability.

  • @param c: The shared sui::clock::Clock object.

  • @return Capability required to execute the proposal.

  • @return CapabilityRequest A hot potato to ensure that the borrower returns the Capability to the dao.

Aborts

  • if the proposal state is not EXECUTABLE

  • if there has not passed enough time since the end_time

  • if the Authorized Witness does not match the proposal.authorized_witness.

  • if the borrowed capability does not match the proposal.capability_id.

return_capability

Returns the borrowed cap to the dao.

public fun return_capability<DaoWitness: drop, Capability: key + store>(dao: &Dao<DaoWitness>, cap: Capability, receipt: CapabilityRequest)
  • @param dao: The Dao.

  • @param cap: The capability that will be returned to the dao.

  • @param receipt: The request hot potato.

Aborts

  • if the user tries to return the cap to the wrong dao

  • if there user tries to return the wrong cap

update_dao_config

Updates the configuration settings of the dao.

public fun update_dao_config<DaoWitness: drop>(
    dao: &mut Dao<DaoWitness>,
    _: &DaoAdmin<DaoWitness>,
    voting_delay: Option<u64>, 
    voting_period: Option<u64>, 
    voting_quorum_rate: Option<u64>, 
    min_action_delay: Option<u64>, 
    min_quorum_votes: Option<u64>
)
  • @param dao: The Dao.

  • @param _: Immutable reference to the DaoAdmin.

  • @param voting_delay: The minimum waiting period between the creation of a proposal and the voting period.

  • @param voting_period: The duration of the voting period.

  • @param voting_quorum_rate: The minimum percentage of votes. E.g. for_votes / total_votes. Range = (0, 1_000_000_000]

  • @param min_action_delay: The delay required to execute a proposal after it passes.

  • @param min_quorum_votes: The minimum votes required for a {Proposal} to be successful.

Aborts

  • if the user tries to return the cap to the wrong dao

  • if there user tries to return the wrong cap

Last updated