版本比较

密钥

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

...

代码块
breakoutModewide
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
  }
}

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
// Dao.move
module Dao {
  use DaoSpace;

  struct DaoSignerDelegate has key {
    cap: SignerCapability, // 托管的签名(这里一旦放进来,就没法再还回去了,且只有一份,没想好是放在space还是放在这里,暂时放这里)
  }
  
  struct Dao {
    id: u64,
    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 {
        /// 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 the proposal
        against_votes: 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.
        action: Option::Option<Action>,
        //在原来的 Proposal 字段上新增两个字段
        block_num: u64, // 快照高度
        root_hash: vector<u8> // 快照根hash
  }
  
  //Set 上也需要用泛型来区分   
  struct DaoProposalSet {
    proposal_set: HashSet<u64, DaoProposal>
  }
  
  //初始化过程中分配给 creator 的 cap
  struct RootCapability has key{}
  
  struct InstallPluginCapability has key{
  }
  
  struct ProposalPluginCapability<phontemProposalPluginInfo<PluginConfig has ActionT>store> hash key{
     installer: address,
     //通过 BitSet 的不同位置标识插件的不同权限
     capabilities: BitSet,
     config: Option<PluginConfig,
  }
  
  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)
  }
  
  public fun install_proposal_plugin<DaoT, PluginT>(cap: &dao::InstallPluginCapability, sender:&signer, capabilites: vector<u8>){
      let dao_signer = dao_signer<DaoT>();
      move_to(&dao_signer, ProposalPluginCapability<PluginT>{
        installer: Signer:address_of(sender),
        capabilites: BiteSet::from_bytes(capabilites),
      })
  }
  
  // _plugin 参数这里没有用,只是确保这个调用来自 PluginT 的实现模块
  public fun extract_proposal_plugin_capability<DaoT, PluginT>(_plugin: &PluginT): ProposalPluginCapability<PluginT>{ 
      move_from<ProposalPluginCapability<PluginT>>(dao_address<DaoT>())
  }
  
  // 这里有个难题是 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>>
  ) {
    
  }
}

...