版本比较

密钥

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

...

代码块
languagerust
// DaoSpace.move
module DaoSpace {

  struct Space {
    voting_delay: u128, // The delay between when a proposal is created, and when the voting starts. A voting_delay of 0 means that as soon as the proposal is created, anyone can vote. A voting_delay of 3600 means that voting will start 3600 seconds after the proposal is created.
    voting_duration: u128, // The duration of the voting period, i.e. how long people will be able to vote for a proposal.
    meta_data: vector<u8>, // 空间元数据,编码后存储在链上(可考虑存在链下)
  }
  
  struct NFTMeta {
    user: address,
  }
  
  struct NFTBody {
     weight: u128
  }
  
  struct SpaceCapability {
  }

  // 创建 space,一个账号只能创建一个(是否只能一个账户创建一个,待讨论)
  public fun create(signer: &signer, voting_delay: u128, voting_duration: u128, meta_data: &vector<u8>): SpaceCapability;
  // 查询 space
  public fun query(broker: address) : (u128, u128, u128);
  // 非托管账号 register
  public fun register(signer: &signer, space_broker: address, cap: &SpaceCapability) : NFT<NFTMeta, NFTBody>;
  // 非托管账号 unregister
  public fun unregister(signer: &signer, nft: NFT<NFTMeta, NFTBody>);
  // NFT 添加权重
  public fun add_weight(signer: &signer, nft: &mut NFT<NFTMeta, NFTBody>, weight: u128);
  // NFT 减少权重
  public fun reduce_weight(signer: &signer, nft: &mut NFT<NFTMeta, NFTBody>, weight: u128);
}

...

DaoRegistry

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

代码块

...

...

module 

...

DaoRegistry{

...

  

...

 

...

 ///
  struct 

...

DaoRegistryEntry<phantom DaoT>{
    

...

dao_id: 

...

u64,
 

...

 

...

  

...

dao_address: address,
  }

  

...

//这个方法必须由 Dao 

...

module 调用
  

...

public(friend) fun register<DaoT>(dao_id: u64,dao_address: address){
    let genesis_account = //get 0x1 signer
    move_to(&genesis_account, DaoRegistryEntry{
        dao_id,
        dao_address,
      }
    )
  }
  
  public fun dao_address<DaoT>():address{
    *&borrow_global<DaoRegistryEntry<DaoT>>.dao_address
  }
}

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

代码块
breakoutModewide
languagerust
// Dao.move
module Dao {
  use DaoSpace;

  struct DaoSignerDelegate has key {
    cap: SignerCapability, // 托管的签名(这里一旦放进来,就没法再还回去了,且只有一份,没想好是放在space还是放在这里,暂时放这里)
  }
  
  struct Dao {
    voting_delay: u128, // The delay between when a proposal is created, and when the voting starts. A voting_delay of 0 means that as soon as the proposal is created, anyone can vote. A voting_delay of 3600 means that voting will start 3600 seconds after the proposal is created.
    voting_duration: u128, // The duration of the voting period, i.e. how long people will be able to vote for a proposal.
    name: vector<u8>, //人类可识别的名称标识,是否需要?
    creator: address,
    meta_data: vector<u8>, // 空间元数据,编码后存储在链上(可考虑存在链下)
    cap: SpaceCapability
  }
  
  /// Proposal data struct.
  /// 是否需要通过 DaoT 来区分 Proposal,如果不需要,则需要把 DAO id 记录在 proposal 中
  /// 但 Action 的泛型无法消除
  struct Proposal<phantom DaoT: store, Action: store> has key {
        /// countid of voters who're against the proposal
        against_votesid: u128u64,
        /// executablecreator afterof thisthe time.proposal
        etaproposer: u64address,
        /// afterwhen how long, the agreed proposal can be executedvoting begins.
        actionstart_delaytime: u64,
        /// howwhen many votes to reach to make the proposal passvoting ends.
        quorumend_votestime: u128u64,
        /// proposal action.count of voters who agree with the proposal
        actionfor_votes: Option::Option<Action>u128,
        ///在原来的 Proposalcount 字段上新增两个字段of voters who're against the proposal
   block_num: u64, // 快照高度  against_votes: u128,
     root_hash:  vector<u8> /// executable after 快照根hashthis time.
 }      //Set 上也需要用泛型来区分eta: u64,
    struct DaoProposalSet {  /// after  proposal_set: HashSet<u64how long, DaoProposal>the agreed proposal }can be executed.
   //初始化过程中分配给 creator  cap   struct RootCapability has key{}action_delay: u64,
        struct/// DaoMemberMeta<phontemhow DaoT>many hasvotes copy{to reach to make  user: address,the proposal pass.
      }  quorum_votes: u128,
  //这里是否需要 DaoT 来区分不同的 Dao?   ///如果不区分的话,同一个用户加入多个 Daoproposal 的情况,当前的action.
IdentifierNFT 无法表达   struct DaoMemberBody<DaoT>{   action:  sbt: Token<DaoT>Option::Option<Action>,
  }      //在原来的 执行策略:转账Proposal 字段上新增两个字段
 struct ExecutionTransferStrategy<phontem TokenT> {     amountblock_num: u128u64, // 快照高度
   to: address,   } root_hash: vector<u8> // 快照根hash
 // 直接创建}
Dao  
public fun new_dao(
 //Set 上也需要用泛型来区分   
 creator: &signer,struct DaoProposalSet {
    votingproposal_delayset: u64HashSet<u64, DaoProposal>
  }
  voting_period:
u64,  //初始化过程中分配给 creator  cap
 min_action_delay: u64) {
  struct RootCapability has key{}
  
//这里 Account 需要提供一个新的方法,允许用一个账号去创建另外一个 Delegate 账号。
   struct InstallPluginCapability has key{
  }
  
let signer_cap = Account::create_delegate_account(&signer);
  struct ProposalPluginCapability<phontem ActionT> hash key{
  let dao_signer = Account::create_signer_with_cap(&siger_cap);installer: address,
     //下面面的操作切换到通过 dao_signerBitSet 身份进行操作的不同位置标识插件的不同权限
     letcapabilities: BitSet,
dao = Dao{..};
  
  move_to(&dao_signer, dao);
  struct DaoMemberMeta<phontem DaoT> has copy{
  // 托管 Daouser: 账号的address,
SignerCapability 到该合约 }
  
 move_to(&dao_signer, DaoSignerDelegate{cap: signer_cap});
     
     issue_member_nft(creator,&dao_signer);
 //这里是否需要 DaoT 来区分不同的 Dao?
  //如果不区分的话,同一个用户加入多个 Dao 的情况,当前的 IdentifierNFT 无法表达
  struct DaoMemberBody<DaoT>{
    sbt: Token<DaoT>,
  }
  
  //初始化 执行策略:转账
dao 的时候无法一次性完成,需要先把 capstruct 都存到ExecutionTransferStrategy<phontem creatorTokenT> 账号下{
     //然后按照 plugin 的方式逐步初始化amount: u128,
    }to: address,
  }
 // 
将一个账号直接升级为 Dao, sender// 会变为直接创建 Dao 账号
  public fun upgrade_tonew_dao(sender:signer, ...) {
     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, ...) {
     //基本逻辑同上,省去了创建账号的流程
  }
  
  public fun dao_address<DaoT>(){
    
  }
  
  fun dao_signer<DaoT>(): signer {
    let signer_cap = borrow_global<DaoSignerDelegate>(dao_address<DaoT>());
    Account::create_signer_with_cap(&siger_cap)
  }
  
  public fun install_proposal_plugin<PluginT>(cap: &dao::InstallPluginCapability, sender:&signer, capabilites: vector<u8>){
      //基本逻辑同上,省去了创建账号的流程move_to
  }
  
  // 这里有个难题是 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>>
  ) {
    
  }
}

...

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

module XProposalPlugin{
  use Dao::{Self,  ProposalPluginCapability}
  
  // XPlugin 的类型标识,用于保存配置
  struct XPlugin{
     cfg_a: u64,
  }
  
  struct XAction{
  }
  
  struct ProposalPluginCapabilityHolder{
     cap: ProposalPluginCapability<XAction>
  }
  
  fun new_action(args:vector<u8>): XAction{
       //bcs decode args
       //construct XAction
  }
  
  public fun plugin(sender: &signer){
    //这里的 sender
必须是 dao 账号,但这里如何获得 dao 账号,得想一个方式
  }
  
  public fun execute_proposal<DaoT>(sender: &signer, proposal_id: u64){
      let dao_address = Dao::get_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
      //update the executor
  }
  
  //the entry script function
  public(script) fun execute_proposal_entry<DaoT>(sender: signer, proposal_id: u64){
        execute_proposal<DaoT>(&sender, proposal_id)
  }
  
  public fun propose<DaoT>(sender:&signer, args:vector<u8>, exec_delay: u64){
      let action = new_action(args);
      
      let dao_address = Dao::get_dao_address<DaoT>();
      let cap_holder = borrow_global<ProposalPluginCapabilityHolder>(dao_address);
      
      Dao::propose<DaoT, XAction>(&cap_holder.cap, sender, action, exec_delay, exec_delay);
  }
  
  public(script) fun propose_entry<DaoT>(sender:signer, args:vector<u8>, exec_delay: u64){
      propose(&sender, args, exec_delay)
  }
}

...