Skip to content

Commit

Permalink
fix: enhanced process_result proposal call (#491)
Browse files Browse the repository at this point in the history
* fix: minor refactor

* feat: enhanced process_result calldata

* fix: optimized calldata storage

* fix: minor fix
  • Loading branch information
Birdmannn authored Feb 16, 2025
1 parent dead259 commit 7bb0405
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 20 deletions.
61 changes: 42 additions & 19 deletions onchain/cairo/afk/src/dao/dao_aa.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,14 @@ pub mod DaoAA {
MIN_TRANSACTION_VERSION, QUERY_OFFSET, execute_calls // is_valid_stark_signature
};
use core::ecdsa::check_ecdsa_signature;
use core::hash::{HashStateExTrait, HashStateTrait};
use core::num::traits::Zero;
use core::poseidon::{PoseidonTrait, poseidon_hash_span};
use openzeppelin::access::accesscontrol::AccessControlComponent;
use openzeppelin::governance::timelock::TimelockControllerComponent;
use openzeppelin::introspection::src5::SRC5Component;
use openzeppelin::upgrades::upgradeable::UpgradeableComponent;
use openzeppelin::utils::cryptography::snip12::StructHash;
use starknet::account::Call;

use starknet::storage::{
Expand Down Expand Up @@ -104,16 +107,15 @@ pub mod DaoAA {
proposals_calldata: Map<u256, Calldata>, // Map ProposalID => calldata
proposal_by_user: Map<ContractAddress, u256>,
total_proposal: u256,
executable_tx: Map<felt252, bool>, // Map Hashed Call => executable
proposal_tx: Map<
u256, felt252
>, // Map Proposal ID => Hashed Call (for one call, multicall excluded)
vote_state_by_proposal: Map<u256, VoteState>, // Map ProposalID => VoteState
// vote_by_proposal: Map<u256, Proposal>,
tx_data_per_proposal: Map<u256, Span<felt252>>, //
starknet_address: felt252,
proposals_call_external:Map<u256, Vec<Call>>, // Map ProposalID => calldata

tx_to_execute: Map<u256, Span<felt252>>, // Map ProposalID => TX to execute
tx_executed: Map<u256, Span<felt252>>, // Map ProposalID => TX to execute
tx_call_to_execute: Map<u256, Span<Call>>, // Map ProposalID => TX to execute
tx_call_executed: Map<u256, Span<Call>>, // Map ProposalID => TX to execute
executables_count: u64,
// votes_by_proposal: Map<u256, u256>, // Maps proposal ID to vote count
// here
// user_votes: Map<
Expand Down Expand Up @@ -229,17 +231,21 @@ pub mod DaoAA {
proposal_result_by: contract_address_const::<0x0>(),
};

// check
self.proposals.entry(id).write(Option::Some(proposal));

let proposal_calldata = self.proposals_calldata.entry(id);

proposal_calldata.to.write(calldata.to);
proposal_calldata.selector.write(calldata.selector);
proposal_calldata.is_executed.write(false);

for data in calldata.calldata {
proposal_calldata.calldata.append().write(*data);
};
// end check.

self.proposal_tx.entry(id).write(calldata.hash_struct());
self.total_proposal.write(id);
self.emit(ProposalCreated { id, owner, created_at, end_at });

Expand Down Expand Up @@ -386,20 +392,12 @@ pub mod DaoAA {
let total_votes = yes_votes + no_votes;
let valid_threshold_percentage = yes_votes * 100 / total_votes;

let executables_count = self.executables_count.read();
if valid_threshold_percentage >= self.minimum_threshold_percentage.read() {
proposal.proposal_result = ProposalResult::Passed;
// let proposal_calldata = self.proposals_calldata.entry(proposal_id);

// let tx_to_execute = self.tx_to_execute.read(proposal_id);
// for i in 0
// ..proposal_calldata
// .len() {
// let data = *calldata.at(i);
// tx_to_execute.append().write(data);
// };
// tx_call_to_execute: Map<u256, Span<Call>>, // Map ProposalID => TX to execute


let proposal_tx = self.proposal_tx.entry(proposal_id).read();
self.executable_tx.entry(proposal_tx).write(true);
self.executables_count.write(executables_count + 1);
} else {
proposal.proposal_result = ProposalResult::Failed;
}
Expand All @@ -412,6 +410,22 @@ pub mod DaoAA {
);
self.proposals.entry(proposal_id).write(Option::Some(proposal));
}

fn is_executable(ref self: ContractState, calldata: Call) -> bool {
self.executable_tx.entry(calldata.hash_struct()).read()
}
}

pub impl CallStructHash of StructHash<Call> {
fn hash_struct(self: @Call) -> felt252 {
let hash_state = PoseidonTrait::new();
hash_state
.update_with('AFK_DAO')
.update_with(*self.to)
.update_with(*self.selector)
.update_with(poseidon_hash_span(*self.calldata))
.finalize()
}
}

#[abi(embed_v0)]
Expand Down Expand Up @@ -617,7 +631,9 @@ mod tests {
calldata: array!['data 1', 'data 2'].span()
};
// created by 'CREATOR'
proposal_dispatcher.create_proposal(proposal_params, calldata)
let proposal_id = proposal_dispatcher.create_proposal(proposal_params, calldata);
assert(!proposal_dispatcher.is_executable(calldata), '');
proposal_id
}

/// TESTS
Expand Down Expand Up @@ -843,5 +859,12 @@ mod tests {
);

spy.assert_emitted(@array![(proposal_contract, expected_event)]);
let calldata = Call {
to: contract_address_const::<'TO'>(),
selector: 'selector',
calldata: array!['data 1', 'data 2'].span()
};
// the creating call should be executable
assert(proposal_dispatcher.is_executable(calldata), 'NOT EXECUTABLE');
}
}
4 changes: 3 additions & 1 deletion onchain/cairo/afk/src/interfaces/voting.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ pub struct Calldata {
pub to: ContractAddress,
pub selector: felt252,
pub calldata: Vec<felt252>,
pub is_executed: bool
pub is_executed: bool,
}

// #[derive(Drop, Serde, Copy, starknet::Store, PartialEq)]
Expand Down Expand Up @@ -181,6 +181,8 @@ pub trait IVoteProposal<TContractState> {
fn get_user_vote(self: @TContractState, proposal_id: u256, user: ContractAddress) -> UserVote;
fn cancel_proposal(ref self: TContractState, proposal_id: u256);
fn process_result(ref self: TContractState, proposal_id: u256);
// debugging
fn is_executable(ref self: TContractState, calldata: Call) -> bool;
}
// Possible extracted Proposal Functions
// Mint the token with a specific ratio
Expand Down

0 comments on commit 7bb0405

Please sign in to comment.