Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/init aa dao #468

Merged
merged 3 commits into from
Feb 5, 2025
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
3 changes: 2 additions & 1 deletion apps/mobile/src/screens/Feed/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,8 @@ export const Feed: React.FC<FeedScreenProps> = ({navigation}) => {
// </>
// }
contentContainerStyle={styles.flatListContent}
data={filteredNotes}
data={feedData}
// data={filteredNotes}
keyExtractor={(item) => item?.id}
renderItem={({item}) => {
if (item.kind === NDKKind.ChannelCreation || item.kind === NDKKind.ChannelMetadata) {
Expand Down
162 changes: 162 additions & 0 deletions onchain/cairo/afk/src/components/voting_proposal.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
use afk::types::defi_types::{TokenPermitted, DepositUser, MintDepositEvent, WithdrawDepositEvent};
use starknet::ContractAddress;

// TODO
// Create the as a Vault component
#[starknet::component]
pub mod VoteComponent {
use afk::interfaces::erc20_mintable::{IERC20MintableDispatcher, IERC20MintableDispatcherTrait};
use afk::interfaces::voting_proposal::{IVoteProposal, Proposal, ProposalStatus, ProposalType, UserVote, VoteState};
use afk::tokens::erc20::{ERC20, IERC20, IERC20Dispatcher, IERC20DispatcherTrait};
use afk::types::constants::{MINTER_ROLE, ADMIN_ROLE};
use core::num::traits::Zero;

use openzeppelin::access::accesscontrol::AccessControlComponent;
use openzeppelin::introspection::src5::SRC5Component;
use starknet::event::EventEmitter;
use starknet::storage::{
Map, StorageMapReadAccess, StorageMapWriteAccess, // Stor
StoragePointerReadAccess,StoragePointerWriteAccess,
StoragePathEntry,
// MutableEntryStoragePathEntry, StorableEntryReadAccess, StorageAsPathReadForward,
// MutableStorableEntryReadAccess, MutableStorableEntryWriteAccess,
// StorageAsPathWriteForward,PathableStorageEntryImpl
};

use starknet::{
ContractAddress, get_caller_address, contract_address_const, get_block_timestamp,
get_contract_address, ClassHash
};
use super::{DepositUser, TokenPermitted, MintDepositEvent, WithdrawDepositEvent};


component!(path: AccessControlComponent, storage: accesscontrol, event: AccessControlEvent);
component!(path: SRC5Component, storage: src5, event: SRC5Event);

// AccessControl
#[abi(embed_v0)]
impl AccessControlImpl =
AccessControlComponent::AccessControlImpl<ComponentState<TContractState>>;
impl AccessControlInternalImpl = AccessControlComponent::InternalImpl<ComponentState<TContractState>>;

#[storage]
struct Storage {
proposals: Map<u256, Proposal>,
proposal_by_user: Map<ContractAddress, u256>,
total_proposal:u256,
vote_state_by_proposal: Map<u256, VoteState>,
vote_by_proposal: Map<u256, Proposal>,
#[substorage(v0)]
accesscontrol: AccessControlComponent::Storage,
#[substorage(v0)]
src5: SRC5Component::Storage,
}


#[constructor]
fn constructor(
ref self: ComponentState<TContractState>, token_address: ContractAddress, admin: ContractAddress
) {
// Give MINTER role to the Vault for the token used
self.total_proposal.write(0);
// self.token_address.write(token_address);
// self.accesscontrol.initializer();
// self.accesscontrol._grant_role(ADMIN_ROLE, admin);
// self.accesscontrol._grant_role(MINTER_ROLE, admin);
}

#[event]
#[derive(Drop, starknet::Event)]
pub enum Event {
MintDepositEvent: MintDepositEvent,
WithdrawDepositEvent: WithdrawDepositEvent,
#[flat]
AccessControlEvent: AccessControlComponent::Event,
#[flat]
SRC5Event: SRC5Component::Event,
}

#[embeddable_as(Vote)]
impl VoteImpl<
TContractState, +HasComponent<TContractState>
> of super::IVoteProposal<ComponentState<TContractState>> {

fn create_proposal(ref self: ComponentState<TContractState>, proposal:Proposal) {

let caller = get_caller_address();
let proposal_id = self.total_proposal.read();
self.total_proposal.write(proposal_id + 1);
self.proposals.entry(proposal_id).write(proposal);

let vote_state = VoteState {
votes_by_proposal: Map::new(),
user_votes: Map::new(),
has_voted: Map::new(),
};
self.proposal_by_user.entry(caller).write(proposal_id);
self.vote_state_by_proposal.entry(proposal_id).write(vote_state);
}

fn cast_vote_type(ref self: ComponentState<TContractState>, proposal_id: u256, vote: UserVote) {
let caller = get_caller_address();
self.vote_by_proposal.entry(proposal_id).write(vote);
self.user_votes.entry(caller).write(proposal_id);
self.has_voted.entry(caller).write(true);
self.user_vote_type.entry(caller).write(vote);
}

fn cast_vote(ref self: ComponentState<TContractState>, proposal_id: u256, vote: u64) {
let caller = get_caller_address();
self.vote_by_proposal.entry(proposal_id).write(vote);
self.user_votes.entry(caller).write(proposal_id);
self.has_voted.entry(caller).write(true);

let mut vote_state = self.vote_state_by_proposal.read(proposal_id);

vote_state.user_votes.entry(caller).write(vote);
vote_state.has_voted.entry(caller).write(true);
// vote_state.votes_by_proposal.entry(vote).write(vote_state.votes_by_proposal.read(vote) + 1);

self.vote_state_by_proposal.entry(proposal_id).write(vote_state);
self.user_vote_type.entry(caller).write(vote);
}

fn get_vote_state(ref self: ComponentState<TContractState>, proposal_id: u256) -> VoteState {
let caller = get_caller_address();
self.vote_by_proposal.read(proposal_id)
}

fn get_proposal(ref self: ComponentState<TContractState>, proposal_id: u256) -> Proposal {
let caller = get_caller_address();
self.proposals.read(proposal_id)
}

fn get_user_vote(ref self: ComponentState<TContractState>, proposal_id: u256, user:ContractAddress) -> UserVote {
let caller = get_caller_address();
self.vote_by_proposal.read(proposal_id)
}



}
// Admin
// Add OPERATOR role to the Vault escrow
// #[external(v0)]
// fn set_control_role(
// ref self: TContractState, recipient: ContractAddress, role: felt252, is_enable: bool
// ) {
// self.accesscontrol.assert_only_role(ADMIN_ROLE);
// assert!(
// role == ADMIN_ROLE
// || role == OPERATOR_ROLE // Think and Add others roles needed on the protocol
// ,
// "role not enable"
// );
// if is_enable {
// self.accesscontrol._grant_role(role, recipient);
// } else {
// self.accesscontrol._revoke_role(role, recipient);
// }
// }

}
138 changes: 118 additions & 20 deletions onchain/cairo/afk/src/dao/dao_aa.cairo
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use starknet::account::Call;
// use starknet::{ContractAddress, get_caller_address, get_contract_address,
// contract_address_const};
use super::profile::NostrProfile;
use super::request::SocialRequest;
use super::transfer::Transfer;

use afk::profile::NostrProfile;
use afk::social::request::SocialRequest;
use afk::tokens::transfer::Transfer;

#[starknet::interface]
pub trait IDaoAA<TContractState> {
Expand Down Expand Up @@ -35,40 +34,77 @@ pub mod DaoAA {
use openzeppelin_access::accesscontrol::AccessControlComponent;
use openzeppelin_governance::timelock::TimelockControllerComponent;
use openzeppelin_introspection::src5::SRC5Component;
use starknet::ContractAddress;
use starknet::account::Call;
use afk::interfaces::voting::{IVoteProposal, Proposal, ProposalStatus, ProposalType, UserVote, VoteState};

use starknet::storage::{
StoragePointerReadAccess, StoragePointerWriteAccess, StoragePathEntry, Map
};
use starknet::{get_caller_address, get_contract_address, get_tx_info, ContractAddress};
use super::ISRC6;

use super::super::request::{
SocialRequest, SocialRequestImpl, SocialRequestTrait, Encode, Signature
use afk::bip340::{Signature, SchnorrSignature};
use afk::social::request::{
SocialRequest, SocialRequestImpl, SocialRequestTrait, Encode
};
use super::super::transfer::Transfer;
use afk::social::transfer::Transfer;
use super::{IDaoAADispatcher, IDaoAADispatcherTrait};

component!(path: AccessControlComponent, storage: access_control, event: AccessControlEvent);
component!(path: TimelockControllerComponent, storage: timelock, event: TimelockEvent);
// component!(path: TimelockControllerComponent, storage: timelock, event: TimelockEvent);
component!(path: SRC5Component, storage: src5, event: SRC5Event);

// Timelock Mixin
// AccessControl
#[abi(embed_v0)]
impl AccessControlImpl =
AccessControlComponent::AccessControlImpl<ContractState>;
impl AccessControlInternalImpl = AccessControlComponent::InternalImpl<ContractState>;

// Upgradeable
impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl<ContractState>;

// SRC5
#[abi(embed_v0)]
impl TimelockMixinImpl =
TimelockControllerComponent::TimelockMixinImpl<ContractState>;
impl TimelockInternalImpl = TimelockControllerComponent::InternalImpl<ContractState>;
impl SRC5Impl = SRC5Component::SRC5Impl<ContractState>;

// // Timelock Mixin
// #[abi(embed_v0)]
// impl TimelockMixinImpl =
// TimelockControllerComponent::TimelockMixinImpl<ContractState>;
// impl TimelockInternalImpl = TimelockControllerComponent::InternalImpl<ContractState>;

#[storage]
struct Storage {
#[key]
public_key: u256,
transfers: Map<u256, bool>,
proposals: Map<u256, Proposal>,
proposal_by_user: Map<ContractAddress, u256>,
total_proposal:u256,
vote_state_by_proposal: Map<u256, VoteState>,
vote_by_proposal: Map<u256, Proposal>,
// votes_by_proposal: Map<u256, u256>, // Maps proposal ID to vote count
user_votes: Map<(u256, ContractAddress), u64>, // Maps user address to proposal ID they voted for
has_voted: Map<(u256, ContractAddress), bool>,
user_vote_type: Map<(u256, ContractAddress), UserVote>,
#[substorage(v0)]
accesscontrol: AccessControlComponent::Storage,
#[substorage(v0)]
src5: SRC5Component::Storage,
#[substorage(v0)]
upgradeable: UpgradeableComponent::Storage
}

#[event]
#[derive(Drop, starknet::Event)]
enum Event {
AccountCreated: AccountCreated,
#[flat]
AccessControlEvent: AccessControlComponent::Event,
#[flat]
SRC5Event: SRC5Component::Event,
#[flat]
UpgradeableEvent: UpgradeableComponent::Event
}

#[derive(Drop, starknet::Event)]
Expand All @@ -80,6 +116,10 @@ pub mod DaoAA {
#[constructor]
fn constructor(ref self: ContractState, public_key: u256) {
self.public_key.write(public_key);
self.total_proposal.write(0);
// self.accesscontrol.initializer();
// self.accesscontrol._grant_role(ADMIN_ROLE, admin);
// self.accesscontrol._grant_role(MINTER_ROLE, admin);
self.emit(AccountCreated { public_key: public_key });
}

Expand All @@ -104,13 +144,71 @@ pub mod DaoAA {
"wrong recipient"
);

if let Option::Some(id) = request.verify() {
assert!(!self.transfers.read(id), "double spend");
self.transfers.entry(id).write(true);
erc20.transfer(request.content.recipient_address, request.content.amount);
} else {
panic!("can't verify signature");
}
// if let Option::Some(id) = request.verify() {
// assert!(!self.transfers.read(id), "double spend");
// self.transfers.entry(id).write(true);
// erc20.transfer(request.content.recipient_address, request.content.amount);
// } else {
// panic!("can't verify signature");
// }
}
}

#[abi(embed_v0)]
impl DaoAA of super::IVoteProposal<ContractState> {
fn create_proposal(ref self: ContractState, proposal:Proposal) {

let caller = get_caller_address();
let proposal_id = self.total_proposal.read();
self.total_proposal.write(proposal_id + 1);
self.proposals.entry(proposal_id).write(proposal);

let vote_state = VoteState {
votes_by_proposal: Map::new(),
user_votes: Map::new(),
has_voted: Map::new(),
};
self.proposal_by_user.entry(caller).write(proposal_id);
self.vote_state_by_proposal.entry(proposal_id).write(vote_state);
}

fn cast_vote_type(ref self: ContractState, proposal_id: u256, vote: UserVote) {
let caller = get_caller_address();
self.vote_by_proposal.entry(proposal_id).write(vote);
self.user_votes.entry(caller).write(proposal_id);
self.has_voted.entry(caller).write(true);
self.user_vote_type.entry(caller).write(vote);
}

fn cast_vote(ref self: ContractState, proposal_id: u256, vote: u64) {
let caller = get_caller_address();
self.vote_by_proposal.entry(proposal_id).write(vote);
self.user_votes.entry(caller).write(proposal_id);
self.has_voted.entry(caller).write(true);

let mut vote_state = self.vote_state_by_proposal.read(proposal_id);

vote_state.user_votes.entry(caller).write(vote);
vote_state.has_voted.entry(caller).write(true);
// vote_state.votes_by_proposal.entry(vote).write(vote_state.votes_by_proposal.read(vote) + 1);

self.vote_state_by_proposal.entry(proposal_id).write(vote_state);
self.user_vote_type.entry(caller).write(vote);
}

// fn get_vote_state(ref self: ContractState, proposal_id: u256) -> VoteState {
// let caller = get_caller_address();
// self.vote_by_proposal.read(proposal_id)
// }

fn get_proposal(ref self: ContractState, proposal_id: u256) -> Proposal {
let caller = get_caller_address();
self.proposals.read(proposal_id)
}

fn get_user_vote(ref self: ContractState, proposal_id: u256, user:ContractAddress) -> UserVote {
let caller = get_caller_address();
self.vote_by_proposal.read(proposal_id)
}
}

Expand Down
Loading
Loading