Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions src/components/dao_controller.cairo
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
#[starknet::component]
pub mod VotingComponent {
use AdminPermissionManagerComponent::AdminPermissionManagerInternalTrait;
use starknet::storage::{
Map, StoragePathEntry, StoragePointerReadAccess, StoragePointerWriteAccess,
};
use starknet::{ContractAddress, get_block_timestamp, get_caller_address};
// use crate::interfaces::icore::IConfig;
use crate::interfaces::dao_controller::IVote;
use crate::structs::admin_permissions::AdminPermission;
use crate::structs::dao_controller::{
Poll, PollCreated, PollReason, PollResolved, PollStatus, PollStopped, PollTrait,
ThresholdChanged, Voted, VotingConfig, VotingConfigNode,
};
use crate::structs::member_structs::{MemberRoleIntoU16, MemberTrait};
use super::super::admin_permission_manager::AdminPermissionManagerComponent;
use super::super::member_manager::MemberManagerComponent;

#[storage]
Expand Down Expand Up @@ -41,6 +44,7 @@ pub mod VotingComponent {
+HasComponent<TContractState>,
+Drop<TContractState>,
impl Member: MemberManagerComponent::HasComponent<TContractState>,
impl AdminPermissionManager: AdminPermissionManagerComponent::HasComponent<TContractState>,
> of IVote<ComponentState<TContractState>> {
// revamp
// add additional creator member details to the poll struct if necessary
Expand Down Expand Up @@ -140,8 +144,9 @@ pub mod VotingComponent {
let max_no_of_possible_approvals = max_possible_of_voters - poll.down_votes;

if max_no_of_possible_approvals < threshold {
let outcome = poll.resolve(threshold);
self.emit(PollResolved { id: poll_id, outcome, timestamp })
// Poll is rejected because it's impossible to reach threshold
poll.status = PollStatus::FINISHED(false);
self.emit(PollResolved { id: poll_id, outcome: false, timestamp })
}

self.has_voted.entry((caller, poll_id)).write(true);
Expand All @@ -153,14 +158,15 @@ pub mod VotingComponent {
fn set_threshold(
ref self: ComponentState<TContractState>, new_threshold: u256, member_id: u256,
) {
// Protect this with permissions later
let caller = get_caller_address();
let mc = get_dep_component!(@self, Member);
let member = mc.members.entry(member_id).member.read();
member.verify(caller);

let role_in_u16 = MemberRoleIntoU16::into(member.role);
assert(role_in_u16 >= self.min_role_for_executing.read(), 'Setter not qualified');
// Check if caller has admin permissions to change threshold
let admin_permission_manager = get_dep_component!(@self, AdminPermissionManager);
admin_permission_manager
.require_admin_permission(caller, AdminPermission::GRANT_PERMISSIONS);

let previous_threshold = self.generic_threshold.read();
self.generic_threshold.write(new_threshold);
Expand All @@ -175,7 +181,7 @@ pub mod VotingComponent {
fn get_all_polls(self: @ComponentState<TContractState>) -> Array<Poll> {
let mut poll_array = array![];

for i in 0..(self.no_of_polls.read() + 1) {
for i in 0..self.no_of_polls.read() {
let current_poll = self.polls.entry(i).read();
poll_array.append(current_poll);
}
Expand Down
41 changes: 34 additions & 7 deletions src/components/member_manager.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@
/// It also interacts with a factory contract to coordinate state across a broader system.
#[starknet::component]
pub mod MemberManagerComponent {
use AdminPermissionManagerComponent::AdminPermissionManagerInternalTrait;
use core::num::traits::Zero;
use littlefinger::components::admin_permission_manager::AdminPermissionManagerComponent;
use littlefinger::interfaces::ifactory::{IFactoryDispatcher, IFactoryDispatcherTrait};
// use littlefinger::interfaces::icore::IConfig;
use littlefinger::interfaces::imember_manager::IMemberManager;
use littlefinger::structs::admin_permissions::AdminPermission;
use littlefinger::structs::member_structs::{
InviteAccepted, InviteStatus, Member, MemberConfig, MemberConfigNode, MemberDetails,
MemberEnum, MemberInvite, MemberInvited, MemberNode, MemberResponse, MemberRole,
Expand Down Expand Up @@ -61,7 +64,9 @@ pub mod MemberManagerComponent {
/// Public-facing implementation of the `IMemberManager` interface.
#[embeddable_as(MemberManager)]
pub impl MemberManagerImpl<
TContractState, +HasComponent<TContractState>,
TContractState,
+HasComponent<TContractState>,
impl Admin: AdminPermissionManagerComponent::HasComponent<TContractState>,
> of IMemberManager<ComponentState<TContractState>> {
/// Adds a new member to the organization.
///
Expand All @@ -83,6 +88,10 @@ pub mod MemberManagerComponent {
// the function with their wallet actually.
// This means that we'll have to put verify_member to add to it
// Will have to find another means to hash the id, or not. Let us see how things go
let admin_permission_manager = get_dep_component!(@self, Admin);
admin_permission_manager
.require_admin_permission(get_caller_address(), AdminPermission::ADD_MEMBER);

let caller = get_caller_address();
let id: u256 = self.member_count.read() + 1;
assert(!caller.is_zero(), 'Zero Address Caller');
Expand Down Expand Up @@ -119,8 +128,11 @@ pub mod MemberManagerComponent {
/// ### Parameters
/// - `member_id`: ID of the member to promote
fn add_admin(ref self: ComponentState<TContractState>, member_id: u256) {
let caller = get_caller_address();
assert(self.admin_ca.entry(caller).read(), 'Caller Not an Admin');
let admin_permission_manager = get_dep_component!(@self, Admin);
admin_permission_manager
.require_admin_permission(
get_caller_address(), AdminPermission::GRANT_ADMIN_STATUS,
);
let member_node = self.members.entry(member_id);
let mut member = member_node.member.read();
// let old_role = member.role;
Expand Down Expand Up @@ -177,8 +189,11 @@ pub mod MemberManagerComponent {
fn update_member_base_pay(
ref self: ComponentState<TContractState>, member_id: u256, base_pay: u256,
) {
let caller = get_caller_address();
assert(self.admin_ca.entry(caller).read(), 'UNAUTHORIZED');
let admin_permission_manager = get_dep_component!(@self, Admin);
admin_permission_manager
.require_admin_permission(
get_caller_address(), AdminPermission::CHANGE_BASE_SALARIES,
);
let member_node = self.members.entry(member_id);
let mut member = member_node.member.read();
assert(member.is_member(), 'INVALID MEMBER ID');
Expand Down Expand Up @@ -208,6 +223,10 @@ pub mod MemberManagerComponent {
ref self: ComponentState<TContractState>,
member_id: u256 // suspension_duration: u64 //block timestamp operation
) {
let admin_permission_manager = get_dep_component!(@self, Admin);
admin_permission_manager
.require_admin_permission(get_caller_address(), AdminPermission::REMOVE_MEMBER);

let m = self.members.entry(member_id);
let mut member = m.member.read();
member.suspend();
Expand All @@ -219,6 +238,10 @@ pub mod MemberManagerComponent {
/// ### Parameters
/// - `member_id`: ID of the member
fn reinstate_member(ref self: ComponentState<TContractState>, member_id: u256) {
let admin_permission_manager = get_dep_component!(@self, Admin);
admin_permission_manager
.require_admin_permission(get_caller_address(), AdminPermission::ADD_MEMBER);

let mut member = self.members.entry(member_id).member.read();
member.reinstate();
self.members.entry(member_id).member.write(member);
Expand Down Expand Up @@ -261,8 +284,12 @@ pub mod MemberManagerComponent {
// For this protocol, the member must accept before other admins verify the member...
// this can only happen when the member config requires multisig.
// let id: u256 = (self.member_count.read() + 1).into();
let caller = get_caller_address();
assert(self.admin_ca.entry(caller).read(), 'UNAUTHORIZED CALLER');
let admin_permission_manager = get_dep_component!(@self, Admin);
admin_permission_manager
.require_admin_permission(
get_caller_address(), AdminPermission::SEND_MEMBER_INVITES,
);

assert(role <= 2 && role >= 0, 'Invalid Role');
let mut actual_role = MemberRole::EMPLOYEE(1);
if (role == 0) {
Expand Down
9 changes: 3 additions & 6 deletions src/components/organization.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
/// - Ownership transfers.
#[starknet::component]
pub mod OrganizationComponent {
use MemberManagerComponent::MemberInternalTrait;
use starknet::storage::{
Map, StoragePathEntry, StoragePointerReadAccess, StoragePointerWriteAccess,
};
Expand Down Expand Up @@ -110,9 +111,7 @@ pub mod OrganizationComponent {
expiry: Option<u64>,
) {
let member_component = get_dep_component!(@self, Member);
let caller = get_caller_address();
let is_admin = member_component.admin_ca.entry(caller).read();
assert(is_admin, 'Caller Not Permitted');
member_component.assert_admin();

let contract = Contract {
id: self.contract_counter.read().into(),
Expand All @@ -138,9 +137,7 @@ pub mod OrganizationComponent {
expiry: Option<u64>,
) {
let member_component = get_dep_component!(@self, Member);
let caller = get_caller_address();
let is_admin = member_component.admin_ca.entry(caller).read();
assert(is_admin, 'Caller Not Permitted');
member_component.assert_admin();

let contract = Contract {
id: self.contract_counter.read().into(),
Expand Down
37 changes: 33 additions & 4 deletions src/contracts/core.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,27 @@
/// - `OwnableComponent` and `UpgradeableComponent`: For access control and contract upgrades.
#[starknet::contract]
mod Core {
use AdminPermissionManagerComponent::AdminPermissionManagerInternalTrait;
use MemberManagerComponent::MemberInternalTrait;
use OrganizationComponent::OrganizationInternalTrait;
use littlefinger::components::admin_permission_manager::AdminPermissionManagerComponent;
use littlefinger::components::dao_controller::VotingComponent;
use littlefinger::components::disbursement::DisbursementComponent;
use littlefinger::components::member_manager::MemberManagerComponent;
use littlefinger::components::organization::OrganizationComponent;
use littlefinger::interfaces::icore::ICore;
use littlefinger::interfaces::ivault::{IVaultDispatcher, IVaultDispatcherTrait};
use littlefinger::structs::admin_permissions::AdminPermission;
use littlefinger::structs::disbursement_structs::ScheduleStatus;
// use littlefinger::structs::organization::{OrganizationConfig, OrganizationInfo, OwnerInit};
use littlefinger::structs::member_structs::MemberRoleIntoU16;
use openzeppelin::access::ownable::OwnableComponent;
use openzeppelin::upgrades::UpgradeableComponent;
use openzeppelin::upgrades::interface::IUpgradeable;
use starknet::storage::StoragePointerWriteAccess;
use starknet::{ClassHash, ContractAddress, get_block_timestamp, get_contract_address};
use starknet::{
ClassHash, ContractAddress, get_block_timestamp, get_caller_address, get_contract_address,
};
use crate::interfaces::imember_manager::IMemberManager;

component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);
Expand All @@ -38,6 +43,11 @@ mod Core {
component!(path: OrganizationComponent, storage: organization, event: OrganizationEvent);
component!(path: VotingComponent, storage: voting, event: VotingEvent);
component!(path: DisbursementComponent, storage: disbursement, event: DisbursementEvent);
component!(
path: AdminPermissionManagerComponent,
storage: admin_permission_manager,
event: AdminPermissionManagerEvent,
);

#[abi(embed_v0)]
impl MemberImpl = MemberManagerComponent::MemberManager<ContractState>;
Expand All @@ -49,15 +59,17 @@ mod Core {
OrganizationComponent::OrganizationManager<ContractState>;
#[abi(embed_v0)]
impl VotingImpl = VotingComponent::VotingImpl<ContractState>;
#[abi(embed_v0)]
impl AdminPermissionManagerImpl =
AdminPermissionManagerComponent::AdminPermissionManagerImpl<ContractState>;

#[abi(embed_v0)]
impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl<ContractState>;
impl OwnableInternalImpl = OwnableComponent::InternalImpl<ContractState>;

impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl<ContractState>;

impl DisbursementInternalImpl = DisbursementComponent::InternalImpl<ContractState>;


/// Defines the storage layout for the `Core` contract.
#[storage]
#[allow(starknet::colliding_storage_paths)]
Expand All @@ -81,7 +93,10 @@ mod Core {
voting: VotingComponent::Storage, //my component
/// Substorage for the Disbursement component.
#[substorage(v0)]
disbursement: DisbursementComponent::Storage //my component
disbursement: DisbursementComponent::Storage, //my component
/// Substorage for the AdminPermissionManager component.
#[substorage(v0)]
admin_permission_manager: AdminPermissionManagerComponent::Storage //my component
}

/// Events emitted by the `Core` contract, including events from all its components.
Expand All @@ -106,6 +121,9 @@ mod Core {
/// Emits disbursement-related events.
#[flat]
DisbursementEvent: DisbursementComponent::Event,
/// Emits admin permission manager-related events.
#[flat]
AdminPermissionManagerEvent: AdminPermissionManagerComponent::Event,
}

// #[derive(Drop, Copy, Serde)]
Expand Down Expand Up @@ -168,6 +186,7 @@ mod Core {
);
self.vault_address.write(vault_address);
self.disbursement._init(owner);
self.admin_permission_manager.initialize_admin_permissions(owner);
self.ownable.initializer(owner);
}

Expand Down Expand Up @@ -209,6 +228,12 @@ mod Core {
end: u64,
interval: u64,
) {
self
.admin_permission_manager
.require_admin_permission(
get_caller_address(), AdminPermission::SET_DISBURSEMENT_SCHEDULES,
);

self.disbursement._initialize(schedule_type, start, end, interval)
}

Expand All @@ -224,6 +249,10 @@ mod Core {
/// - If the payout is attempted before the required interval has passed since the last
/// execution.
fn schedule_payout(ref self: ContractState, token: ContractAddress) {
self
.admin_permission_manager
.require_admin_permission(get_caller_address(), AdminPermission::PAY_MEMBERS);

let members = self.member.get_members();
let no_of_members = members.len();

Expand Down
Loading
Loading