Skip to content

Commit 842186f

Browse files
authored
Merge pull request #71 from gidson5/gid-p-c
Added vote functionlities
2 parents d982874 + 1dbafb6 commit 842186f

File tree

4 files changed

+121
-62
lines changed

4 files changed

+121
-62
lines changed

src/campaign.cairo

+36-33
Original file line numberDiff line numberDiff line change
@@ -6,33 +6,36 @@ mod TokengiverCampaigns {
66
// IMPORT
77
// *************************************************************************
88
use core::traits::TryInto;
9+
use openzeppelin::access::ownable::OwnableComponent;
10+
use openzeppelin::token::erc20::interface::{IERC20Dispatcher, IERC20DispatcherTrait};
11+
use openzeppelin::upgrades::UpgradeableComponent;
12+
use openzeppelin::upgrades::interface::IUpgradeable;
13+
use starknet::class_hash::class_hash_const;
14+
use starknet::storage::{
15+
Map, StoragePathEntry, StoragePointerReadAccess, StoragePointerWriteAccess,
16+
};
17+
use starknet::syscalls::deploy_syscall;
918
use starknet::{
10-
ContractAddress, get_caller_address, get_block_timestamp, ClassHash, get_contract_address,
11-
contract_address_const, syscalls::deploy_syscall, SyscallResultTrait, syscalls,
12-
class_hash::class_hash_const,
13-
storage::{Map, StoragePathEntry, StoragePointerReadAccess, StoragePointerWriteAccess}
19+
ClassHash, ContractAddress, SyscallResultTrait, contract_address_const, get_block_timestamp,
20+
get_caller_address, get_contract_address, syscalls,
1421
};
15-
use tokengiver::interfaces::ITokenGiverNft::{
16-
ITokenGiverNftDispatcher, ITokenGiverNftDispatcherTrait
22+
use token_bound_accounts::interfaces::ILockable::{
23+
ILockableDispatcher, ILockableDispatcherTrait,
1724
};
18-
use tokengiver::interfaces::IRegistry::{
19-
IRegistryDispatcher, IRegistryDispatcherTrait, IRegistryLibraryDispatcher
25+
use tokengiver::base::errors::Errors::{
26+
INSUFFICIENT_BALANCE, NOT_CAMPAIGN_OWNER, NOT_CONTRACT_OWNER, TRANSFER_FAILED,
2027
};
28+
use tokengiver::base::types::Campaign;
29+
use tokengiver::interfaces::ICampaign::ICampaign;
2130
use tokengiver::interfaces::IERC721::{IERC721Dispatcher, IERC721DispatcherTrait};
2231
use tokengiver::interfaces::IGovernanceToken::{
23-
IGovernanceTokenDispatcher, IGovernanceTokenDispatcherTrait
32+
IGovernanceTokenDispatcher, IGovernanceTokenDispatcherTrait,
2433
};
25-
use tokengiver::interfaces::ICampaign::ICampaign;
26-
use tokengiver::base::types::Campaign;
27-
use tokengiver::base::errors::Errors::{
28-
NOT_CAMPAIGN_OWNER, INSUFFICIENT_BALANCE, TRANSFER_FAILED, NOT_CONTRACT_OWNER
34+
use tokengiver::interfaces::IRegistry::{
35+
IRegistryDispatcher, IRegistryDispatcherTrait, IRegistryLibraryDispatcher,
2936
};
30-
use openzeppelin::token::erc20::interface::{IERC20Dispatcher, IERC20DispatcherTrait};
31-
use openzeppelin::access::ownable::OwnableComponent;
32-
use openzeppelin::upgrades::UpgradeableComponent;
33-
use openzeppelin::upgrades::interface::IUpgradeable;
34-
use token_bound_accounts::interfaces::ILockable::{
35-
ILockableDispatcher, ILockableDispatcherTrait
37+
use tokengiver::interfaces::ITokenGiverNft::{
38+
ITokenGiverNftDispatcher, ITokenGiverNftDispatcherTrait,
3639
};
3740

3841
component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);
@@ -65,7 +68,7 @@ mod TokengiverCampaigns {
6568
donations: Map<ContractAddress, u256>,
6669
donation_count: Map<ContractAddress, u16>,
6770
donation_details: Map<
68-
(ContractAddress, ContractAddress), DonationDetails
71+
(ContractAddress, ContractAddress), DonationDetails,
6972
>, // map((), donation_details)
7073
campaign_nft_token: Map<ContractAddress, (ContractAddress, u256)>,
7174
strk_address: ContractAddress,
@@ -144,7 +147,7 @@ mod TokengiverCampaigns {
144147
token_giver_nft_class_hash: ClassHash,
145148
token_giver_nft_contract_address: ContractAddress,
146149
strk_address: ContractAddress,
147-
owner: ContractAddress
150+
owner: ContractAddress,
148151
) {
149152
self.token_giver_nft_class_hash.write(token_giver_nft_class_hash);
150153
self.token_giver_nft_contract_address.write(token_giver_nft_contract_address);
@@ -178,7 +181,7 @@ mod TokengiverCampaigns {
178181

179182
//set dispatcher
180183
let token_giver_dispatcher = ITokenGiverNftDispatcher {
181-
contract_address: token_giver_nft_contract_address
184+
contract_address: token_giver_nft_contract_address,
182185
};
183186

184187
// mint the nft
@@ -189,10 +192,10 @@ mod TokengiverCampaigns {
189192
let token_id = token_giver_dispatcher.get_user_token_id(get_caller_address());
190193

191194
let campaign_address = IRegistryLibraryDispatcher {
192-
class_hash: registry_hash.try_into().unwrap()
195+
class_hash: registry_hash.try_into().unwrap(),
193196
}
194197
.create_account(
195-
implementation_hash, token_giver_nft_contract_address, token_id.clone(), salt
198+
implementation_hash, token_giver_nft_contract_address, token_id.clone(), salt,
196199
);
197200

198201
let token_uri = token_giver_dispatcher.get_token_uri(token_id);
@@ -224,7 +227,7 @@ mod TokengiverCampaigns {
224227
token_giver_nft_address: token_giver_nft_contract_address,
225228
nft_token_uri: token_uri,
226229
block_timestamp: get_block_timestamp(),
227-
}
230+
},
228231
);
229232

230233
campaign_address
@@ -254,8 +257,8 @@ mod TokengiverCampaigns {
254257

255258
// get instance of the governance token
256259
let governance_token = IGovernanceTokenDispatcher {
257-
contract_address: contract_address_const::<0x0, // change to real address
258-
>()
260+
contract_address: contract_address_const::<0x0 // change to real address
261+
>(),
259262
};
260263

261264
let time = get_block_timestamp();
@@ -271,7 +274,7 @@ mod TokengiverCampaigns {
271274
amount: amount,
272275
token_id: campaign.token_id,
273276
block_timestamp: time,
274-
}
277+
},
275278
);
276279
}
277280

@@ -306,18 +309,18 @@ mod TokengiverCampaigns {
306309
recipient: caller,
307310
amount: amount,
308311
block_timestamp: get_block_timestamp(),
309-
}
312+
},
310313
);
311314
}
312315

313316
fn set_available_withdrawal(
314-
ref self: ContractState, campaign_address: ContractAddress, amount: u256
317+
ref self: ContractState, campaign_address: ContractAddress, amount: u256,
315318
) {
316319
self.withdrawal_balance.write(campaign_address, amount);
317320
}
318321

319322
fn lock_campaign(
320-
ref self: ContractState, campaign_address: ContractAddress, lock_until: u64
323+
ref self: ContractState, campaign_address: ContractAddress, lock_until: u64,
321324
) {
322325
// Get campaign details
323326
let campaign: Campaign = self.campaign.read(campaign_address);
@@ -338,7 +341,7 @@ mod TokengiverCampaigns {
338341
self.donations.read(campaign_address)
339342
}
340343
fn get_available_withdrawal(
341-
self: @ContractState, campaign_address: ContractAddress
344+
self: @ContractState, campaign_address: ContractAddress,
342345
) -> u256 {
343346
// self.withdrawal_balance.read(campaign_address)
344347
let token_address = self.strk_address.read();
@@ -366,7 +369,7 @@ mod TokengiverCampaigns {
366369
fn update_token_giver_nft(
367370
ref self: ContractState,
368371
token_giver_nft_class_hash: ClassHash,
369-
token_giver_nft_contract_address: ContractAddress
372+
token_giver_nft_contract_address: ContractAddress,
370373
) {
371374
// This function can only be called by the owner
372375
self.ownable.assert_only_owner();

src/campaign_pool.cairo

+76-24
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,28 @@ mod CampaignPools {
55
// *************************************************************************
66
// IMPORT
77
// *************************************************************************
8+
use core::num::traits::Zero;
89
use core::traits::TryInto;
9-
use starknet::{
10-
ContractAddress, get_caller_address, get_block_timestamp, ClassHash, get_contract_address,
11-
syscalls::deploy_syscall, SyscallResultTrait, syscalls, class_hash::class_hash_const,
12-
storage::{Map, StoragePathEntry, StoragePointerReadAccess, StoragePointerWriteAccess}
13-
};
14-
use tokengiver::base::errors::Errors;
15-
use tokengiver::interfaces::ICampaignPool::ICampaignPool;
16-
use tokengiver::base::types::CampaignPool;
1710
use openzeppelin::access::ownable::OwnableComponent;
1811
use openzeppelin::upgrades::UpgradeableComponent;
1912
use openzeppelin::upgrades::interface::IUpgradeable;
20-
use tokengiver::interfaces::ITokenGiverNft::{
21-
ITokenGiverNftDispatcher, ITokenGiverNftDispatcherTrait
13+
use starknet::class_hash::class_hash_const;
14+
use starknet::storage::{
15+
Map, StoragePathEntry, StoragePointerReadAccess, StoragePointerWriteAccess,
2216
};
17+
use starknet::syscalls::deploy_syscall;
18+
use starknet::{
19+
ClassHash, ContractAddress, SyscallResultTrait, get_block_timestamp, get_caller_address,
20+
get_contract_address, syscalls,
21+
};
22+
use tokengiver::base::errors::Errors;
23+
use tokengiver::base::types::CampaignPool;
24+
use tokengiver::interfaces::ICampaignPool::ICampaignPool;
2325
use tokengiver::interfaces::IRegistry::{
24-
IRegistryDispatcher, IRegistryDispatcherTrait, IRegistryLibraryDispatcher
26+
IRegistryDispatcher, IRegistryDispatcherTrait, IRegistryLibraryDispatcher,
27+
};
28+
use tokengiver::interfaces::ITokenGiverNft::{
29+
ITokenGiverNftDispatcher, ITokenGiverNftDispatcherTrait,
2530
};
2631

2732
component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);
@@ -40,16 +45,16 @@ mod CampaignPools {
4045
struct Storage {
4146
campaign_pool: Map<ContractAddress, CampaignPool>,
4247
campaign_pool_applications: Map<
43-
ContractAddress, (ContractAddress, u256)
48+
ContractAddress, (ContractAddress, u256),
4449
>, // map<Campaign Address, (campaign pool address, amount)>
4550
campaign_pool_count: u16,
4651
campaign_pool_nft_token: Map<
47-
ContractAddress, (ContractAddress, u256)
52+
ContractAddress, (ContractAddress, u256),
4853
>, // (recipient, (campaign_address, token_id));
4954
donations: Map<ContractAddress, u256>,
5055
donation_count: Map<ContractAddress, u16>,
5156
donation_details: Map<
52-
(ContractAddress, ContractAddress), DonationDetails
57+
(ContractAddress, ContractAddress), DonationDetails,
5358
>, // map((campaign pool address, Campaign Address), donation_details)
5459
strk_address: ContractAddress,
5560
token_giver_nft_contract_address: ContractAddress,
@@ -59,6 +64,8 @@ mod CampaignPools {
5964
ownable: OwnableComponent::Storage,
6065
#[substorage(v0)]
6166
upgradeable: UpgradeableComponent::Storage,
67+
donor_votes: Map<(ContractAddress, ContractAddress), VoteData>,
68+
campaign_votes_count: Map<ContractAddress, u256>,
6269
}
6370

6471

@@ -71,12 +78,20 @@ mod CampaignPools {
7178
CreateCampaignPool: CreateCampaignPool,
7279
DonationMade: DonationMade,
7380
ApplicationMade: ApplicationMade,
81+
DonorVoted: DonorVoted,
7482
#[flat]
7583
OwnableEvent: OwnableComponent::Event,
7684
#[flat]
7785
UpgradeableEvent: UpgradeableComponent::Event,
7886
}
7987

88+
#[derive(Drop, starknet::Event)]
89+
pub struct DonorVoted {
90+
campaign_address: ContractAddress,
91+
donor_address: ContractAddress,
92+
time: u64,
93+
}
94+
8095
#[derive(Drop, starknet::Event)]
8196
pub struct CreateCampaignPool {
8297
#[key]
@@ -121,6 +136,12 @@ mod CampaignPools {
121136
amount: u256,
122137
}
123138

139+
#[derive(Drop, Copy, Serde, starknet::Store)]
140+
pub struct VoteData {
141+
campaign_address: ContractAddress,
142+
donor: ContractAddress,
143+
}
144+
124145
// *************************************************************************
125146
// CONSTRUCTOR
126147
// *************************************************************************
@@ -130,7 +151,7 @@ mod CampaignPools {
130151
token_giver_nft_class_hash: ClassHash,
131152
token_giver_nft_contract_address: ContractAddress,
132153
strk_address: ContractAddress,
133-
owner: ContractAddress
154+
owner: ContractAddress,
134155
) {
135156
self.token_giver_nft_class_hash.write(token_giver_nft_class_hash);
136157
self.token_giver_nft_contract_address.write(token_giver_nft_contract_address);
@@ -155,15 +176,15 @@ mod CampaignPools {
155176
let campaign_pool_count: u16 = self.campaign_pool_count.read() + 1;
156177
let token_giver_nft_contract_address = self.token_giver_nft_contract_address.read();
157178
let nft_contract_dispatcher = ITokenGiverNftDispatcher {
158-
contract_address: token_giver_nft_contract_address
179+
contract_address: token_giver_nft_contract_address,
159180
};
160181
let token_id: u256 = nft_contract_dispatcher.mint_token_giver_nft(get_caller_address());
161182

162183
let campaign_address = IRegistryLibraryDispatcher {
163-
class_hash: registry_hash.try_into().unwrap()
184+
class_hash: registry_hash.try_into().unwrap(),
164185
}
165186
.create_account(
166-
implementation_hash, token_giver_nft_contract_address, token_id.clone(), salt
187+
implementation_hash, token_giver_nft_contract_address, token_id.clone(), salt,
167188
);
168189
let token_uri = nft_contract_dispatcher.get_token_uri(token_id);
169190
let campaign_details = CampaignPool {
@@ -187,26 +208,57 @@ mod CampaignPools {
187208
campaign_pool_id: campaign_pool_count.try_into().unwrap(),
188209
nft_token_uri: token_uri.clone(),
189210
token_giver_nft_address: token_giver_nft_contract_address,
190-
block_timestamp: get_block_timestamp()
191-
}
211+
block_timestamp: get_block_timestamp(),
212+
},
192213
);
193214

194215
campaign_address
195216
}
196217

218+
fn vote_project(
219+
ref self: ContractState,
220+
campaign_pool_address: ContractAddress,
221+
campaign_address: ContractAddress,
222+
) {
223+
let caller = get_caller_address();
224+
225+
let user_votes = self.donor_votes.read((caller, campaign_address));
226+
let caller_donation = self.donations.read(caller);
227+
let campaign_count = self.campaign_votes_count.read(campaign_address);
228+
229+
assert(caller_donation > 0, 'Caller not donor');
230+
231+
assert(user_votes.donor.is_non_zero(), 'Voted already');
232+
233+
let new_vote = VoteData { campaign_address: campaign_address, donor: caller };
234+
235+
self.donor_votes.write((caller, campaign_address), new_vote);
236+
237+
self.campaign_votes_count.write(campaign_address, campaign_count + 1);
238+
239+
self
240+
.emit(
241+
DonorVoted {
242+
campaign_address: campaign_address,
243+
donor_address: caller,
244+
time: get_block_timestamp(),
245+
},
246+
);
247+
}
248+
197249
fn get_campaign(self: @ContractState, campaign_address: ContractAddress) -> CampaignPool {
198250
self.campaign_pool.read(campaign_address)
199251
}
200252

201253
fn donate_campaign_pool(
202-
ref self: ContractState, campaign_pool_address: ContractAddress, amount: u256
254+
ref self: ContractState, campaign_pool_address: ContractAddress, amount: u256,
203255
) {}
204256

205257
fn apply_to_campaign_pool(
206258
ref self: ContractState,
207259
campaign_address: ContractAddress,
208260
campaign_pool_address: ContractAddress,
209-
amount: u256
261+
amount: u256,
210262
) {
211263
// Get caller address to identify who is applying
212264
let caller = get_caller_address();
@@ -243,11 +295,11 @@ mod CampaignPools {
243295
recipient: caller,
244296
amount: amount,
245297
block_timestamp: get_block_timestamp(),
246-
}
298+
},
247299
);
248300
}
249301
fn get_campaign_application(
250-
self: @ContractState, campaign_address: ContractAddress
302+
self: @ContractState, campaign_address: ContractAddress,
251303
) -> (ContractAddress, u256) {
252304
self.campaign_pool_applications.read(campaign_address)
253305
}

src/interfaces/ICampaign.cairo

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use starknet::{ContractAddress, ClassHash};
1+
use starknet::{ClassHash, ContractAddress};
22
use tokengiver::base::types::Campaign;
33
// *************************************************************************
44
// INTERFACE of TOKEN GIVER NFT
@@ -27,7 +27,7 @@ pub trait ICampaign<TState> {
2727
fn update_token_giver_nft(
2828
ref self: TState,
2929
token_giver_nft_class_hash: ClassHash,
30-
token_giver_nft_contract_address: ContractAddress
30+
token_giver_nft_contract_address: ContractAddress,
3131
);
3232

3333
// fn approve_campaign_spending(ref self: TState, campaign_address: ContractAddress);

0 commit comments

Comments
 (0)