From ff2d802aa64665464920ca9a26164c2e0478956d Mon Sep 17 00:00:00 2001 From: 0xpause <101114886+0xpause@users.noreply.github.com> Date: Fri, 2 Sep 2022 11:46:37 +0800 Subject: [PATCH] MintProposalPlugin (#105) * token mint and burn cap in DAOSapce * add MintProposalPlugin * add mint_proposal_plugin test * remove unnecessary assert * fix exp * update delegate_token_mint_cap/delegate_token_mint_cap_entry --- build/StarcoinFramework/BuildInfo.yaml | 5 +- build/StarcoinFramework/docs/README.md | 1 + .../daospaceplugin/mint_proposal_plugin.exp | 81 ++++++ .../daospaceplugin/mint_proposal_plugin.move | 265 ++++++++++++++++++ sources/daospace/DAOSpace.move | 114 ++++++-- .../daospaceplugin/MintProposalPlugin.move | 61 ++++ 6 files changed, 501 insertions(+), 26 deletions(-) create mode 100644 integration-tests/daospaceplugin/mint_proposal_plugin.exp create mode 100644 integration-tests/daospaceplugin/mint_proposal_plugin.move create mode 100644 sources/daospaceplugin/MintProposalPlugin.move diff --git a/build/StarcoinFramework/BuildInfo.yaml b/build/StarcoinFramework/BuildInfo.yaml index 33f0d766..d8a659bb 100644 --- a/build/StarcoinFramework/BuildInfo.yaml +++ b/build/StarcoinFramework/BuildInfo.yaml @@ -150,6 +150,9 @@ compiled_package_info: ? address: "0x00000000000000000000000000000001" name: MintDaoProposal : StarcoinFramework + ? address: "0x00000000000000000000000000000001" + name: MintProposalPlugin + : StarcoinFramework ? address: "0x00000000000000000000000000000001" name: MintScripts : StarcoinFramework @@ -300,7 +303,7 @@ compiled_package_info: ? address: "0x00000000000000000000000000000001" name: YieldFarmingV2 : StarcoinFramework - source_digest: C3F10D8763E687130581034F694C48F86494655044F4BC0919B011480303FC2C + source_digest: 2F6686B5BAFFE5E5DEB6F001CD6D0D8FA93121DB944E71F0E3DCBAB51D81FA90 build_flags: dev_mode: false test_mode: false diff --git a/build/StarcoinFramework/docs/README.md b/build/StarcoinFramework/docs/README.md index 78470a98..485bf4ec 100644 --- a/build/StarcoinFramework/docs/README.md +++ b/build/StarcoinFramework/docs/README.md @@ -60,6 +60,7 @@ This is the root document for the Move StarcoinFramework module documentation. T - [`0x1::MerkleNFTDistributor`](MerkleNFT.md#0x1_MerkleNFTDistributor) - [`0x1::MerkleProof`](MerkleNFT.md#0x1_MerkleProof) - [`0x1::MintDaoProposal`](MintDaoProposal.md#0x1_MintDaoProposal) +- [`0x1::MintProposalPlugin`](MintProposalPlugin.md#0x1_MintProposalPlugin) - [`0x1::MintScripts`](MintScripts.md#0x1_MintScripts) - [`0x1::ModifyDaoConfigProposal`](ModifyDaoConfigProposal.md#0x1_ModifyDaoConfigProposal) - [`0x1::ModuleUpgradeScripts`](ModuleUpgradeScripts.md#0x1_ModuleUpgradeScripts) diff --git a/integration-tests/daospaceplugin/mint_proposal_plugin.exp b/integration-tests/daospaceplugin/mint_proposal_plugin.exp new file mode 100644 index 00000000..1047997c --- /dev/null +++ b/integration-tests/daospaceplugin/mint_proposal_plugin.exp @@ -0,0 +1,81 @@ +processed 29 tasks + +task 8 'run'. lines 71-85: +{ + "gas_used": 125914, + "status": "Executed" +} + +task 9 'run'. lines 87-96: +{ + "gas_used": 1106537, + "status": "Executed" +} + +task 10 'run'. lines 98-108: +{ + "gas_used": 53739, + "status": "Executed" +} + +task 11 'run'. lines 110-123: +{ + "gas_used": 8525, + "status": { + "ExecutionFailure": { + "location": { + "Module": { + "address": "0x00000000000000000000000000000001", + "name": "Token" + } + }, + "function": 16, + "code_offset": 2 + } + } +} + +task 12 'run'. lines 125-139: +{ + "gas_used": 264834, + "status": "Executed" +} + +task 16 'run'. lines 147-158: +{ + "gas_used": 101440, + "status": "Executed" +} + +task 19 'run'. lines 164-173: +{ + "gas_used": 575872, + "status": "Executed" +} + +task 20 'run'. lines 175-200: +{ + "gas_used": 435660, + "status": "Executed" +} + +task 22 'call'. lines 204-204: +"0xa7dcef9aef26202fce82a7c7d6672afb/1/0x00000000000000000000000000000001::IdentifierNFT::IdentifierNFT<0x00000000000000000000000000000001::DAOSpace::DAOMember<0x662ba5a1a1da0f1c70a9762c7eeb7aaf::XDAO::XDAO>,0x00000000000000000000000000000001::DAOSpace::DAOMemberBody<0x662ba5a1a1da0f1c70a9762c7eeb7aaf::XDAO::XDAO>>" + +task 24 'run'. lines 208-222: +{ + "gas_used": 8799122, + "status": "Executed" +} + +task 26 'run'. lines 226-240: +{ + "gas_used": 173465, + "status": "Executed" +} + +task 28 'run'. lines 244-265: +{ + "gas_used": 513504, + "status": "Executed" +} diff --git a/integration-tests/daospaceplugin/mint_proposal_plugin.move b/integration-tests/daospaceplugin/mint_proposal_plugin.move new file mode 100644 index 00000000..76769c9c --- /dev/null +++ b/integration-tests/daospaceplugin/mint_proposal_plugin.move @@ -0,0 +1,265 @@ +//# init -n dev + +//# faucet --addr creator --amount 100000000000 + +//# faucet --addr alice --amount 10000000000 + +//# faucet --addr bob --amount 10000000000 + +//# faucet --addr cindy --amount 10000000000 + +//# publish +module creator::XDAO { + use StarcoinFramework::DAOAccount; + use StarcoinFramework::DAOSpace; + use StarcoinFramework::AnyMemberPlugin::{Self, AnyMemberPlugin}; + use StarcoinFramework::InstallPluginProposalPlugin::{Self, InstallPluginProposalPlugin}; + use StarcoinFramework::MintProposalPlugin::{Self, MintProposalPlugin}; + use StarcoinFramework::Option; + + struct XDAO has store, copy, drop{} + + const NAME: vector = b"X"; + + /// directly upgrade the sender account to DAOAccount and create DAO + 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::upgrade_to_dao(sender); + + + //let dao_signer = DAOAccount::dao_signer(&dao_account_cap); + let config = DAOSpace::new_dao_config( + voting_delay, + voting_period, + voting_quorum_rate, + min_action_delay, + min_proposal_deposit, + ); + let dao_root_cap = DAOSpace::create_dao(dao_account_cap, *&NAME, Option::none>(), + Option::none>(), b"ipfs://description", XDAO{}, config); + + DAOSpace::install_plugin_with_root_cap(&dao_root_cap, InstallPluginProposalPlugin::required_caps()); + DAOSpace::install_plugin_with_root_cap(&dao_root_cap, AnyMemberPlugin::required_caps()); + DAOSpace::install_plugin_with_root_cap(&dao_root_cap, MintProposalPlugin::required_caps()); + + DAOSpace::burn_root_cap(dao_root_cap); + + } +} + +//# publish +module alice::AliceToken { + use StarcoinFramework::Token; + + struct AliceToken has copy, drop, store { } + + public fun init(account: &signer) { + Token::register_token( + account, + 3, + ); + } +} + +//# block --author 0x1 --timestamp 86400000 + +//# run --signers alice +script { + use alice::AliceToken::{AliceToken, Self}; + use StarcoinFramework::Account; + use StarcoinFramework::Token; + + fun main(account: signer) { + AliceToken::init(&account); + let market_cap = Token::market_cap(); + assert!(market_cap == 0, 101); + assert!(Token::is_registered_in(@alice), 102); + Account::do_accept_token(&account); + } +} +// check: EXECUTED + +//# run --signers creator +script{ + use creator::XDAO; + + fun main(sender: signer){ + // time unit is millsecond + XDAO::create_dao(sender, 10000, 360000, 1, 10000, 0); + } +} +// check: EXECUTED + +//# run --signers alice +script { + use alice::AliceToken::AliceToken; + use creator::XDAO::XDAO; + use StarcoinFramework::MintProposalPlugin; + + fun main(sender: signer) { + MintProposalPlugin::delegate_token_mint_cap_entry(sender); + } +} +// check: EXECUTED + +//# run --signers alice +script { + use alice::AliceToken::AliceToken; + use StarcoinFramework::Account; + use StarcoinFramework::Token; + use StarcoinFramework::Signer; + + fun main(sender: signer) { + let token = Token::mint(&sender, 100000); + let receiver = Signer::address_of(&sender); + Account::deposit(receiver, token); + } +} +// check: ABORTED, Alice don't have MintCapability + +//# run --signers alice +script { + use creator::XDAO::XDAO; + use StarcoinFramework::AnyMemberPlugin; + use StarcoinFramework::IdentifierNFT; + use StarcoinFramework::DAOSpace::{DAOMember, DAOMemberBody}; + + fun main(sender: signer) { + IdentifierNFT::accept, DAOMemberBody>(&sender); + let image_data = b"image"; + let image_url = b""; + AnyMemberPlugin::join(sender, image_data, image_url); + } +} +// check: EXECUTED + +//# block --author 0x1 --timestamp 86410000 + +//# block --author=0x2 --timestamp 86420000 + +//# call-api chain.info + +//# run --signers alice --args {{$.call-api[0].head.parent_hash}} +script { + use StarcoinFramework::Block; + + fun checkpoint(_account: signer, parent_hash: vector) { + let expect_parent_hash = Block::get_parent_hash(); + assert!(expect_parent_hash == parent_hash, 103); + + Block::checkpoint(); + } +} +// check: EXECUTED + +//# block --author=0x3 --timestamp 86450000 + +//# call-api chain.get_block_by_hash ["{{$.call-api[0].head.parent_hash}}",{"raw":true}] + +//# run --signers alice --args {{$.call-api[1].raw.header}} + +script { + use StarcoinFramework::Block; + + fun update(_account: signer, raw_header: vector) { + Block::update_state_root(raw_header); + } +} +// check: EXECUTED + +//# run --signers alice +script { + use alice::AliceToken::AliceToken; + use creator::XDAO::XDAO; + use StarcoinFramework::MintProposalPlugin; + + use StarcoinFramework::Debug; + use StarcoinFramework::DAOSpace; + + fun main(sender: signer) { + let description = b"mint to bob"; + let amount = 100000; + let action_delay = 0; + MintProposalPlugin::create_mint_proposal( + sender, description, @bob, amount, action_delay); + let (_id, proposer, start_time, end_time, _yes_votes, _no_votes, _no_with_veto_votes, _abstain_votes, block_number, state_root) = DAOSpace::proposal_info(1); + + Debug::print(&proposer); + Debug::print(&start_time); + Debug::print(&end_time); + Debug::print(&block_number); + Debug::print(&state_root); + + } +} +// check: EXECUTED + +//# block --author=0x3 --timestamp 86460000 + +//# call 0x1::SnapshotUtil::get_access_path --type-args {{$.faucet[0].txn.raw_txn.decoded_payload.ScriptFunction.args[0]}}::XDAO::XDAO --args {{$.faucet[1].txn.raw_txn.decoded_payload.ScriptFunction.args[0]}} + +//# call-api state.get_with_proof_by_root_raw ["{{$.call[0]}}","{{$.call-api[1].header.state_root}}"] + +//# run --signers alice --args {{$.call-api[2]}} +script{ + use creator::XDAO::XDAO; + use StarcoinFramework::DAOSpace; + + fun cast_vote(sender: signer, snpashot_raw_proofs: vector){ + let proposal_id = 1; + let choice = DAOSpace::choice_yes(); + DAOSpace::cast_vote(&sender, proposal_id, snpashot_raw_proofs, choice); + + let proposal_state = DAOSpace::proposal_state(1); + assert!(proposal_state == 2, 104); // DAOSpace::ACTIVE + } +} +// check: EXECUTED + +//# block --author=0x3 --timestamp 86830000 + +//# run --signers alice +script{ + use creator::XDAO::XDAO; + use StarcoinFramework::DAOSpace; + + // execute action + fun queue_proposal_action(sender: signer){ + let proposal_id = 1; + let proposal_state = DAOSpace::proposal_state(proposal_id); + assert!(proposal_state == 4, 105); // DAOSpace::AGREED + DAOSpace::do_queue_proposal_action(&sender, proposal_id); + + } +} +// check: EXECUTED + +//# block --author=0x3 --timestamp 86840000 + +//# run --signers bob +script { + use creator::XDAO::XDAO; + use alice::AliceToken::AliceToken; + use StarcoinFramework::MintProposalPlugin; + use StarcoinFramework::Account; + use StarcoinFramework::Signer; + use StarcoinFramework::Token; + use StarcoinFramework::DAOSpace; + + fun main(sender: signer) { + let proposal_id = 1; + let proposal_state = DAOSpace::proposal_state(proposal_id); + assert!(proposal_state == 6, 106); // DAOSpace::EXECUTABLE + + let addr = Signer::address_of(&sender); + MintProposalPlugin::execute_mint_proposal(sender, proposal_id); + let balance = Account::balance(addr); + assert!(balance == 100000, 107); + assert!(Token::market_cap() == balance, 108); + } +} \ No newline at end of file diff --git a/sources/daospace/DAOSpace.move b/sources/daospace/DAOSpace.move index 2658a37e..d05a006b 100644 --- a/sources/daospace/DAOSpace.move +++ b/sources/daospace/DAOSpace.move @@ -29,6 +29,7 @@ module StarcoinFramework::DAOSpace { const ERR_STORAGE_ERROR: u64 = 103; const ERR_NFT_ERROR: u64 = 104; const ERR_ALREADY_INIT: u64 = 105; + const ERR_TOKEN_ERROR: u64 = 106; /// member const ERR_EXPECT_MEMBER: u64 = 200; @@ -104,14 +105,26 @@ module StarcoinFramework::DAOSpace { cap: DAOAccountCap, } - struct DAOTokenMintCapHolder has key { + /// Capability for minting SBT. + struct DAOSBTMintCapHolder has key { cap: Token::MintCapability, } - struct DAOTokenBurnCapHolder has key { + /// Capability for burning SBT. + struct DAOSBTBurnCapHolder has key { cap: Token::BurnCapability, } + /// Capability for minting any tokens. + struct DAOTokenMintCapHolder has key { + cap: Token::MintCapability, + } + + /// Capability for burning any tokens. + struct DAOTokenBurnCapHolder has key { + cap: Token::BurnCapability, + } + struct DAONFTMintCapHolder has key { cap: NFT::MintCapability>, } @@ -135,35 +148,41 @@ module StarcoinFramework::DAOSpace { /// A type describing a capability. struct CapType has copy, drop, store { code: u8 } - /// Creates a install plugin capability type. + /// Create a install plugin capability type. public fun install_plugin_cap_type(): CapType { CapType{ code: 0 } } - /// Creates a upgrade module capability type. + /// Create a upgrade module capability type. public fun upgrade_module_cap_type(): CapType { CapType{ code: 1 } } - /// Creates a modify dao config capability type. + /// Create a modify dao config capability type. public fun modify_config_cap_type(): CapType { CapType{ code: 2 } } - /// Creates a withdraw Token capability type. + /// Create a withdraw Token capability type. public fun withdraw_token_cap_type(): CapType { CapType{ code: 3 } } - /// Creates a withdraw NFT capability type. + /// Create a withdraw NFT capability type. public fun withdraw_nft_cap_type(): CapType { CapType{ code: 4 } } - /// Creates a write data to DAO account capability type. + /// Create a write data to DAO account capability type. public fun storage_cap_type(): CapType { CapType{ code: 5 } } - /// Creates a member capability type. + /// Create a member capability type. /// This cap can issue DAO member NFT or update member's SBT public fun member_cap_type(): CapType { CapType{ code: 6 } } - /// Creates a vote capability type. + /// Create a vote capability type. public fun proposal_cap_type(): CapType { CapType{ code: 7 } } - /// Creates a grant capability type. + /// Create a grant capability type. public fun grant_cap_type(): CapType { CapType{ code: 8 } } - /// Creates all capability types. + /// Create a token minting capability type. + public fun token_mint_cap_type(): CapType { CapType{code: 9 } } + + /// Create a token burning capability type. + public fun token_burn_cap_type(): CapType { CapType{code: 10 } } + + /// Create all capability types. public fun all_caps(): vector { let caps = Vector::singleton(install_plugin_cap_type()); Vector::push_back(&mut caps, upgrade_module_cap_type()); @@ -252,10 +271,10 @@ module StarcoinFramework::DAOSpace { let token_mint_cap = Token::remove_mint_capability(&dao_signer); let token_burn_cap = Token::remove_burn_capability(&dao_signer); - move_to(&dao_signer, DAOTokenMintCapHolder{ + move_to(&dao_signer, DAOSBTMintCapHolder{ cap: token_mint_cap, }); - move_to(&dao_signer, DAOTokenBurnCapHolder{ + move_to(&dao_signer, DAOSBTBurnCapHolder{ cap: token_burn_cap, }); @@ -483,7 +502,7 @@ module StarcoinFramework::DAOSpace { // Membership function /// Join DAO and get a membership - public fun join_member(_cap: &DAOMemberCap, to_address: address, image_data:Option::Option>, image_url:Option::Option>, init_sbt: u128) acquires DAONFTMintCapHolder, DAOTokenMintCapHolder, DAO, MemberEvent { + public fun join_member(_cap: &DAOMemberCap, to_address: address, image_data:Option::Option>, image_url:Option::Option>, init_sbt: u128) acquires DAONFTMintCapHolder, DAOSBTMintCapHolder, DAO, MemberEvent { ensure_not_member(to_address); let member_id = next_member_id(); @@ -493,7 +512,7 @@ module StarcoinFramework::DAOSpace { let dao_address = dao_address(); - let token_mint_cap = &borrow_global_mut>(dao_address).cap; + let token_mint_cap = &borrow_global_mut>(dao_address).cap; let sbt = Token::mint_with_capability(token_mint_cap, init_sbt); let body = DAOMemberBody{ @@ -525,12 +544,12 @@ module StarcoinFramework::DAOSpace { } /// Member quit DAO by self - public (script) fun quit_member_entry(sender: signer) acquires DAONFTBurnCapHolder, DAOTokenBurnCapHolder, MemberEvent, DAO { + public (script) fun quit_member_entry(sender: signer) acquires DAONFTBurnCapHolder, DAOSBTBurnCapHolder, MemberEvent, DAO { quit_member(&sender); } /// Member quit DAO by self - public fun quit_member(sender: &signer) acquires DAONFTBurnCapHolder, DAOTokenBurnCapHolder, MemberEvent, DAO { + public fun quit_member(sender: &signer) acquires DAONFTBurnCapHolder, DAOSBTBurnCapHolder, MemberEvent, DAO { let member_addr = Signer::address_of(sender); let (member_id , sbt) = do_remove_member(member_addr); let dao_address = dao_address(); @@ -545,7 +564,7 @@ module StarcoinFramework::DAOSpace { } /// Revoke membership with cap - public fun revoke_member(_cap: &DAOMemberCap, member_addr: address) acquires DAONFTBurnCapHolder, DAOTokenBurnCapHolder, MemberEvent, DAO { + public fun revoke_member(_cap: &DAOMemberCap, member_addr: address) acquires DAONFTBurnCapHolder, DAOSBTBurnCapHolder, MemberEvent, DAO { let (member_id , sbt) = do_remove_member(member_addr); let dao_address = dao_address(); @@ -566,7 +585,7 @@ module StarcoinFramework::DAOSpace { assert!(!is_member(member_addr), Errors::invalid_state(ERR_EXPECT_NOT_MEMBER)); } - fun do_remove_member(member_addr: address):(u64,u128) acquires DAONFTBurnCapHolder, DAOTokenBurnCapHolder { + fun do_remove_member(member_addr: address):(u64,u128) acquires DAONFTBurnCapHolder, DAOSBTBurnCapHolder { ensure_member(member_addr); let dao_address = dao_address(); @@ -575,13 +594,13 @@ module StarcoinFramework::DAOSpace { let member_id = NFT::get_type_meta, DAOMemberBody>(&nft).id; let DAOMemberBody{ sbt } = NFT::burn_with_cap(nft_burn_cap, nft); let sbt_amount = Token::value(&sbt); - let token_burn_cap = &mut borrow_global_mut>(dao_address).cap; + let token_burn_cap = &mut borrow_global_mut>(dao_address).cap; Token::burn_with_capability(token_burn_cap, sbt); (member_id, sbt_amount) } /// Increment the member SBT - public fun increase_member_sbt(_cap: &DAOMemberCap, member_addr: address, amount: u128) acquires DAONFTUpdateCapHolder, DAOTokenMintCapHolder, MemberEvent { + public fun increase_member_sbt(_cap: &DAOMemberCap, member_addr: address, amount: u128) acquires DAONFTUpdateCapHolder, DAOSBTMintCapHolder, MemberEvent { ensure_member(member_addr); let dao_address = dao_address(); @@ -592,7 +611,7 @@ module StarcoinFramework::DAOSpace { let body = NFT::borrow_body_mut_with_cap(nft_update_cap, nft); - let token_mint_cap = &mut borrow_global_mut>(dao_address).cap; + let token_mint_cap = &mut borrow_global_mut>(dao_address).cap; let increase_sbt = Token::mint_with_capability(token_mint_cap, amount); Token::deposit(&mut body.sbt, increase_sbt); @@ -609,7 +628,7 @@ module StarcoinFramework::DAOSpace { } /// Decrement the member SBT - public fun decrease_member_sbt(_cap: &DAOMemberCap, member_addr: address, amount: u128) acquires DAONFTUpdateCapHolder, DAOTokenBurnCapHolder, MemberEvent { + public fun decrease_member_sbt(_cap: &DAOMemberCap, member_addr: address, amount: u128) acquires DAONFTUpdateCapHolder, DAOSBTBurnCapHolder, MemberEvent { ensure_member(member_addr); let dao_address = dao_address(); @@ -620,7 +639,7 @@ module StarcoinFramework::DAOSpace { let body = NFT::borrow_body_mut_with_cap(nft_update_cap, nft); - let token_burn_cap = &mut borrow_global_mut>(dao_address).cap; + let token_burn_cap = &mut borrow_global_mut>(dao_address).cap; let decrease_sbt = Token::withdraw(&mut body.sbt, amount); let sbt_amount = Token::value(&body.sbt); @@ -1030,6 +1049,51 @@ module StarcoinFramework::DAOSpace { DAOGrantCap{} } + /// Delegate the token mint capability to DAO + /// _witness parameter ensures that the caller is the module which define PluginT + public fun delegate_token_mint_cap(cap: Token::MintCapability, _witness: &PluginT) + acquires DAOAccountCapHolder { + let dao_signer = dao_signer(); + move_to>( + &dao_signer, + DAOTokenMintCapHolder { cap }, + ); + } + + /// Delegate the token burn capability to DAO + /// _witness parameter ensures that the caller is the module which define PluginT + public fun delegate_token_burn_cap(cap: Token::BurnCapability, _witness: &PluginT) + acquires DAOAccountCapHolder { + let dao_signer = dao_signer(); + move_to>( + &dao_signer, + DAOTokenBurnCapHolder { cap }, + ); + } + + /// Mint token + public fun mint_token(amount: u128, _witness: &PluginT): Token + acquires InstalledPluginInfo, DAOTokenMintCapHolder { + validate_cap(token_mint_cap_type()); + let dao_addr = dao_address(); + assert!(exists>(dao_addr), Errors::not_published(ERR_TOKEN_ERROR)); + let DAOTokenMintCapHolder { cap } = + borrow_global>(dao_addr); + let tokens = Token::mint_with_capability(cap, amount); + tokens + } + + /// Burn token + public fun burn_token(tokens: Token, _witness: &PluginT) + acquires InstalledPluginInfo, DAOTokenBurnCapHolder { + validate_cap(token_burn_cap_type()); + let dao_addr = dao_address(); + assert!(exists>(dao_addr), Errors::not_published(ERR_TOKEN_ERROR)); + let DAOTokenBurnCapHolder { cap } = + borrow_global>(dao_addr); + Token::burn_with_capability(cap, tokens); + } + /// Proposal /// -------------------------------------------------- /// Proposal state diff --git a/sources/daospaceplugin/MintProposalPlugin.move b/sources/daospaceplugin/MintProposalPlugin.move new file mode 100644 index 00000000..62f0e2aa --- /dev/null +++ b/sources/daospaceplugin/MintProposalPlugin.move @@ -0,0 +1,61 @@ +module StarcoinFramework::MintProposalPlugin{ + use StarcoinFramework::DAOSpace::{Self, CapType}; + use StarcoinFramework::Signer; + use StarcoinFramework::Errors; + use StarcoinFramework::Vector; + use StarcoinFramework::InstallPluginProposalPlugin; + use StarcoinFramework::Token; + use StarcoinFramework::Account; + + struct MintProposalPlugin has store, drop{} + + /// MintToken request. + struct MintTokenAction has copy, drop, store { + /// the receiver of minted tokens. + receiver: address, + /// how many tokens to mint. + amount: u128, + } + + public fun required_caps():vector{ + let caps = Vector::singleton(DAOSpace::proposal_cap_type()); + Vector::push_back(&mut caps, DAOSpace::token_mint_cap_type()); + caps + } + + const ERR_NOT_RECEIVER :u64 = 101; + const ERR_NO_MINT_CAP: u64 = 102; + + public fun delegate_token_mint_cap(sender: &signer) { + let witness = MintProposalPlugin {}; + let mint_cap = Token::remove_mint_capability(sender); + DAOSpace::delegate_token_mint_cap(mint_cap, &witness); + } + + public (script) fun delegate_token_mint_cap_entry(sender: signer) { + delegate_token_mint_cap(&sender); + } + + public (script) fun create_mint_proposal(sender: signer, description: vector, receiver: address, amount: u128, action_delay: u64){ + let witness = MintProposalPlugin{}; + let cap = DAOSpace::acquire_proposal_cap(&witness); + let action = MintTokenAction{ + receiver, + amount, + }; + DAOSpace::create_proposal(&cap, &sender, action, description, action_delay); + } + + public (script) fun execute_mint_proposal(sender: signer, proposal_id: u64){ + let witness = MintProposalPlugin{}; + let proposal_cap = DAOSpace::acquire_proposal_cap(&witness); + let MintTokenAction{receiver, amount} = DAOSpace::execute_proposal>(&proposal_cap, &sender, proposal_id); + assert!(receiver == Signer::address_of(&sender),Errors::not_published(ERR_NOT_RECEIVER)); + let tokens = DAOSpace::mint_token(amount, &witness); + Account::deposit(receiver, tokens); + } + + public (script) fun install_plugin_proposal(sender:signer, description: vector, action_delay:u64){ + InstallPluginProposalPlugin::create_proposal(&sender, required_caps(), description, action_delay); + } +} \ No newline at end of file