// 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>>
) {
}
}
|