-
Notifications
You must be signed in to change notification settings - Fork 94
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'NethermindEth:main' into main
- Loading branch information
Showing
60 changed files
with
3,771 additions
and
439 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
scarb 2.6.4 | ||
starknet-foundry 0.24.0 | ||
scarb 2.6.5 | ||
starknet-foundry 0.25.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
target |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# Code generated by scarb DO NOT EDIT. | ||
version = 1 | ||
|
||
[[package]] | ||
name = "ecdsa_verification" | ||
version = "0.1.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
[package] | ||
name = "simple_account" | ||
version.workspace = true | ||
edition = '2023_11' | ||
|
||
|
||
[dependencies] | ||
starknet.workspace = true | ||
openzeppelin.workspace = true | ||
|
||
[scripts] | ||
test.workspace = true | ||
|
||
[[target.starknet-contract]] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
mod simple_account; | ||
|
||
#[cfg(test)] | ||
mod tests; |
90 changes: 90 additions & 0 deletions
90
listings/advanced-concepts/simple_account/src/simple_account.cairo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
use starknet::account::Call; | ||
|
||
#[starknet::interface] | ||
trait ISRC6<TContractState> { | ||
fn execute_calls(self: @TContractState, calls: Array<Call>) -> Array<Span<felt252>>; | ||
fn validate_calls(self: @TContractState, calls: Array<Call>) -> felt252; | ||
fn is_valid_signature( | ||
self: @TContractState, hash: felt252, signature: Array<felt252> | ||
) -> felt252; | ||
} | ||
|
||
#[starknet::contract] | ||
mod simpleAccount { | ||
use super::ISRC6; | ||
use starknet::account::Call; | ||
use core::num::traits::Zero; | ||
use core::ecdsa::check_ecdsa_signature; | ||
|
||
// Implement SRC5 with openzeppelin | ||
use openzeppelin::account::interface; | ||
use openzeppelin::introspection::src5::SRC5Component; | ||
component!(path: SRC5Component, storage: src5, event: SRC5Event); | ||
|
||
#[abi(embed_v0)] | ||
impl SRC5Impl = SRC5Component::SRC5Impl<ContractState>; | ||
impl SRC5InternalImpl = SRC5Component::InternalImpl<ContractState>; | ||
|
||
#[storage] | ||
struct Storage { | ||
#[substorage(v0)] | ||
src5: SRC5Component::Storage, | ||
public_key: felt252 | ||
} | ||
|
||
#[constructor] | ||
fn constructor(ref self: ContractState, public_key: felt252) { | ||
self.src5.register_interface(interface::ISRC6_ID); | ||
self.public_key.write(public_key); | ||
} | ||
|
||
#[event] | ||
#[derive(Drop, starknet::Event)] | ||
enum Event { | ||
#[flat] | ||
SRC5Event: SRC5Component::Event | ||
} | ||
|
||
#[abi(embed_v0)] | ||
impl SRC6 of ISRC6<ContractState> { | ||
fn execute_calls(self: @ContractState, calls: Array<Call>) -> Array<Span<felt252>> { | ||
assert(starknet::get_caller_address().is_zero(), 'Not Starknet Protocol'); | ||
let Call { to, selector, calldata } = calls.at(0); | ||
let res = starknet::syscalls::call_contract_syscall(*to, *selector, *calldata).unwrap(); | ||
array![res] | ||
} | ||
|
||
fn validate_calls(self: @ContractState, calls: Array<Call>) -> felt252 { | ||
assert(starknet::get_caller_address().is_zero(), 'Not Starknet Protocol'); | ||
let tx_info = starknet::get_tx_info().unbox(); | ||
let tx_hash = tx_info.transaction_hash; | ||
let signature = tx_info.signature; | ||
if self._is_valid_signature(tx_hash, signature) { | ||
starknet::VALIDATED | ||
} else { | ||
0 | ||
} | ||
} | ||
|
||
fn is_valid_signature( | ||
self: @ContractState, hash: felt252, signature: Array<felt252> | ||
) -> felt252 { | ||
if self._is_valid_signature(hash, signature.span()) { | ||
starknet::VALIDATED | ||
} else { | ||
0 | ||
} | ||
} | ||
} | ||
|
||
#[generate_trait] | ||
impl SignatureVerificationImpl of SignatureVerification { | ||
fn _is_valid_signature( | ||
self: @ContractState, hash: felt252, signature: Span<felt252> | ||
) -> bool { | ||
check_ecdsa_signature( | ||
hash, self.public_key.read(), *signature.at(0_u32), *signature.at(1_u32) | ||
) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
#[cfg(test)] | ||
mod tests { // TODO | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
target | ||
.snfoundry_cache/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
152
listings/applications/advanced_factory/src/contract.cairo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
|
||
|
Oops, something went wrong.