diff --git a/build/StarcoinFramework/BuildInfo.yaml b/build/StarcoinFramework/BuildInfo.yaml index 2ffe0425..3712f387 100644 --- a/build/StarcoinFramework/BuildInfo.yaml +++ b/build/StarcoinFramework/BuildInfo.yaml @@ -321,7 +321,7 @@ compiled_package_info: ? address: "0x00000000000000000000000000000001" name: YieldFarmingV2 : StarcoinFramework - source_digest: 1D12C56D29AC46078A871B5A02F4E3AA760DED30C97624E676DD2F230B194B2E + source_digest: C418E52E298E7210FDE1B8940380A857EC8FD1C313530D80EC6BCD9F4A547033 build_flags: dev_mode: false test_mode: false diff --git a/integration-tests/starcoin_dao/starcoin_onchain_config.exp b/integration-tests/starcoin_dao/starcoin_onchain_config.exp index eb506a4a..3494ac28 100644 --- a/integration-tests/starcoin_dao/starcoin_onchain_config.exp +++ b/integration-tests/starcoin_dao/starcoin_onchain_config.exp @@ -1,4 +1,4 @@ -processed 41 tasks +processed 42 tasks task 11 'run'. lines 23-37: { @@ -90,8 +90,24 @@ task 38 'run'. lines 219-228: "status": "Executed" } -task 40 'run'. lines 232-247: +task 40 'run'. lines 232-248: { - "gas_used": 444489, + "gas_used": 496864, "status": "Executed" } + +task 41 'run'. lines 250-261: +{ + "gas_used": 164164, + "status": { + "MoveAbort": { + "location": { + "Module": { + "address": "0x00000000000000000000000000000001", + "name": "DAOSpace" + } + }, + "abort_code": "103175" + } + } +} diff --git a/integration-tests/starcoin_dao/starcoin_onchain_config.move b/integration-tests/starcoin_dao/starcoin_onchain_config.move index 91a2547c..b438ac24 100644 --- a/integration-tests/starcoin_dao/starcoin_onchain_config.move +++ b/integration-tests/starcoin_dao/starcoin_onchain_config.move @@ -239,9 +239,23 @@ script{ fun execute_proposal(sender: signer){ assert!(DAOSpace::proposal_state(1) == 7 , 103); ConfigProposalPlugin::execute_proposal(&sender, 1); + assert!(DAOSpace::proposal_state(1) == 8 , 104); assert!(RewardConfig::reward_delay() == 5, 105); } } -// check: EXECUTED \ No newline at end of file +// check: EXECUTED + +//# run --signers alice +script{ + use StarcoinFramework::DAOSpace; + use StarcoinFramework::StarcoinDAO::StarcoinDAO; + + fun execute_proposal(sender: signer){ + assert!(DAOSpace::proposal_state(1) == 8 , 104); + DAOSpace::clean_proposal_by_id(&sender, 1); + let _ = DAOSpace::proposal(1); + } +} +// check: ABORT, code 103175, proposal 1 not exist. \ No newline at end of file diff --git a/integration-tests/starcoin_dao/starcoin_upgrade_module.exp b/integration-tests/starcoin_dao/starcoin_upgrade_module.exp index 2f2f95a9..95f663a4 100644 --- a/integration-tests/starcoin_dao/starcoin_upgrade_module.exp +++ b/integration-tests/starcoin_dao/starcoin_upgrade_module.exp @@ -1,4 +1,4 @@ -processed 44 tasks +processed 45 tasks task 11 'run'. lines 23-37: { @@ -90,8 +90,24 @@ task 39 'run'. lines 227-236: "status": "Executed" } -task 41 'run'. lines 240-251: +task 41 'run'. lines 240-252: { - "gas_used": 467445, + "gas_used": 519740, "status": "Executed" } + +task 44 'run'. lines 258-269: +{ + "gas_used": 148462, + "status": { + "MoveAbort": { + "location": { + "Module": { + "address": "0x00000000000000000000000000000001", + "name": "DAOSpace" + } + }, + "abort_code": "103175" + } + } +} diff --git a/integration-tests/starcoin_dao/starcoin_upgrade_module.move b/integration-tests/starcoin_dao/starcoin_upgrade_module.move index bcba9a2a..8997ea21 100644 --- a/integration-tests/starcoin_dao/starcoin_upgrade_module.move +++ b/integration-tests/starcoin_dao/starcoin_upgrade_module.move @@ -246,6 +246,7 @@ script{ fun execute_proposal(sender: signer){ assert!(DAOSpace::proposal_state(1) == 7 , 103); UpgradeModulePlugin::execute_proposal(&sender, 1); + assert!(DAOSpace::proposal_state(1) == 8 , 104); } } // check: EXECUTED @@ -253,3 +254,16 @@ script{ //# block --author=0x3 --timestamp 93880000 //# deploy {{$.package[0].file}} --signers alice + +//# run --signers alice +script{ + use StarcoinFramework::DAOSpace; + use StarcoinFramework::StarcoinDAO::StarcoinDAO; + + fun execute_proposal(sender: signer){ + assert!(DAOSpace::proposal_state(1) == 8 , 104); + DAOSpace::clean_proposals(&sender); + let _ = DAOSpace::proposal(1); + } +} +// check: ABORT, code 103175, proposal 1 not exist. \ No newline at end of file diff --git a/sources/daospace/DAOSpace.move b/sources/daospace/DAOSpace.move index 1a089cf5..524e6e81 100644 --- a/sources/daospace/DAOSpace.move +++ b/sources/daospace/DAOSpace.move @@ -346,7 +346,6 @@ module StarcoinFramework::DAOSpace { proposal_create_event: Event::new_event_handle(&dao_signer), vote_event: Event::new_event_handle(&dao_signer), proposal_action_event: Event::new_event_handle(&dao_signer), - proposal_rejection_event: Event::new_event_handle(&dao_signer), }); // dao event emit @@ -1364,8 +1363,6 @@ module StarcoinFramework::DAOSpace { vote_event: Event::EventHandle, /// proposal action event. proposal_action_event: Event::EventHandle, - /// event when proposal is rejected. - proposal_rejection_event: Event::EventHandle, } /// emitted when proposal created. @@ -1403,13 +1400,8 @@ module StarcoinFramework::DAOSpace { proposal_id: u64, /// the sender. sender: address, - } - - /// emitted when proposal is rejected. - struct ProposalRejectionEvent has drop, store { - dao_id: u64, - proposal_id: u64, - sender: address, + /// proposal state after the action: EXTRACTED or REJECTED + state: u8, } /// propose a proposal. @@ -1703,7 +1695,10 @@ module StarcoinFramework::DAOSpace { let sender_addr = Signer::address_of(sender); assert!(exists>(dao_address), Errors::invalid_state(ERR_PROPOSAL_ACTIONS_NOT_EXIST)); - let (proposal, actionT, deposit) = take_proposal_action(dao_address, proposal_id); + let (actionT, deposit) = take_proposal_action(dao_address, proposal_id); + + let global_proposals = borrow_global_mut(dao_address); + let proposal = borrow_proposal(global_proposals, proposal_id); Account::deposit(proposal.proposer, deposit); @@ -1711,14 +1706,56 @@ module StarcoinFramework::DAOSpace { let dao_id = dao_id(dao_address); let proposal_event = borrow_global_mut>(dao_address); Event::emit_event(&mut proposal_event.proposal_action_event, - ProposalActionEvent { dao_id, proposal_id, sender: sender_addr } + ProposalActionEvent { dao_id, proposal_id, sender: sender_addr, state: EXTRACTED } ); actionT } - fun take_proposal_action(dao_address: address, proposal_id: u64): (Proposal, ActionT, Token) - acquires ProposalActions, GlobalProposals, GlobalProposalActions { + // Clean proposals that have been rejected or executed. + public fun clean_proposals(_sender: &signer) + acquires GlobalProposals, GlobalProposalActions { + let dao_address = dao_address(); + let global_proposals = borrow_global_mut(dao_address); + + let i = 0; + let len = Vector::length(&global_proposals.proposals); + while(i < len){ + let proposal = Vector::borrow(&global_proposals.proposals, i); + let state = proposal_state_with_proposal(proposal); + if (state == EXTRACTED || state == REJECTED) { + let _ = Vector::remove(&mut global_proposals.proposals, i); + len = len - 1; + } else { + i = i + 1; + } + }; + } + + public (script) fun clean_proposals_entry(sender: signer) + acquires GlobalProposals, GlobalProposalActions { + clean_proposals(&sender); + } + + // Clean specific proposal by proposal id, only for rejected or executed proposals + public fun clean_proposal_by_id(_sender: &signer, proposal_id: u64) + acquires GlobalProposals, GlobalProposalActions { + let dao_address = dao_address(); + let global_proposals = borrow_global_mut(dao_address); + let proposal = borrow_proposal(global_proposals, proposal_id); + let state = proposal_state_with_proposal(proposal); + assert!(state == EXTRACTED || state == REJECTED, Errors::invalid_state(ERR_PROPOSAL_STATE_INVALID)); + + let _ = remove_proposal(global_proposals, proposal_id); + } + + public (script) fun clean_proposal_by_id_entry(sender: signer, proposal_id: u64) + acquires GlobalProposals, GlobalProposalActions { + clean_proposal_by_id(&sender, proposal_id) + } + + fun take_proposal_action(dao_address: address, proposal_id: u64): (ActionT, Token) + acquires ProposalActions, GlobalProposalActions { let actions = borrow_global_mut>(dao_address); let index_opt = find_action(&actions.actions, proposal_id); assert!(Option::is_some(&index_opt), Errors::invalid_argument(ERR_ACTION_INDEX_INVALID)); @@ -1733,10 +1770,7 @@ module StarcoinFramework::DAOSpace { let propopsal_action_index = Option::extract(&mut proposal_action_index_opt); let ProposalActionIndex{ proposal_id:_,} = Vector::remove(&mut global_proposal_actions.proposal_action_indexs, propopsal_action_index); - let global_proposals = borrow_global_mut(dao_address); - let proposal = remove_proposal(global_proposals, proposal_id); - - (proposal, action, deposit) + (action, deposit) } fun remove_proposal(proposals: &mut GlobalProposals, proposal_id: u64): Proposal { @@ -1814,20 +1848,29 @@ module StarcoinFramework::DAOSpace { /// Proposals are rejected when their nowithveto option reaches a certain threshold /// A portion of the pledged tokens will be rewarded to the executor who executes the proposal - public fun reject_proposal(sender: &signer, proposal_id: u64) acquires ProposalActions, GlobalProposals, GlobalProposalActions{ + public fun reject_proposal(sender: &signer, proposal_id: u64) + acquires DAO, ProposalEvent, ProposalActions, GlobalProposals, GlobalProposalActions{ // Only REJECTED proposal's action can be burn token. assert!(proposal_state(proposal_id) == REJECTED, Errors::invalid_state(ERR_PROPOSAL_STATE_INVALID)); let dao_address = dao_address(); assert!(exists>(dao_address), Errors::invalid_state(ERR_PROPOSAL_ACTIONS_NOT_EXIST)); - let (_, _, token) = take_proposal_action(dao_address, proposal_id); + let (_, token) = take_proposal_action(dao_address, proposal_id); // Part of the token is awarded to whoever executes this method , TODO: 10 % let award_amount = Token::value(&token) / 10; let (burn_token , award_token) = Token::split(token, award_amount); Account::deposit(Signer::address_of(sender), award_token); STC::burn(burn_token); + + // emit event + let dao_id = dao_id(dao_address); + let proposal_event = borrow_global_mut>(dao_address); + Event::emit_event(&mut proposal_event.proposal_action_event, + ProposalActionEvent { dao_id, proposal_id, sender: Signer::address_of(sender), state: REJECTED } + ); } - public (script) fun reject_proposal_entry(sender: signer, proposal_id: u64) acquires ProposalActions, GlobalProposals, GlobalProposalActions{ + public (script) fun reject_proposal_entry(sender: signer, proposal_id: u64) + acquires DAO, ProposalEvent, ProposalActions, GlobalProposals, GlobalProposalActions{ reject_proposal(&sender, proposal_id); }