版本比较

密钥

  • 该行被添加。
  • 该行被删除。
  • 格式已经改变。

...

比如,创始人 Alice 开始有了一个想法,于是创建了一个 ADao,这时候成员只有创始人一人,所以他的 SBT 权重为 100%,所有的提案他一个人就可以通过。后来他招募了两个合伙人,Bob 和 Tom,每人占 1/3 的 SBT 权重,所有的提案至少需要 2 个人同意(Dao 投票阈值为 50%的情况),ADao 变成了合伙 Dao。再后来,ADao 发行了一个 Token,安装了 Stake 插件,抵押该 Token 的自动成为 Dao 成员,成员 SBT 根据抵押时长计算,该 Dao 成为一个公共 Dao。

五、整体设计

Image Removed

space:空间,负责跟踪提案、投票的全局设置,其包含多个提案,空间中有一些Meta data(头像,描述,主站信息等),DaoSpace用以负责描述空间信息,每个项目方均可通过调用DaoSpace::create 来创建一个space。

...

languagerust

...

TODO update

...

DaoRegistry

Dao 注册中心,保存在 0x1 账号下的全局注册表,提供 DaoT → Dao address 的反向索引

代码块
module DaoRegistry{
  
   

...

/// 

...

Global 

...

Dao registry info
  

...

 

...

 

...

struct 

...

DaoRegistry 

...

has 

...

key{

...

 

...

 

...

 

...

 

...

 

...

   next_dao_id: u64,
    }

    /// Registry Entry for record the mapping between `DaoT` and `dao_address`
    struct DaoRegistryEntry<phantom DaoT> has key{
        dao_id: u64,
        dao_address: address,
    }

    // This function should call from GenesisDao module
    public(friend) fun register<DaoT>(dao_address: address): u64;
    
  

...

 

...

 

...

public fun dao_address<DaoT>():address;
}

DaoAccount

提供通用的 Dao 账户创建和管理能力。Dao 账户是对 SignerDelegated 账户的一种再封装,Dao 账户创建后,升级策略自动更新为两阶段升级策略。拥有 DaoAccountCap 即可拥有对该 DaoAccount 的控制权。

代码块
module DaoAccount{
 weight: u128  /// }DaoAccount
    struct structDaoAccount SpaceCapabilityhas key{
  }
   // 创建 space,一个账号只能创建一个(是否只能一个账户创建一个,待讨论) dao_address: address,
public   fun create(signer: &signer, voting_delay: u128, votingsigner_durationcap: u128SignerCapability,
meta_data: &vector<u8>): SpaceCapability;   // 查询 space upgrade_plan_cap: UpgradePlanCapability,
public fun query(broker: address) :}
(u128,
u128, u128);   /// 非托管账号This registercapability can control publicthe Dao funaccount
register(signer: &signer, space_broker: address, cap: &SpaceCapability) : NFT<NFTMeta, NFTBody>;struct DaoAccountCap has store, key{
  // 非托管账号 unregister   public fun unregister(signer dao_address: &signeraddress,
nft:   NFT<NFTMeta, NFTBody>);}
  // NFT 添加权重
  public fun add_weight(signer: &signer, nft: &mut NFT<NFTMeta, NFTBody>, weight: u128);
  // NFT 减少权重 /// Create a new Dao Account and return DaoAccountCap
    /// Dao Account is a delegate account, the `creator` has the `DaoAccountCap` 
    public fun reducecreate_weightaccount(signercreator: &signer, nft): &mutDaoAccountCap;
NFT<NFTMeta,
NFTBody>, weight: u128); }

DaoRegistry

Dao 注册中心,保存在 0x1 账号下的全局注册表,提供 DaoT → Dao address 的反向索引

...

breakoutModewide

...

 /// Provide a function to create signer with `DaoAccountCap`
    public fun dao_signer(cap: &DaoAccountCap): signer;
    

    public fun submit_upgrade_plan(cap: &DaoAccountCap, package_hash: vector<u8>, version:u64, enforced: bool);
}

GenesisDao

定义 Dao,Dao 的 Capability,Dao 的提案处理流程。

代码块
languagerust
module GenesisDao {
  
   struct Dao has key {
        dao_id: u64,
        dao_addressname: vector<u8>,
      }  dao_address: address,
  )   }   next_member_id: u64,
  public}
fun dao_address<DaoT>():address{
    *&borrow_global<DaoRegistryEntry<DaoT>>.dao_address
  }
}

DaoAccount

对 Dao Account 的封装,提供通用的 Dao 账号存储能力,是否需要和 Dao 合并在一起

代码块
breakoutModewide
module DaoAccount{

  //Dao 账号 signer 托管
  struct DaoSignerCapability has key {
    cap: SignerCapability,
  }
  
  // The capability for write data to dao account
  struct StorageCapability has drop{
    dao_address:address 
  }
  
  struct DaoUpgradePlanCapability has key{
    cap: PackageTxnManager::UpgradePlanCapability,
  }

  struct StorageItem<V has store> has key{
    item: V,
  }
  
  public fun create_account(creator: &signer){
     let signer_cap = Account::create_delegate_account(creator);
     let dao_signer = Account::create_signer_with_cap(&siger_cap);
     move_to(&dao_signer, DaoSignerCapability{
      cap: signer_cap,
     });
     PackageTxnManager::update_module_upgrade_strategy(&dao_signer, PackageTxnManager::get_strategy_two_phase(), Some(0));
     let upgrade_cap = PackageTxnManager::extract_submit_upgrade_plan_cap(&dao_signer);
     move_to(&dao_signer, DaoUpgradePlanCapability{
      cap: upgrade_cap,
     });
  }
  
  public(friend) fun dao_signer(dao_address: address): signer {
    let signer_cap = borrow_global<DaoSignerDelegate>(dao_address);
    Account::create_signer_with_cap(&signer_cap)
  }
  
  public(friend) fun apply_storage_capability(dao_address: address): StorageCapability{
    StorageCapability{
      dao_address
    }
  }
  
  public fun move_to<V has store>(cap: &StorageCapability, item: V){
    move_to(cap.dao_address, StorageEntry{
       item,
    })
  } 
  
  public fun move_from<V has store>(cap: &StorageCapability): V {
    let StorageItem{ item } = move_from<StorageItem<V>>(cap.dao_address);
    item
  }
}

Dao:代表治理的相关流程,该合约中处理底层Space与Proposal的拼装,将一些权限托管到该合约中,考虑还可以往上拆分,即将执行策略部分拆分到上层合约中。

...

breakoutModewide
languagerust

...

 /// Configuration of the DAO.
  struct DaoConfig has copy, drop, store {
      /// after proposal created, how long use should wait before he can vote (in milliseconds)
      voting_delay: u64,
      /// how long the voting window is (in milliseconds).
      voting_period: u64,
      /// the quorum rate to agree on the proposal.
      /// if 50% votes needed, then the voting_quorum_rate should be 50.
      /// it should between (0, 100].
      voting_quorum_rate: u8,
      /// how long the proposal should wait before it can be executed (in milliseconds).
      min_action_delay: u64,
      /// how many STC should be deposited to create a proposal.
      min_proposal_deposit: u128,
  }
  

   public fun withdraw_token<DaoT: store, PluginT, TokenT: store>(_cap: &DaoWithdrawTokenCap<DaoT, PluginT>, amount: u128): Token<TokenT>;
   
   public fun join_member<DaoT: store, PluginT>(_cap: &DaoMemberCap<DaoT, PluginT>, to_address: address, init_sbt: u128); 
   
}

DaoTemplate

每个 DAO 初始化的时候都会根据这个模版生成一个命名为 XDao 的 module,并且初始化插件。

代码块
/// Dao 生成模版,
module ${DaoName}Dao{
  use StarcoinFramework::GenesisDao;
  
  struct ${DaoName} has store{}
    
  const NAME: vector<u8> = b"${DaoName}";

  /// sender should create a DaoAccount before call this entry function.
  public(script) fun create_dao(sender: signer, voting_delay: u64,
      voting_period: u64,
      voting_quorum_rate: u8,
      min_action_delay: u64,
      min_proposal_deposit: u128,){
      
      let dao_account_cap = DaoAccount::extract_dao_account_cap(&sender);
  
      let config = GenesisDao::new_dao_config(
          voting_delay,
          voting_period,
          voting_quorum_rate,
          min_action_delay,
          min_proposal_deposit,
      );
      let dao_root_cap = GenesisDao::create_dao<${DaoName}>(dao_account_cap, *&NAME, ${Name}{}, config);
      
      $for_each plugin in $Plugins{
        GenesisDao::install_plugin_with_root_cap<${DaoName}, plugin.Name>(&dao_root_cap, ${plugin.Name}::required_caps());
      }
      GenesisDao::burn_root_cap(dao_root_cap);
  }
  
}

Proposal

提案代表一次治理过程,Dao 的成员根据 SBT 的快照来进行投票。

代码块
languagerust
module GenesisDao {

  /// Proposal data struct.
  ///struct 是否需要通过 DaoT 来区分 Proposal,如果不需要,则需要把 DAO id 记录在 proposal 中
  /// 但 Action 的泛型无法消除
  struct Proposal<phantom DaoT: store, Action: store> has keyProposal has store, copy, drop {
        /// id of the proposal
        id: u64,
 
      /// creator of the proposal
        proposer: address,
        /// when voting begins.
        start_time: u64,
        /// when voting ends.

       end_time: u64,
        /// count of voters who agree with the proposal
        for_votes: u128,
        /// count of voters who're against `yes|no|no_with_veto|abstain` with the proposal
        against_votes: u128vector<u128>,
        /// executable after this time.
        eta: u64,
 
      /// after how long, the agreed proposal can be executed.
        action_delay: u64,
 
      /// how many votes to reach to make the proposal pass.
 
      quorum_votes: u128,
 
      /// proposal action.
the block number when submit proposal 
      actionblock_number: Option::Option<Action>u64,
        ///在原来的 Proposalthe 字段上新增两个字段state root of the block which has the  block_num:number u64,
// 快照高度         root_hashstate_root: vector<u8>,
// 快照根hash }

}  struct ProposalAction<Action: store> has //Setstore 上也需要用泛型来区分{
     struct DaoProposalSet { /// id of the proposal
      proposal_setid: HashSet<u64u64, DaoProposal>
  }      //初始化过程中分配给To creatorprevent spam, capproposals must be structsubmitted RootCapabilitywith hasa key{}deposit
     struct InstallPluginCapability//TODO hasshould key{support custom Token?
}      structdeposit: ProposalPluginInfo<PluginConfigToken<STC>,
has store> hash key{   /// proposal action.
installer: address,      //通过 BitSet 的不同位置标识插件的不同权限
     capabilities: BitSet,
     config: Option<PluginConfig,
  }
  
  // DaoWithdrawCapability 是一次性的 capability,不能 store,可以 drop
  struct DaoWithdrawCapability has drop{
  }
  
  struct DaoMemberMeta<phontem DaoT> has copy{
    user: address,
  }
  
  //这里是否需要 DaoT 来区分不同的 Dao?
  //如果不区分的话,同一个用户加入多个 Dao 的情况,当前的 IdentifierNFT 无法表达
  struct DaoMemberBody<DaoT>{
    sbt: Token<DaoT>,
  }
  
  // 执行策略:转账
  struct ExecutionTransferStrategy<phontem TokenT> {
    amount: u128,
    to: address,
  }
  
  // 直接创建 Dao
  public fun new_dao(
     creator: &signer, 
     voting_delay: u64, 
     voting_period: u64, 
     min_action_delay: u64) {
     //这里 Account 需要提供一个新的方法,允许用一个账号去创建另外一个 Delegate 账号。
     let signer_cap = Account::create_delegate_account(&signer);
     let dao_signer = Account::create_signer_with_cap(&siger_cap);
     //下面面的操作切换到 dao_signer 身份进行操作
     let dao = Dao{..};
     move_to(&dao_signer, dao);
     // 托管 Dao 账号的 SignerCapability 到该合约
     move_to(&dao_signer, DaoSignerDelegate{cap: signer_cap});
     
     issue_member_nft(creator,&dao_signer);
     
     //初始化 dao 的时候无法一次性完成,需要先把 cap 都存到 creator 账号下
     //然后按照 plugin 的方式逐步初始化
  }
  
  // 将一个账号直接升级为 Dao, sender 会变为 Dao 账号
  public fun upgrade_to_dao(sender:signer, ...) {
     //基本逻辑同上,省去了创建账号的流程
  }
  
  ///这里好像没办法检测 DaoT 和 dao_address 的关系
  public fun register<DaoT>(creator: &signer, dao_address: address){
      let dao = borrow_global<Dao>(DaoRegsitry::dao_address<DaoT>());
      //check the dao creator and creator args
      DaoRegistry::register<DaoT>(dao_address, dao.id)
  }
  
  fun dao_signer<DaoT>(): signer {
    let signer_cap = borrow_global<DaoSignerDelegate>(DaoRegsitry::dao_address<DaoT>());
    Account::create_signer_with_cap(&siger_cap)
  }
  
  /// _access_key 确保这个调用来自 PluginT 的 Module
  public fun install_proposal_plugin<DaoT, PluginT>(cap: &dao::InstallPluginCapability, _access_key: &PluginT, installer:&signer, capabilites: vector<u8>){
      let dao_signer = dao_signer<DaoT>();
      move_to(&dao_signer, ProposalPluginCapability<PluginT>{
        installer: Signer:address_of(installer),
        capabilites: BiteSet::from_bytes(capabilites),
      })
  }
  
  public fun borrow_withdraw_capability<DaoT, PluginT>(plugin: &PluginT): DaoWithdrawCapability {
      // check capability with ProposalPluginCapability
      DaoWithdrawCapability
  }
  
  public fun withdraw<DaoT, TokenT>(cap: DaoWithdrawCapability, amount: u64): Token<TokenT>{
    let dao_signer = dao_signer<DaoT>();
    Account::withdraw<TokenT>(amount)
  }
  
  struct PluginStorageItem<PluginT, V>{
    item: V,
  }
  
  public fun move_to<DaoT, PluginT, V>(_access_key: &PluginT, item: V){
    let dao_signer = dao_signer<DaoT>();
    move_to(&dao_signer, PluginStorageItem<PluginT>{
      item
    });
  }
  
  // 这里有个难题是 TokenT 从哪里来。
  // 一种方法是先生成一个账号,部署合约,然后升级为 dao
  // 另外一种方法是通过 Dao 的合约升级方式进行部署合约
  fun issue_member_nft<DaoT>(creator: &signer, dao_signer: &signer){
     Token::register<DaoT>(dao_signer);
     let basemeta = NFT::new_meta_with_image();
     NFT::register_nft_v2<DaoMemberMeta<DaoT>>(dao_signer, basemeta);
     let creator_address = Signer::address_of(creator);
     // issue 第一个 NFT 给 creator
     let meta = DaoMemberMeta<DaoT>{
        user: creator;
     };
     //如何初始化 creator 的 sbt?
     let sbt = Token::zero<DaoT>();
     let body = DaoMemberBody<DaoT>{
      sbt,
     }
     let nft = NFT::mint(basemeta, meta, body);
     IdentifierNFT::accept<DaoMemberMeta<DaoT>,DaoMemberBody<DaoT>>(creator);
     IdentifierNFT::grant(dao_signer, creator);
     
  }
     
  // 参与投票方/创建投票方注册到space
  public fun register_to_space(
      signer: &signer, 
      broker: address) {
      // 创建对应的NFT
  }

  // 参与投票方/创建投票方注册到space
  // 方便再上一层的DAO调用
  public fun regiter_to_space_get_nft(
      signer: &signer, 
      broker: address) : Option::Option<NFT<DaoSpace::NFTMeta, DaoSpace::NFTData>> {
  }
  
  // 根据 space_broker 来创建对应的proposal
  public fun create_proposal<ExecutionStrategy>(
      signer: &signer, // 创建者
      space_broker: u64, // space 代理人
      block_num: u64, // 快照高度
      root_hash: vector<u8> // 快照根hash
  );
  
  // 投票
  public fun do_vote(
      signer: &signer, 
      broker: address,
      id: u64, 
      amount: u128,
      choice: u8,
      proof: &vector<u8>,
      side_nodes: &vector<u8>) {
    // 证明...
    // 取本地NFT
    // 用NFT投票
    do_vote_with_nft(broker, id, choice, );
  }
  
  // 用NFT来投票
  // 方便上层DAO来调用
  public fun do_vote_with_nft(
    broker: address,
    id: u64,
    choice: u8,
    nft: Option::Option<NFT<DaoSpace::NFTMeta, DaoSpace::NFTData>>
  ) {
    
  }
}

DaoTemplate

每个 DAO 初始化的时候都会根据这个模版生成一个命名为 XDao 的 module。需要确认下 XDao 这个 module 是否使用统一的名字更容易使用。

代码块
breakoutModewide
/// Dao 生成模版,
module {X}Dao{
  use StarcoinFramework::Dao;
  
  //XDao 的类型标识
  struct X {}
  
  const DAO_ADDRESS = {dao_address};
  
  
  
  public(script) init_dao(sender: signer, capabilities:vector<vector<u8>, plugin_configs: vector<vector<u8>>){
    let plugin_install_cap = Dao::create_dao();
    PluginX::install_plugin(&plugin_install_cap, &sender, capabilities[0],configs[0]);
    PluginY::install_plugin(&plugin_install_cap, &sender, capabilities[1],configs[1]);
  }
  
  ///Dao 的入口方法是不是都需要通过 XDao 模块代理一边?
  
}

proposal:提案,即一个提案代表一次投票过程,该部分跟原有的流程类似,但是去掉了TokenType,该合约只处理提案的相关处理过程,不做其他无关的事情。

代码块
breakoutModewide
languagerust
// DaoProposal.move
module DaoProposal {

  struct ProposalCapability {
    proposal_id: u64,
  }

  struct Proposal<Action> {
    ... // 现有的一些结构
    proposal_id: u64,
    voting_system: u8, // 投票类型有单选投票、二次投票、排名投票、加权投票等投票类型
    voting_start_time: u64,
    voting_end_time: u64,
    voting_block_num: u64, // 投票快照高度
    voting_block_root: vector<u8>, // 投票快照高度的root hash
    action: Option::Option<Action>, // 执行策略的结构参数
  }
  
  struct Vote {
    /// vote for the proposal under the `proposer`.
    proposer: address,
    /// proposal id.
    id: u64,
    choie: u8, // 同意,反对,拒绝
    weight: u128, // 投票权重
  }
  
  public fun create_proposal<Action>(...,
      space_broker: address, 
      space_id: u64,
      root_hash: &vector<u8>): ProposalCapability;
  
  public fun cast_vote(
      signer: &signer,
      proposer_broker: address,
      id: u64, 
      amount: u128,
      choice: u8,
      cap: &ProposalCapability
    );
    
  public fun extract_strategy<Action>(id: u64) : Action;
};

Proposal action plugin

代码块
breakoutModewide
//所有的 proposal action 插件都需要提供两个公开的 entry script function,参数保持一致

module XProposalPlugin{
  use Dao::{Self,  ProposalPluginCapability}
  
  // XPlugin 的类型标识
  struct XPlugin{
  }
  
  struct XPluginConfig{
    cfg_1: u64,
  }
  
  struct XAction{
  }
  
  struct ProposalPluginCapabilityHolder{
     cap: ProposalPluginCapability<XPlugin>
  }
  
  fun new_action(args:vector<u8>): XAction{
       //bcs decode args
       //construct XAction
  }
  
  //返回 plugin 所需要的 capabilities
  public fun get_capabilities():vector<u8>{}
  
  public fun install_plugin<DaoT>(cap: &Dao::PluginInstallCapability, installer: &signer, capabilities: vector<u8>, config:vector<u8>){
     //bcs decode config arg, construct config.
     let config = XPluginConfig{}
     let plugin = XPlugin{};
     Dao::install_proposal_plugin_capability<DaoT, XPlugin>(cap, &plugin, installer, capabilities);
     //保存配置
     Dao::move_to<DaoT, XPlugin>(&plugin, config);
  }
  
  public fun execute_proposal<DaoT>(sender: &signer, proposal_id: u64){
      let dao_address = DaoRegistry::dao_address<DaoT>();
      let cap_holder = borrow_global<ProposalPluginCapabilityHolder>(dao_address);
      let actoin = Dao::extract_proposal_action<DaoT, XAction>(&cap_holder.cap, sender, proposal_id);
      //execute the action,such as trasnfer tokenaction: Action,
  }
}

Proposal action plugin

以成员加入的 Proposal Plugin 为例,create_proposal 方法会在 DaoT 代表的 Dao 中创建一个 Proposal。该 Dao 的成员进行投票,按照治理流程对 Proposal 进行决策,如果到达可执行状态,则任何人可以调用 execute_proposal 方法执行该提案,执行后,MemberJoinAction 中的 member 成为 Dao 的成员,并且得到了 init_sbt 个 SBT。

代码块
module MemberProposalPlugin{
    use StarcoinFramework::GenesisDao::{Self, CapType};
    use StarcoinFramework::Vector;

    struct MemberProposalPlugin has drop{}

    struct MemberJoinAction has store {
        member: address,
        init_sbt: u128,
    }

    public fun required_caps():vector<CapType>{
       Vector::singleton(GenesisDao::member_cap_type())    
    }

    public fun create_proposal<DaoT: store>(sender: &signer, member: address, init_sbt: u128, action_delay: u64){
        let pluginwitness = XPluginMemberProposalPlugin{};
        let withdraw_cap = DaoGenesisDao::borrowacquire_withdrawproposal_capability<DaoTcap<DaoT,XPlugin> MemberProposalPlugin>(&pluginwitness);
        let tokenaction = Dao::withdraw<STC>(&withdraw_cap, 1000); MemberJoinAction{
            //updatemember,
the executor   }      //the entry scriptinit_sbt,
function   public(script) fun execute_proposal_entry<DaoT>(sender: signer, proposal_id: u64){ };
        execute_proposal<DaoT>GenesisDao::create_proposal(&cap, sender, action, proposalaction_iddelay);
    }

    public fun execute_proposal<DaoT: propose<DaoT>store>(sender: &signer, args:vector<u8>, exec_delayproposal_id: u64){
      let action = new_action(args);
      
      let dao_address = Dao::get_dao_address<DaoT>()let witness = MemberProposalPlugin{};
        let proposal_cap_holder = borrow_global<ProposalPluginCapabilityHolder>(dao_addressGenesisDao::acquire_proposal_cap<DaoT, MemberProposalPlugin>(&witness);
        let MemberJoinAction{member, init_sbt} =  DaoGenesisDao::propose<DaoTexecute_proposal<DaoT, MemberProposalPlugin, XAction>MemberJoinAction>(&capproposal_holder.cap, sender, action, exec_delay, exec_delayproposal_id);

 }      public(script) funlet propose_entry<DaoT>(sender:signer, args:vector<u8>, exec_delay: u64){member_cap = GenesisDao::acquire_member_cap<DaoT, MemberProposalPlugin>(&witness);
        proposeGenesisDao::join_member(&sendermember_cap, argsmember, execinit_delaysbt);
    }
}

...

TODO 详细描述提案处理流程

六、流程

创建流程

  1. 用户 A 发起交易,先创建合约账号 X, A 拥有 X 的控制权。

  2. 用户填写配置,选择需要安装的插件,生成 用户通过 DApp 界面填写配置,选择需要安装的插件,DApp 根据 Dao Template 生成 XDao module,以及初始化的参数。

  3. 编译 浏览器编译 XDao module,并且通过两阶段升级的方式,由 A 来发期交易,将 来发起交易,将 XDao module 部署到 X 账号下,并通 init_script 初始化 XDao 以及插件。

  4. Dao 创建完成。创建完成,进入治理阶段。

...

七、问题

  1. Move实现层面,区分不同的项目方来创建DAO,是通过Template Type 来对其进行异化还是通过 address+id的方式,若按照前者,如何解决合约动态部署的问题?

    这个当前有两个方案,这个 issue 中提了两个方案 [Feature Request] Support Issue a Token on webpage · Issue #4 · starcoinorg/dapps (http://github.com ) ,未来可以支持合约中部署合约。

  2. Snapshot中,存在不同的准入策略,即参与/创建投票的人在DAO中创建/参与投票的时候会有一个准入的门槛,这个准入的门槛是一系列判断条件,这个条件有预置的也有用户。在solidity中可以动态调用,故可以通过一个ABI的字符数组来进行表示,实际执行的时候也是动态去调用这个ABI,且这些策略是可以拼接的。而Move中如果也按照这个思路显然无法实现

    感觉可以简化一下,小额抵押某种 Token 即可,如果是发垃圾投票就通过投票没收。

  3. 类似的,Snapshot也存在不同的Execution Action,在Move中也可以通过预置Execution的模式去实现,是否还有其他的实现思路?

    当前 DAO 的 Action 是支持第三方扩展的,并不是只能用预置的 Action。
    执行在前端触发。

  4. 治理权重的计算(基于长线hodl:锁仓时长、锁仓量),基于余额的权重计算有难度。锁仓有激励。

    1. 不同类型项目采用不同机制。Swap自实现weight维护。

  5. 扩展点的设计,包括Action等动态调用的扩展,通过interface形式,前端来触发。DAO的平滑升级如何扩展?

    1. Action的扩展性;

    2. DAO类型的扩展性,不同DAO类型如何转换;

    3. 投票权重的扩展性;

    4. 投票策略类的扩展性;

6.2号讨论:

  • 插件的扩展性,DAO的创建,通过Templete来实现,第一期不开放注册入口

  • DAO的升级,不同类型的DAO进行抽象,尽可能抽象出同样的类型和权限,否则升级会比较困难;

  • Member加入的门槛,通过判断某种token的balance,不跟stake耦合;member列表如何存储?

  • SBT 权重的维护,由项目方合约来更新,无法实现hook机制

  • 一期不提供合约,实现链下DAO+问卷类投票,纯粹API+前端来实现,同步开发合约;二期上线合约版DAO,支持链上DAO和治理,避免合约升级和兼容性问题。

  • 设计通用的Stake流程和Library,锁仓时长、收益、权益的发放等

  • DAO产品调研和需求完善

  • 论坛/文档

  • 直播

  • 公链升级切换到DAO上

DAO合约分工

...

DAO合约框架 @jolestar

...

插件机制,包括插件权限等 @jolestar

...

DAO Bob

...

Member及 插件机制 Ellen

  • SBT/NFT

...

Proposal ElementX

...

Action

工具链

...

bsc序列化,参数传参

...

merkle proof

...


五、参考

Snapshot 说明文档

Snapshot X 说明文档

...