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: Advanced factory contract #219

Merged
merged 116 commits into from
Jun 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
116 commits
Select commit Hold shift + click to select a range
c3c1781
add initial factory
Jun 6, 2024
77e0f4c
add ownable component
Jun 6, 2024
4482699
add caller to CounterCreated event
Jun 6, 2024
8c4041d
turn counter into campaign
Jun 6, 2024
a444ead
fix Campaign interfaced funcs + implement donate
Jun 6, 2024
a29d077
add _assert_is_ended + update error messages
Jun 6, 2024
d9facfe
_assert_active->_assert_campaign_active
Jun 6, 2024
9436c77
_assert_is_ended->_assert_campaign_ended
Jun 6, 2024
e3ff8de
implement withdraw
Jun 6, 2024
2ea6f8f
add missing assert success in donate
Jun 6, 2024
abd561a
add title & description
Jun 6, 2024
8c255fb
update comment
Jun 6, 2024
31b84f3
implement upgrade
Jun 6, 2024
cae84c6
clean up internal funcs and imports
Jun 6, 2024
c45855b
move hardcoded errors in Errors mod
Jun 6, 2024
2008ed3
donate -> contribute + event rename
Jun 6, 2024
662a4f3
withdraw -> claim
Jun 6, 2024
7e13707
add store impl for contract addr. array
Jun 7, 2024
a0932c8
remove store impl
Jun 7, 2024
52aa534
add dynamic array impl
Jun 7, 2024
843bb2e
remove dyn. array
Jun 7, 2024
5c6b5c1
remove descr + convert title to felt + convert target to u128
Jun 7, 2024
dabb2c1
implement updating class hashes
Jun 7, 2024
7f7c7fc
Make title ByteArray again + target into u256 + update ctor arg seria…
Jun 7, 2024
a39ced9
refactor serialization + add back description
Jun 7, 2024
0fcfd17
remove unused contracts
Jun 8, 2024
5f766fd
add 1 test
Jun 10, 2024
74fe0fd
add get_description
Jun 10, 2024
b3e1efb
add correct deps
Jun 10, 2024
b327d80
add alexandria to toml
Jun 10, 2024
1092946
format factory.cairo
Jun 10, 2024
3bba851
add missing snforge workspace
Jun 10, 2024
f1bd81e
add missing getters + tests
Jun 10, 2024
b5a7a3f
add factory deploy tests
Jun 10, 2024
36adaa5
add class hash update test + event assertions
Jun 10, 2024
a2902a2
assert old class hash prior to update
Jun 10, 2024
586a0f0
remove commented out test
Jun 10, 2024
2eba71b
use common alex. storage workspace in using_lists
Jun 10, 2024
399c12a
add missing newline in toml
Jun 10, 2024
3d71f59
move factory tests to separate file
Jun 10, 2024
4674726
add scaffold docs for contracts
Jun 10, 2024
2c1ef6b
add end_time asserts
Jun 10, 2024
4b62bb6
refactor private asserts
Jun 10, 2024
07e85ff
check if target reached before claiming
Jun 10, 2024
1ddf279
add ability to withdraw funds
Jun 10, 2024
7de30aa
make contributions into a component (now iterable)
Jun 11, 2024
7af01aa
refactor 'withhold' - contrs map to amt_idx
Jun 11, 2024
0ed6fdf
add get_contributors func
Jun 11, 2024
b00df42
get_contributors -> get_contributions
Jun 11, 2024
58517ec
total_contributors->contributor_count
Jun 11, 2024
fae8b34
add tests for campaign upgrade and deploy + update all relevant code …
Jun 11, 2024
05ab75f
add status to campaign
Jun 11, 2024
2ca2ede
add close fn
Jun 11, 2024
cc2705a
pass desired donation token in ctor
Jun 11, 2024
9280f9a
merge all getters into get_details
Jun 11, 2024
a99aaca
return total_contributions in details
Jun 11, 2024
47a9d72
remove rev version from alexandria dep
Jun 12, 2024
8d68d86
verbose names
Jun 12, 2024
cd82c99
reorg. folder structure
Jun 12, 2024
cf2b916
add tag to alexandria dep
Jun 12, 2024
22ac28d
campaign_upgrade.cairo->mock_upgrade.cairo
Jun 12, 2024
38068f8
add explicit alexandria rev + make crowdfunding contracts standalone …
Jun 12, 2024
a451d90
add status pending
Jun 12, 2024
7c23cfd
field rename: factory->creator
Jun 12, 2024
ec6edb6
refund users when upgrading campaign
Jun 12, 2024
eca7eec
Make owner the calling address, and creator is the campaign manager
Jun 12, 2024
3803a6f
add get_contributor (amount) func
Jun 12, 2024
f9941a3
Add successful campaign test
Jun 12, 2024
bb30453
update comment for upgrade
Jun 13, 2024
92042e5
_refund_all->_withdraw_all
Jun 13, 2024
7bcaa07
update checks for withdraw
Jun 13, 2024
f660953
rework contribute
Jun 13, 2024
1aa6bc1
rework all funcs
Jun 13, 2024
6156289
unsuccessful -> failed
Jun 13, 2024
93d2860
calc end_time in start fn
Jun 13, 2024
bb61698
calc end_time in upgrade fn
Jun 13, 2024
fad077c
makes upgrades callable only by creators in factory
Jun 13, 2024
50f65b7
fix factory tests
Jun 13, 2024
cae2898
fix crowdfunding tests
Jun 13, 2024
441d5c1
reduce total contri. when withdraw from act. camp
Jun 13, 2024
df0d763
add refund fn
Jun 13, 2024
71d4ff5
refactor withdraw_all to use _refund
Jun 13, 2024
0671b0e
pending->draft
Jun 13, 2024
f6258cb
fix mock and tests
Jun 13, 2024
f236df1
add test for close
Jun 13, 2024
863abaf
add test for withdraw
Jun 13, 2024
d3221c8
upgrade > update end_time only if duration provided
Jun 13, 2024
af95cb4
close->cancel
Jun 14, 2024
07fbd06
rename to more align with Solidity by example
Jun 14, 2024
411e8f7
target->goal
Jun 14, 2024
d8809b7
remove comment
Jun 14, 2024
097e9b6
err CLOSED->CANCELED + check active in unpledge
Jun 14, 2024
59e5117
contributor->pledger
Jun 14, 2024
123229c
add campaign doc content
Jun 14, 2024
a97f449
remove draft status
Jun 14, 2024
f3d5a9d
add start_time
Jun 14, 2024
8f78dc4
remove Status
Jun 14, 2024
315169c
update doc for campaign
Jun 14, 2024
adaa0b9
move total_pledges to pledgeable
Jun 14, 2024
5fcb4e2
reorder alphabetically
Jun 14, 2024
f0a6586
remove Launched event + upgrade mock
Jun 14, 2024
377c02d
TARGET->GOAL
Jun 14, 2024
e25df4e
reorder params in Details
Jun 14, 2024
36ff85c
add inline to _refund
Jun 14, 2024
af94299
add new pledgeable tests
Jun 14, 2024
ccd2362
add getX tests + add get_pledge_count
Jun 14, 2024
e3c9f55
refactor pledger_to_amount_index->pledger_to_amount
Jun 15, 2024
131346d
Add tests with 1000 pledgers
Jun 17, 2024
d1477c4
add test for add + update existing pledger
Jun 17, 2024
4eba1ed
reenable lib
Jun 17, 2024
f702709
Add link to adv. factory in crowdfunding point 9
Jun 17, 2024
ab66865
write the adv. factory chapter
Jun 17, 2024
cfd7694
upgrade_campaign_implementation-> upgrade_campaign + comment updates
Jun 17, 2024
5c39c5a
rename get_pledgers_as_arr->array
Jun 17, 2024
9ddcaf6
Use ERC20Upgradeable instead of ERC20 preset
Jun 26, 2024
48f78fe
Add missing token recipient ctor argument in crowdfunding tests
Jun 26, 2024
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
19 changes: 19 additions & 0 deletions Scarb.lock
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
# Code generated by scarb DO NOT EDIT.
version = 1

[[package]]
name = "advanced_factory"
version = "0.1.0"
dependencies = [
"alexandria_storage",
"components",
"crowdfunding",
"snforge_std",
]

[[package]]
name = "alexandria_storage"
version = "0.3.0"
Expand Down Expand Up @@ -44,6 +54,15 @@ version = "0.1.0"
name = "counter"
version = "0.1.0"

[[package]]
name = "crowdfunding"
version = "0.1.0"
dependencies = [
"components",
"openzeppelin",
"snforge_std",
]

[[package]]
name = "custom_type_serde"
version = "0.1.0"
Expand Down
2 changes: 2 additions & 0 deletions Scarb.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ starknet = ">=2.6.4"
openzeppelin = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", tag="v0.14.0" }
components = { path = "listings/applications/components" }
snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry.git", tag = "v0.25.0" }
# The latest Alexandria release supports only Cairo v2.6.0, so using explicit rev that supports Cairo v2.6.3
alexandria_storage = { git = "https://github.com/keep-starknet-strange/alexandria.git", rev="800f5ad" }
0xNeshi marked this conversation as resolved.
Show resolved Hide resolved

[workspace.package]
description = "Collection of examples of how to use the Cairo programming language to create smart contracts on Starknet."
Expand Down
2 changes: 1 addition & 1 deletion listings/advanced-concepts/using_lists/Scarb.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ edition = '2023_11'

[dependencies]
starknet.workspace = true
alexandria_storage = { git = "https://github.com/keep-starknet-strange/alexandria.git", rev="800f5ad"}
alexandria_storage.workspace = true

[scripts]
test.workspace = true
Expand Down
2 changes: 2 additions & 0 deletions listings/applications/advanced_factory/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
target
.snfoundry_cache/
18 changes: 18 additions & 0 deletions listings/applications/advanced_factory/Scarb.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
name = "advanced_factory"
version.workspace = true
edition = "2023_11"

[dependencies]
starknet.workspace = true
components.workspace = true
alexandria_storage.workspace = true
snforge_std.workspace = true
crowdfunding = { path = "../crowdfunding" }

[scripts]
test.workspace = true

[[target.starknet-contract]]
casm = true
build-external-contracts = ["crowdfunding::campaign::Campaign"]
152 changes: 152 additions & 0 deletions listings/applications/advanced_factory/src/contract.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// ANCHOR: contract
pub use starknet::{ContractAddress, ClassHash};

#[starknet::interface]
pub trait ICampaignFactory<TContractState> {
fn create_campaign(
ref self: TContractState,
title: ByteArray,
description: ByteArray,
goal: u256,
start_time: u64,
end_time: u64,
token_address: ContractAddress
) -> ContractAddress;
fn get_campaign_class_hash(self: @TContractState) -> ClassHash;
fn update_campaign_class_hash(ref self: TContractState, new_class_hash: ClassHash);
fn upgrade_campaign(
ref self: TContractState, campaign_address: ContractAddress, new_end_time: Option<u64>
);
}

#[starknet::contract]
pub mod CampaignFactory {
use core::num::traits::zero::Zero;
use starknet::{
ContractAddress, ClassHash, SyscallResultTrait, syscalls::deploy_syscall,
get_caller_address, get_contract_address
};
use alexandria_storage::list::{List, ListTrait};
use crowdfunding::campaign::{ICampaignDispatcher, ICampaignDispatcherTrait};
use components::ownable::ownable_component;

component!(path: ownable_component, storage: ownable, event: OwnableEvent);

#[abi(embed_v0)]
impl OwnableImpl = ownable_component::Ownable<ContractState>;
impl OwnableInternalImpl = ownable_component::OwnableInternalImpl<ContractState>;

#[storage]
struct Storage {
#[substorage(v0)]
ownable: ownable_component::Storage,
/// Store all of the created campaign instances' addresses and thei class hashes
campaigns: LegacyMap<(ContractAddress, ContractAddress), ClassHash>,
/// Store the class hash of the contract to deploy
campaign_class_hash: ClassHash,
}

#[event]
#[derive(Drop, starknet::Event)]
pub enum Event {
#[flat]
OwnableEvent: ownable_component::Event,
CampaignClassHashUpgraded: CampaignClassHashUpgraded,
CampaignCreated: CampaignCreated,
ClassHashUpdated: ClassHashUpdated,
}

#[derive(Drop, starknet::Event)]
pub struct ClassHashUpdated {
pub new_class_hash: ClassHash,
}

#[derive(Drop, starknet::Event)]
pub struct CampaignClassHashUpgraded {
pub campaign: ContractAddress,
}

#[derive(Drop, starknet::Event)]
pub struct CampaignCreated {
pub creator: ContractAddress,
pub contract_address: ContractAddress
}

pub mod Errors {
pub const CLASS_HASH_ZERO: felt252 = 'Class hash cannot be zero';
pub const ZERO_ADDRESS: felt252 = 'Zero address';
pub const SAME_IMPLEMENTATION: felt252 = 'Implementation is unchanged';
pub const CAMPAIGN_NOT_FOUND: felt252 = 'Campaign not found';
}

#[constructor]
fn constructor(ref self: ContractState, class_hash: ClassHash) {
assert(class_hash.is_non_zero(), Errors::CLASS_HASH_ZERO);
self.campaign_class_hash.write(class_hash);
self.ownable._init(get_caller_address());
}


#[abi(embed_v0)]
impl CampaignFactory of super::ICampaignFactory<ContractState> {
fn create_campaign(
ref self: ContractState,
title: ByteArray,
description: ByteArray,
goal: u256,
start_time: u64,
end_time: u64,
token_address: ContractAddress,
) -> ContractAddress {
let creator = get_caller_address();

// Create contructor arguments
let mut constructor_calldata: Array::<felt252> = array![];
((creator, title, description, goal), start_time, end_time, token_address)
.serialize(ref constructor_calldata);

// Contract deployment
let (contract_address, _) = deploy_syscall(
self.campaign_class_hash.read(), 0, constructor_calldata.span(), false
)
.unwrap_syscall();

// track new campaign instance
self.campaigns.write((creator, contract_address), self.campaign_class_hash.read());

self.emit(Event::CampaignCreated(CampaignCreated { creator, contract_address }));

contract_address
}

fn get_campaign_class_hash(self: @ContractState) -> ClassHash {
self.campaign_class_hash.read()
}

fn update_campaign_class_hash(ref self: ContractState, new_class_hash: ClassHash) {
self.ownable._assert_only_owner();
assert(new_class_hash.is_non_zero(), Errors::CLASS_HASH_ZERO);

self.campaign_class_hash.write(new_class_hash);

self.emit(Event::ClassHashUpdated(ClassHashUpdated { new_class_hash }));
}

fn upgrade_campaign(
ref self: ContractState, campaign_address: ContractAddress, new_end_time: Option<u64>
) {
assert(campaign_address.is_non_zero(), Errors::ZERO_ADDRESS);

let creator = get_caller_address();
let old_class_hash = self.campaigns.read((creator, campaign_address));
assert(old_class_hash.is_non_zero(), Errors::CAMPAIGN_NOT_FOUND);
assert(old_class_hash != self.campaign_class_hash.read(), Errors::SAME_IMPLEMENTATION);

let campaign = ICampaignDispatcher { contract_address: campaign_address };
campaign.upgrade(self.campaign_class_hash.read(), new_end_time);
}
}
}
// ANCHOR_END: contract


5 changes: 5 additions & 0 deletions listings/applications/advanced_factory/src/lib.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
mod contract;
mod mock_upgrade;

#[cfg(test)]
mod tests;
8 changes: 8 additions & 0 deletions listings/applications/advanced_factory/src/mock_upgrade.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#[starknet::contract]
pub mod MockContract {
#[storage]
struct Storage {}
#[event]
#[derive(Drop, starknet::Event)]
enum Event {}
}
Loading