From 60a8da7e1118445242382678bded7bc8dbb5dcb6 Mon Sep 17 00:00:00 2001 From: msaug Date: Thu, 6 Jul 2023 15:35:47 +0200 Subject: [PATCH 1/4] feat: calling_other_contracts --- .../verify-cairo-programs/action.yml | 2 +- .github/workflows/verify_cairo_programs.yml | 2 +- .../calling_other_contracts/Scarb.toml | 2 +- .../calling_other_contracts/src/callee.cairo | 21 +++++++++++----- .../calling_other_contracts/src/caller.cairo | 24 +++++++++++++------ .../calling_other_contracts/src/lib.cairo | 2 +- 6 files changed, 36 insertions(+), 17 deletions(-) diff --git a/.github/workflows/verify-cairo-programs/action.yml b/.github/workflows/verify-cairo-programs/action.yml index 0432e970..1a5dc7c3 100644 --- a/.github/workflows/verify-cairo-programs/action.yml +++ b/.github/workflows/verify-cairo-programs/action.yml @@ -8,7 +8,7 @@ runs: - name: Install scarb shell: bash run: | - curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh | bash -s -- -v 0.4.0 + curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh | bash -s -- -v 0.5.1 - name: Run build script shell: bash diff --git a/.github/workflows/verify_cairo_programs.yml b/.github/workflows/verify_cairo_programs.yml index cbae9d2d..151a0814 100644 --- a/.github/workflows/verify_cairo_programs.yml +++ b/.github/workflows/verify_cairo_programs.yml @@ -18,7 +18,7 @@ jobs: - name: Install scarb run: | - curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh | bash -s -- -v 0.4.0 + curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh | bash -s -- -v 0.5.1 - name: Run build script run: | diff --git a/listings/ch00-introduction/calling_other_contracts/Scarb.toml b/listings/ch00-introduction/calling_other_contracts/Scarb.toml index 787468a6..484c25eb 100644 --- a/listings/ch00-introduction/calling_other_contracts/Scarb.toml +++ b/listings/ch00-introduction/calling_other_contracts/Scarb.toml @@ -5,6 +5,6 @@ version = "0.1.0" # See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest [dependencies] -starknet = "1.1.0" +starknet = ">=2.0.1" [[target.starknet-contract]] \ No newline at end of file diff --git a/listings/ch00-introduction/calling_other_contracts/src/callee.cairo b/listings/ch00-introduction/calling_other_contracts/src/callee.cairo index 5c5692c1..d2ef1aaf 100644 --- a/listings/ch00-introduction/calling_other_contracts/src/callee.cairo +++ b/listings/ch00-introduction/calling_other_contracts/src/callee.cairo @@ -1,12 +1,21 @@ -#[contract] +#[starknet::interface] +trait ICallee { + fn set_value(ref self: TContractState, value: u128) -> u128; +} + + +#[starknet::contract] mod Callee { + #[storage] struct Storage { - _x: u128, + value: u128, } - #[external] - fn set_x(x: u128) -> u128 { - _x::write(x); - x + #[external(v0)] + impl ICalleeImpl of super::ICallee { + fn set_value(ref self: ContractState, value: u128) -> u128 { + self.value.write(value); + value + } } } diff --git a/listings/ch00-introduction/calling_other_contracts/src/caller.cairo b/listings/ch00-introduction/calling_other_contracts/src/caller.cairo index 1ee624bb..1cb9ede4 100644 --- a/listings/ch00-introduction/calling_other_contracts/src/caller.cairo +++ b/listings/ch00-introduction/calling_other_contracts/src/caller.cairo @@ -1,16 +1,26 @@ -#[abi] -trait ICallee { - fn set_x(x: u128) -> u128; +use starknet::ContractAddress; +#[starknet::interface] +trait ICaller { + fn set_value_from_address(ref self: TContractState, addr: ContractAddress, value: u128); } +#[starknet::interface] +trait ICallee { + fn set_value(ref self: TContractState, value: u128) -> u128; +} -#[contract] +#[starknet::contract] mod Caller { use super::{ICalleeDispatcher, ICalleeDispatcherTrait}; use starknet::ContractAddress; - #[external] - fn set_x_from_address(addr: ContractAddress, x: u128) { - let x = ICalleeDispatcher { contract_address: addr }.set_x(x); + #[storage] + struct Storage {} + + #[external(v0)] + impl ICallerImpl of super::ICaller { + fn set_value_from_address(ref self: ContractState, addr: ContractAddress, value: u128) { + ICalleeDispatcher { contract_address: addr }.set_value(value); + } } } diff --git a/listings/ch00-introduction/calling_other_contracts/src/lib.cairo b/listings/ch00-introduction/calling_other_contracts/src/lib.cairo index 24a63181..abc5e83e 100644 --- a/listings/ch00-introduction/calling_other_contracts/src/lib.cairo +++ b/listings/ch00-introduction/calling_other_contracts/src/lib.cairo @@ -1,2 +1,2 @@ -mod callee; mod caller; +mod callee; From 8f44ba36e043b94dcf4d558780a9ffbda65e97dd Mon Sep 17 00:00:00 2001 From: msaug Date: Thu, 6 Jul 2023 17:24:06 +0200 Subject: [PATCH 2/4] feat: port to v2.0.1 syntax --- .../ch00-introduction/constructor/Scarb.toml | 2 +- .../constructor/src/lib.cairo | 11 +- listings/ch00-introduction/counter/Scarb.toml | 2 +- .../counter/src/counter.cairo | 49 +++--- listings/ch00-introduction/errors/Scarb.toml | 2 +- .../errors/src/custom_errors.cairo | 25 ++- .../errors/src/simple_errors.cairo | 29 ++-- .../errors/src/vault_errors.cairo | 38 ++-- listings/ch00-introduction/events/Scarb.toml | 2 +- .../events/src/counter.cairo | 36 ++-- .../src/function_attributes.cairo | 29 ---- .../function_attributes/src/lib.cairo | 1 - listings/ch00-introduction/if_else/.gitignore | 1 - listings/ch00-introduction/if_else/Scarb.toml | 8 - .../if_else/src/access_log.cairo | 37 ---- .../ch00-introduction/if_else/src/lib.cairo | 1 - .../ch00-introduction/mappings/Scarb.toml | 2 +- .../mappings/src/mappings.cairo | 21 ++- .../mappings/src/test_mappings.cairo | 14 +- .../storing_arrays/Scarb.toml | 5 +- .../storing_arrays/src/storing_arrays.cairo | 115 +++++++------ .../ch00-introduction/variables/Scarb.toml | 2 +- .../variables/src/global_variables.cairo | 18 +- .../variables/src/local_variables.cairo | 24 ++- .../variables/src/storage_variables.cairo | 26 +-- .../.gitignore | 0 .../Scarb.toml | 4 +- .../visibility/src/lib.cairo | 1 + .../visibility/src/visibility.cairo | 35 ++++ .../write_to_any_slot/Scarb.toml | 5 +- .../src/test_write_any_slot.cairo | 8 +- .../src/write_any_slot.cairo | 26 +-- .../ch01-applications/simple_vault/Scarb.toml | 5 +- .../simple_vault/src/simple_vault.cairo | 162 ++++++++---------- .../upgradeable_contract/Scarb.toml | 2 +- .../src/upgradeable_contract_v0.cairo | 32 ++-- .../src/upgradeable_contract_v1.cairo | 32 ++-- src/SUMMARY.md | 2 +- src/ch00-08-function_attributes.md | 2 +- 39 files changed, 421 insertions(+), 395 deletions(-) delete mode 100644 listings/ch00-introduction/function_attributes/src/function_attributes.cairo delete mode 100644 listings/ch00-introduction/function_attributes/src/lib.cairo delete mode 100644 listings/ch00-introduction/if_else/.gitignore delete mode 100644 listings/ch00-introduction/if_else/Scarb.toml delete mode 100644 listings/ch00-introduction/if_else/src/access_log.cairo delete mode 100644 listings/ch00-introduction/if_else/src/lib.cairo rename listings/ch00-introduction/{function_attributes => visibility}/.gitignore (100%) rename listings/ch00-introduction/{function_attributes => visibility}/Scarb.toml (78%) create mode 100644 listings/ch00-introduction/visibility/src/lib.cairo create mode 100644 listings/ch00-introduction/visibility/src/visibility.cairo diff --git a/listings/ch00-introduction/constructor/Scarb.toml b/listings/ch00-introduction/constructor/Scarb.toml index a4cb19a8..d79578b1 100644 --- a/listings/ch00-introduction/constructor/Scarb.toml +++ b/listings/ch00-introduction/constructor/Scarb.toml @@ -5,6 +5,6 @@ version = "0.1.0" # See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest [dependencies] -starknet = "1.1.0" +starknet = ">=2.0.1" [[target.starknet-contract]] \ No newline at end of file diff --git a/listings/ch00-introduction/constructor/src/lib.cairo b/listings/ch00-introduction/constructor/src/lib.cairo index 47f85854..a6db7d61 100644 --- a/listings/ch00-introduction/constructor/src/lib.cairo +++ b/listings/ch00-introduction/constructor/src/lib.cairo @@ -1,13 +1,14 @@ -#[contract] -mod constructor { +#[starknet::contract] +mod example_constructor { use starknet::ContractAddress; + #[storage] struct Storage { - _names: LegacyMap::, + names: LegacyMap::, } #[constructor] - fn constructor(name: felt252, address: ContractAddress) { - _names::write(address, name); + fn constructor(ref self: ContractState, name: felt252, address: ContractAddress) { + self.names.write(address, name); } } diff --git a/listings/ch00-introduction/counter/Scarb.toml b/listings/ch00-introduction/counter/Scarb.toml index 2e5938be..c3fa70cd 100644 --- a/listings/ch00-introduction/counter/Scarb.toml +++ b/listings/ch00-introduction/counter/Scarb.toml @@ -3,6 +3,6 @@ name = "counter" version = "0.1.0" [dependencies] -starknet = "1.1.0" +starknet = ">=2.0.1" [[target.starknet-contract]] diff --git a/listings/ch00-introduction/counter/src/counter.cairo b/listings/ch00-introduction/counter/src/counter.cairo index 822965ce..903b8dec 100644 --- a/listings/ch00-introduction/counter/src/counter.cairo +++ b/listings/ch00-introduction/counter/src/counter.cairo @@ -1,29 +1,34 @@ -#[contract] -mod SimpleCounter { - struct Storage { - // Counter variable - _counter: u256, - } +#[starknet::interface] +trait ISimpleCounter { + fn get_current_count(self: @TContractState) -> u256; + fn increment(ref self: TContractState); + fn decrement(ref self: TContractState); +} - #[constructor] - fn constructor() {} - #[view] - fn get_current_count() -> u256 { - return _counter::read(); +#[starknet::contract] +mod simple_counter { + #[storage] + struct Storage { + // Counter variable + counter: u256, } - #[external] - fn increment() { - // Store counter value + 1 - let counter: u256 = _counter::read() + 1; - _counter::write(counter); - } + #[external(v0)] + impl SimpleCounterImpl of super::ISimpleCounter { + fn get_current_count(self: @ContractState) -> u256 { + return self.counter.read(); + } - #[external] - fn decrement() { - // Store counter value - 1 - let counter: u256 = _counter::read() - 1; - _counter::write(counter); + fn increment(ref self: ContractState) { + // Store counter value + 1 + let mut counter: u256 = self.counter.read() + 1; + self.counter.write(counter); + } + fn decrement(ref self: ContractState) { + // Store counter value - 1 + let mut counter: u256 = self.counter.read() - 1; + self.counter.write(counter); + } } } diff --git a/listings/ch00-introduction/errors/Scarb.toml b/listings/ch00-introduction/errors/Scarb.toml index c536b5e5..d3731cd1 100644 --- a/listings/ch00-introduction/errors/Scarb.toml +++ b/listings/ch00-introduction/errors/Scarb.toml @@ -5,6 +5,6 @@ version = "0.1.0" # See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest [dependencies] -starknet = "1.1.0" +starknet = ">=2.0.1" [[target.starknet-contract]] \ No newline at end of file diff --git a/listings/ch00-introduction/errors/src/custom_errors.cairo b/listings/ch00-introduction/errors/src/custom_errors.cairo index 822e2239..189c780f 100644 --- a/listings/ch00-introduction/errors/src/custom_errors.cairo +++ b/listings/ch00-introduction/errors/src/custom_errors.cairo @@ -3,19 +3,26 @@ mod Errors { const NOT_NULL: felt252 = 'must not be null'; } -#[contract] + +#[starknet::contract] mod CustomErrorsExample { use super::Errors; - #[view] - fn test_assert(i: u256) { - assert(i > 0, Errors::NOT_POSITIVE); - } + #[storage] + struct Storage {} + + #[generate_trait] + #[external(v0)] + impl CustomErrorsExampleImpl of CustomErrorsExampleTrait { + fn test_assert(self: @ContractState, i: u256) { + assert(i > 0, Errors::NOT_POSITIVE); + } - #[view] - fn test_panic(i: u256) { - if (i == 0) { - panic_with_felt252(Errors::NOT_NULL); + #[view] + fn test_panic(self: @ContractState, i: u256) { + if (i == 0) { + panic_with_felt252(Errors::NOT_NULL); + } } } } diff --git a/listings/ch00-introduction/errors/src/simple_errors.cairo b/listings/ch00-introduction/errors/src/simple_errors.cairo index 1c68165e..ffec9f0d 100644 --- a/listings/ch00-introduction/errors/src/simple_errors.cairo +++ b/listings/ch00-introduction/errors/src/simple_errors.cairo @@ -1,17 +1,22 @@ -#[contract] +#[starknet::contract] mod ErrorsExample { - #[view] - fn test_assert(i: u256) { - // Assert used to validate a condition - // and abort execution if the condition is not met - assert(i > 0, 'i must be greater than 0'); - } + #[storage] + struct Storage {} + + #[generate_trait] + #[external(v0)] + impl ErrorsExampleImpl of ErrorsExampleTrait { + fn test_assert(self: @ContractState, i: u256) { + // Assert used to validate a condition + // and abort execution if the condition is not met + assert(i > 0, 'i must be greater than 0'); + } - #[view] - fn test_panic(i: u256) { - if (i == 0) { - // Panic used to abort execution directly - panic_with_felt252('i must not be 0'); + fn test_panic(self: @ContractState, i: u256) { + if (i == 0) { + // Panic used to abort execution directly + panic_with_felt252('i must not be 0'); + } } } } diff --git a/listings/ch00-introduction/errors/src/vault_errors.cairo b/listings/ch00-introduction/errors/src/vault_errors.cairo index 91c82b3a..7c10277e 100644 --- a/listings/ch00-introduction/errors/src/vault_errors.cairo +++ b/listings/ch00-introduction/errors/src/vault_errors.cairo @@ -3,35 +3,37 @@ mod VaultErrors { // you can define more errors here } -#[contract] +#[starknet::contract] mod VaultErrorsExample { use super::VaultErrors; + #[storage] struct Storage { balance: u256, } - #[external] - fn deposit(amount: u256) { - let old_balance = balance::read(); - let new_balance = old_balance + amount; + #[generate_trait] + #[external(v0)] + impl VaultErrorsExampleImpl of VaultErrorsExampleTrait { + fn deposit(ref self: ContractState, amount: u256) { + let mut balance = self.balance.read(); + balance = balance + amount; + self.balance.write(balance); + } - balance::write(new_balance); - } + fn withdraw(ref self: ContractState, amount: u256) { + let mut balance = self.balance.read(); - #[external] - fn withdraw(amount: u256) { - let current_balance = balance::read(); + assert(balance >= amount, VaultErrors::INSUFFICIENT_BALANCE); - assert(current_balance >= amount, VaultErrors::INSUFFICIENT_BALANCE); + // Or using panic: + if (balance >= amount) { + panic_with_felt252(VaultErrors::INSUFFICIENT_BALANCE); + } - // Or using panic: - if (current_balance >= amount) { - panic_with_felt252(VaultErrors::INSUFFICIENT_BALANCE); - } + let balance = balance - amount; - let new_balance = current_balance - amount; - - balance::write(new_balance); + self.balance.write(balance); + } } } diff --git a/listings/ch00-introduction/events/Scarb.toml b/listings/ch00-introduction/events/Scarb.toml index 63071abe..e5da91fb 100644 --- a/listings/ch00-introduction/events/Scarb.toml +++ b/listings/ch00-introduction/events/Scarb.toml @@ -3,6 +3,6 @@ name = "counter" version = "0.1.0" [dependencies] -starknet = "1.1.0" +starknet = ">=2.0.1" [[target.starknet-contract]] \ No newline at end of file diff --git a/listings/ch00-introduction/events/src/counter.cairo b/listings/ch00-introduction/events/src/counter.cairo index 3c23ad23..a039a5b2 100644 --- a/listings/ch00-introduction/events/src/counter.cairo +++ b/listings/ch00-introduction/events/src/counter.cairo @@ -1,23 +1,31 @@ -#[contract] -mod SimpleCounter { +#[starknet::contract] +mod EventCounter { + #[storage] struct Storage { // Counter value - _counter: u256, + counter: u128, } #[event] - // Increment event - emitted when the counter is incremented. - fn Increment(counterVal: u256) {} + #[derive(Drop, starknet::Event)] + enum Event { + CounterIncreased: CounterIncreased + } - #[constructor] - fn constructor() {} + #[derive(Drop, starknet::Event)] + struct CounterIncreased { + amount: u128 + } - #[external] - fn increment() { - let mut counter: u256 = _counter::read(); - counter += 1; - _counter::write(counter); - // Emit event - Increment(counter); + #[generate_trait] + #[external(v0)] + impl EventCounterImpl of EventCounterTrait { + fn increment(ref self: ContractState) { + let mut counter = self.counter.read(); + counter += 1; + self.counter.write(counter); + // Emit event + self.emit(Event::CounterIncreased(CounterIncreased { amount: 1 })) + } } } diff --git a/listings/ch00-introduction/function_attributes/src/function_attributes.cairo b/listings/ch00-introduction/function_attributes/src/function_attributes.cairo deleted file mode 100644 index dfe18a90..00000000 --- a/listings/ch00-introduction/function_attributes/src/function_attributes.cairo +++ /dev/null @@ -1,29 +0,0 @@ -#[contract] -mod FunctionAttributes { - - struct Storage { - _value: u32 - } - - // The `set` function is marked as external because it writes to storage (_value) - // and can be called from outside the contract - #[external] - fn set(value: u32) { - _value::write(value); - } - - // The `get` function is marked as view because it doesn't write to storage - // and can be called from outside the contrac - #[view] - fn get() -> u32 { - // We can call an internal function from any functions within the contract - _read_value() - } - - // The `_read_value` function doesn't have any attributes, so it's an internal function - // and can only be called from within the contract - fn _read_value() -> u32 { - _value::read() - } - -} diff --git a/listings/ch00-introduction/function_attributes/src/lib.cairo b/listings/ch00-introduction/function_attributes/src/lib.cairo deleted file mode 100644 index 0828b082..00000000 --- a/listings/ch00-introduction/function_attributes/src/lib.cairo +++ /dev/null @@ -1 +0,0 @@ -mod function_attributes; \ No newline at end of file diff --git a/listings/ch00-introduction/if_else/.gitignore b/listings/ch00-introduction/if_else/.gitignore deleted file mode 100644 index eb5a316c..00000000 --- a/listings/ch00-introduction/if_else/.gitignore +++ /dev/null @@ -1 +0,0 @@ -target diff --git a/listings/ch00-introduction/if_else/Scarb.toml b/listings/ch00-introduction/if_else/Scarb.toml deleted file mode 100644 index f0ebf1bd..00000000 --- a/listings/ch00-introduction/if_else/Scarb.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "if_else" -version = "0.1.0" - -[dependencies] -starknet = "1.1.0" - -[[target.starknet-contract]] \ No newline at end of file diff --git a/listings/ch00-introduction/if_else/src/access_log.cairo b/listings/ch00-introduction/if_else/src/access_log.cairo deleted file mode 100644 index 562a64b9..00000000 --- a/listings/ch00-introduction/if_else/src/access_log.cairo +++ /dev/null @@ -1,37 +0,0 @@ -#[contract] -mod SimpleAccessLog { - // Import the Starknet contract API. - use starknet::{get_caller_address, ContractAddress}; - - struct Storage { - // Add the owner to the contract storage. - _owner: ContractAddress, - } - - #[event] - // Add a welcome event to the contract. - fn WelcomeEvent(name: felt252) {} - - #[constructor] - fn constructor(address: ContractAddress) { - // Set the owner to be the address that deployed the contract. - _owner::write(address); - } - - // Add a function that checks if the caller is the owner. - fn is_owner() -> bool { - return get_caller_address() == _owner::read(); - } - - #[external] - fn log_access() { - // Add a conditional event that welcomes the owner or the user. - if (is_owner()) { - // We know since is_owner() == true, the owner called the function. Call the welcome event with 'Welcome Admin!'. - WelcomeEvent('Welcome Admin!'); - } else { - // We know since is_owner() == false, a normal user(not owner) called the function. Call the welcome event with 'Welcome User!'. - WelcomeEvent('Welcome User!'); - } - } -} diff --git a/listings/ch00-introduction/if_else/src/lib.cairo b/listings/ch00-introduction/if_else/src/lib.cairo deleted file mode 100644 index 527913e1..00000000 --- a/listings/ch00-introduction/if_else/src/lib.cairo +++ /dev/null @@ -1 +0,0 @@ -mod access_log; diff --git a/listings/ch00-introduction/mappings/Scarb.toml b/listings/ch00-introduction/mappings/Scarb.toml index 815a22f4..def4de80 100644 --- a/listings/ch00-introduction/mappings/Scarb.toml +++ b/listings/ch00-introduction/mappings/Scarb.toml @@ -5,6 +5,6 @@ version = "0.1.0" # See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest [dependencies] -starknet = "1.1.0" +starknet = ">=2.0.1" [[target.starknet-contract]] diff --git a/listings/ch00-introduction/mappings/src/mappings.cairo b/listings/ch00-introduction/mappings/src/mappings.cairo index 953317ea..25ddddc5 100644 --- a/listings/ch00-introduction/mappings/src/mappings.cairo +++ b/listings/ch00-introduction/mappings/src/mappings.cairo @@ -1,18 +1,21 @@ -#[contract] +#[starknet::contract] mod MapContract { use starknet::ContractAddress; + #[storage] struct Storage { - _map: LegacyMap::, + map: LegacyMap::, } - #[external] - fn set(key: ContractAddress, value: felt252) { - _map::write(key, value); - } + #[generate_trait] + #[external(v0)] + impl MapContractImpl of IMapContract { + fn set(ref self: ContractState, key: ContractAddress, value: felt252) { + self.map.write(key, value); + } - #[view] - fn get(key: ContractAddress) -> felt252 { - _map::read(key) + fn get(self: @ContractState, key: ContractAddress) -> felt252 { + self.map.read(key) + } } } diff --git a/listings/ch00-introduction/mappings/src/test_mappings.cairo b/listings/ch00-introduction/mappings/src/test_mappings.cairo index 4d44ed61..52b5cb87 100644 --- a/listings/ch00-introduction/mappings/src/test_mappings.cairo +++ b/listings/ch00-introduction/mappings/src/test_mappings.cairo @@ -1,15 +1,15 @@ -#[abi] -trait IMapContract { - #[external] - fn set(key: starknet::ContractAddress, value: felt252); - #[view] - fn get(key: starknet::ContractAddress) -> felt252; +use starknet::ContractAddress; +#[starknet::interface] +trait IMapContract { + fn set(ref self: TContractState, key: ContractAddress, value: felt252); + + fn get(self: @TContractState, key: ContractAddress) -> felt252; } #[cfg(test)] mod tests { use maps::mappings::MapContract; - use super::{IMapContractDispatcher, IMapContractDispatcherTrait}; + use super::{IMapContract, IMapContractDispatcher, IMapContractDispatcherTrait}; use debug::PrintTrait; use starknet::{deploy_syscall, ContractAddress}; use option::OptionTrait; diff --git a/listings/ch00-introduction/storing_arrays/Scarb.toml b/listings/ch00-introduction/storing_arrays/Scarb.toml index 2933a077..a7f9a809 100644 --- a/listings/ch00-introduction/storing_arrays/Scarb.toml +++ b/listings/ch00-introduction/storing_arrays/Scarb.toml @@ -5,7 +5,6 @@ version = "0.1.0" # See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest [dependencies] -starknet = "1.1.0" +starknet = ">=2.0.1" -[[target.starknet-contract]] -allowed-libfuncs-list.name = "experimental_v0.1.0" \ No newline at end of file +[[target.starknet-contract]] \ No newline at end of file diff --git a/listings/ch00-introduction/storing_arrays/src/storing_arrays.cairo b/listings/ch00-introduction/storing_arrays/src/storing_arrays.cairo index 6280f3b4..c73e7c31 100644 --- a/listings/ch00-introduction/storing_arrays/src/storing_arrays.cairo +++ b/listings/ch00-introduction/storing_arrays/src/storing_arrays.cairo @@ -7,99 +7,110 @@ use starknet::{ StorageBaseAddress, StorageAccess, SyscallResult, storage_read_syscall, storage_write_syscall, storage_address_from_base_and_offset }; - +use debug::PrintTrait; // ANCHOR: StorageAccessImpl impl StorageAccessFelt252Array of StorageAccess> { fn read(address_domain: u32, base: StorageBaseAddress) -> SyscallResult> { + StorageAccessFelt252Array::read_at_offset_internal(address_domain, base, 0) + } + fn write( + address_domain: u32, base: StorageBaseAddress, value: Array + ) -> SyscallResult<()> { + StorageAccessFelt252Array::write_at_offset_internal(address_domain, base, 0, value) + } + fn read_at_offset_internal( + address_domain: u32, base: StorageBaseAddress, mut offset: u8 + ) -> SyscallResult> { let mut arr: Array = ArrayTrait::new(); - // Read the stored array's length. - let len: u8 = StorageAccess::::read(address_domain, base) - .expect('Failed to read array length'); - - // This implementation limits the stored array's length to 255. - assert(len <= 255, 'Storage Span too large'); + // Read the stored array's length. If the length is superior to 255, the read will fail. + let len: u8 = StorageAccess::::read_at_offset_internal(address_domain, base, offset) + .expect('Storage Span too large'); + offset += 1; // Sequentially read all stored elements and append them to the array. - let mut i: u8 = 1; + let exit = len + offset; loop { - if i > len { - break (); + if offset >= exit { + break; } - match storage_read_syscall( - :address_domain, address: storage_address_from_base_and_offset(base, i) - ) { - Result::Ok(value) => { - arr.append(value); - }, - Result::Err(_) => { - panic_with_felt252('Storage - Span read error') - } - } - i += 1; + let value = StorageAccess::::read_at_offset_internal( + address_domain, base, offset + ) + .unwrap(); + arr.append(value); + offset += StorageAccess::::size_internal(value); }; // Return the array. Result::Ok(arr) } - fn write( - address_domain: u32, base: StorageBaseAddress, mut value: Array + fn write_at_offset_internal( + address_domain: u32, base: StorageBaseAddress, mut offset: u8, mut value: Array ) -> SyscallResult<()> { - // Store the length of the array in the first storage slot. + // // Store the length of the array in the first storage slot. let len: u8 = value.len().try_into().expect('Storage - Span too large'); - StorageAccess::::write(address_domain, base, len.into()); + StorageAccess::::write_at_offset_internal(address_domain, base, offset, len); + offset += 1; // Store the array elements sequentially - let mut i = 1; loop { match value.pop_front() { Option::Some(element) => { - storage_write_syscall( - :address_domain, - address: storage_address_from_base_and_offset(base, i), - value: element - ); + StorageAccess::::write_at_offset_internal( + address_domain, base, offset, element + )?; + offset += StorageAccess::::size_internal(element); }, Option::None(_) => { - break (); + break Result::Ok(()); } - } - i += 1; - }; - Result::Ok(()) + }; + } } -} -// ANCHOR_END: StorageAccessImpl -#[abi] -trait IStoreArrayContract { - fn store_array(array: Array); - fn read_array() -> Array; + fn size_internal(value: Array) -> u8 { + if value.len() == 0 { + return 1; + } + 1_u8 + StorageAccess::::size_internal(*value[0]) * value.len().try_into().unwrap() + } } +// ANCHOR_END: StorageAccessImpl // ANCHOR: StoreArrayContract -#[contract] +#[starknet::contract] mod StoreArrayContract { - use array::ArrayTrait; use super::StorageAccessFelt252Array; + + #[storage] struct Storage { - _array: Array + arr: Array } - #[external] - fn store_array(array: Array) { - _array::write(array); - } - #[view] - fn read_array() -> Array { - _array::read() + #[generate_trait] + #[external(v0)] + impl StoreArrayImpl of IStoreArrayContract { + fn store_array(ref self: ContractState, arr: Array) { + self.arr.write(arr); + } + + fn read_array(self: @ContractState) -> Array { + self.arr.read() + } } } // ANCHOR_END: StoreArrayContract +#[starknet::interface] +trait IStoreArrayContract { + fn store_array(ref self: TContractState, array: Array); + fn read_array(self: @TContractState) -> Array; +} + #[cfg(test)] mod tests { use super::StoreArrayContract; diff --git a/listings/ch00-introduction/variables/Scarb.toml b/listings/ch00-introduction/variables/Scarb.toml index 78d22b2d..d5a11173 100644 --- a/listings/ch00-introduction/variables/Scarb.toml +++ b/listings/ch00-introduction/variables/Scarb.toml @@ -5,6 +5,6 @@ version = "0.1.0" # See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest [dependencies] -starknet = "1.1.0" +starknet = ">=2.0.1" [[target.starknet-contract]] \ No newline at end of file diff --git a/listings/ch00-introduction/variables/src/global_variables.cairo b/listings/ch00-introduction/variables/src/global_variables.cairo index 01c93665..a96788b5 100644 --- a/listings/ch00-introduction/variables/src/global_variables.cairo +++ b/listings/ch00-introduction/variables/src/global_variables.cairo @@ -1,12 +1,18 @@ -#[contract] +#[starknet::contract] mod GlobalExample { // import the library function and types from the starknet core library use starknet::get_caller_address; - #[external] - fn foo() { - // Call the get_caller_address function to get the sender address - let caller = get_caller_address(); - // ... + #[storage] + struct Storage {} + + #[generate_trait] + #[external(v0)] + impl GlobalExampleImpl of IGlobalExample { + fn foo(ref self: ContractState) { + // Call the get_caller_address function to get the sender address + let caller = get_caller_address(); + // ... + } } } diff --git a/listings/ch00-introduction/variables/src/local_variables.cairo b/listings/ch00-introduction/variables/src/local_variables.cairo index 5e433af1..c33a8de3 100644 --- a/listings/ch00-introduction/variables/src/local_variables.cairo +++ b/listings/ch00-introduction/variables/src/local_variables.cairo @@ -1,14 +1,20 @@ -#[contract] +#[starknet::contract] mod LocalVariablesExample { - #[view] - fn do_something(value: u32) -> u32 { - // Declare a new local variable in the function - let increment = 10; + #[storage] + struct Storage {} - { - // The scope of a code block allows for local variable declaration - let sum = value + increment; - sum + #[generate_trait] + #[external(v0)] + impl LocalVariablesExampleImpl of ILocalVariablsExample { + fn do_something(self: @ContractState, value: u32) -> u32 { + // Declare a new local variable in the function + let increment = 10; + + { + // The scope of a code block allows for local variable declaration + let sum = value + increment; + sum + } } } } diff --git a/listings/ch00-introduction/variables/src/storage_variables.cairo b/listings/ch00-introduction/variables/src/storage_variables.cairo index 5f483d55..60248980 100644 --- a/listings/ch00-introduction/variables/src/storage_variables.cairo +++ b/listings/ch00-introduction/variables/src/storage_variables.cairo @@ -1,20 +1,24 @@ -#[contract] +#[starknet::contract] mod StorageVariablesExample { // All storage variables are contained in a struct called Storage + // annotated with the `#[storage]` attribute + #[storage] struct Storage { // Storage variable holding a number - _value: u32 + value: u32 } - #[external] - // Write to storage variables by sending a transaction that calls an external function - fn set(value: u32) { - _value::write(value); - } + #[generate_trait] + #[external(v0)] + impl StorageVariablesExample of IStorageVariableExample { + // Write to storage variables by sending a transaction that calls an external function + fn set(ref self: ContractState, value: u32) { + self.value.write(value); + } - #[view] - // Read from storage variables without sending transactions - fn get() -> u32 { - _value::read() + // Read from storage variables without sending transactions + fn get(ref self: ContractState) -> u32 { + self.value.read() + } } } diff --git a/listings/ch00-introduction/function_attributes/.gitignore b/listings/ch00-introduction/visibility/.gitignore similarity index 100% rename from listings/ch00-introduction/function_attributes/.gitignore rename to listings/ch00-introduction/visibility/.gitignore diff --git a/listings/ch00-introduction/function_attributes/Scarb.toml b/listings/ch00-introduction/visibility/Scarb.toml similarity index 78% rename from listings/ch00-introduction/function_attributes/Scarb.toml rename to listings/ch00-introduction/visibility/Scarb.toml index 00136ec0..5bd6e265 100644 --- a/listings/ch00-introduction/function_attributes/Scarb.toml +++ b/listings/ch00-introduction/visibility/Scarb.toml @@ -1,10 +1,10 @@ [package] -name = "function_attributes" +name = "visibility" version = "0.1.0" # See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest [dependencies] -starknet = "1.1.0" +starknet = ">=2.0.1" [[target.starknet-contract]] \ No newline at end of file diff --git a/listings/ch00-introduction/visibility/src/lib.cairo b/listings/ch00-introduction/visibility/src/lib.cairo new file mode 100644 index 00000000..9a3c237d --- /dev/null +++ b/listings/ch00-introduction/visibility/src/lib.cairo @@ -0,0 +1 @@ +mod visibility; diff --git a/listings/ch00-introduction/visibility/src/visibility.cairo b/listings/ch00-introduction/visibility/src/visibility.cairo new file mode 100644 index 00000000..62c62477 --- /dev/null +++ b/listings/ch00-introduction/visibility/src/visibility.cairo @@ -0,0 +1,35 @@ +#[starknet::contract] +mod VisiblityContract { + #[storage] + struct Storage { + value: u32 + } + + + #[generate_trait] + #[external(v0)] + impl VisiblityContract of IVisibilityContract { + // The `set` function can be called externally because it is written inside an implementation marked as `#[external]`. + // It can modify the contract's state as it is passed as a reference. + fn set(ref self: ContractState,value: u32) { + self.value.write(value); + } + + // The `set` function can be called externally because it is written inside an implementation marked as `#[external]`. + // However, it can't modify the contract's state is passed as a snapshot: it is only a "view" function. + fn get(self: @ContractState) -> u32 { + // We can call an internal function from any functions within the contract + PrivateFunctionsTrait::_read_value(self) + } + } + + #[generate_trait] + impl PrivateFunctions of PrivateFunctionsTrait { + // The `_read_value` function is outside the implementation that is marked as `#[external(v0)]`, so it's an _internal_ function + // and can only be called from within the contract. + // It can modify the contract's state as it is passed as a reference. + fn _read_value(self: @ContractState) -> u32 { + self.value.read() + } + } +} diff --git a/listings/ch00-introduction/write_to_any_slot/Scarb.toml b/listings/ch00-introduction/write_to_any_slot/Scarb.toml index 8dda6abe..96fcc699 100644 --- a/listings/ch00-introduction/write_to_any_slot/Scarb.toml +++ b/listings/ch00-introduction/write_to_any_slot/Scarb.toml @@ -5,7 +5,6 @@ version = "0.1.0" # See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest [dependencies] -starknet = "1.1.0" +starknet = ">=2.0.1" -[[target.starknet-contract]] -allowed-libfuncs-list.name = "experimental_v0.1.0" \ No newline at end of file +[[target.starknet-contract]] \ No newline at end of file diff --git a/listings/ch00-introduction/write_to_any_slot/src/test_write_any_slot.cairo b/listings/ch00-introduction/write_to_any_slot/src/test_write_any_slot.cairo index 10c25fe0..9f02e693 100644 --- a/listings/ch00-introduction/write_to_any_slot/src/test_write_any_slot.cairo +++ b/listings/ch00-introduction/write_to_any_slot/src/test_write_any_slot.cairo @@ -1,9 +1,9 @@ use write_to_any_slot::write_any_slot::WriteToAnySlot; -#[abi] -trait IWriteToAnySlot { - fn write_slot(value: u32); - fn read_slot() -> u32; +#[starknet::interface] +trait IWriteToAnySlot { + fn write_slot(ref self: TContractState, value: u32); + fn read_slot(self: @TContractState) -> u32; } #[cfg(test)] diff --git a/listings/ch00-introduction/write_to_any_slot/src/write_any_slot.cairo b/listings/ch00-introduction/write_to_any_slot/src/write_any_slot.cairo index 5cab00b1..c55b52df 100644 --- a/listings/ch00-introduction/write_to_any_slot/src/write_any_slot.cairo +++ b/listings/ch00-introduction/write_to_any_slot/src/write_any_slot.cairo @@ -1,4 +1,4 @@ -#[contract] +#[starknet::contract] mod WriteToAnySlot { use starknet::syscalls::{storage_read_syscall, storage_write_syscall}; use array::ArrayTrait; @@ -8,23 +8,25 @@ mod WriteToAnySlot { use starknet::storage_access::Felt252TryIntoStorageAddress; use starknet::StorageAddress; + #[storage] struct Storage {} const SLOT_NAME: felt252 = 'test_slot'; - #[external] - fn write_slot(value: u32) { - storage_write_syscall(0, get_address_from_name(SLOT_NAME), value.into()); - } + #[generate_trait] + #[external(v0)] + impl WriteToAnySlot of IWriteToAnySlot { + fn write_slot(ref self: ContractState, value: u32) { + storage_write_syscall(0, get_address_from_name(SLOT_NAME), value.into()); + } - #[view] - fn read_slot() -> u32 { - storage_read_syscall(0, get_address_from_name(SLOT_NAME)) - .unwrap_syscall() - .try_into() - .unwrap() + fn read_slot(self: @ContractState) -> u32 { + storage_read_syscall(0, get_address_from_name(SLOT_NAME)) + .unwrap_syscall() + .try_into() + .unwrap() + } } - fn get_address_from_name(variable_name: felt252) -> StorageAddress { let mut data: Array = ArrayTrait::new(); data.append(variable_name); diff --git a/listings/ch01-applications/simple_vault/Scarb.toml b/listings/ch01-applications/simple_vault/Scarb.toml index 2c7de185..5df740cb 100644 --- a/listings/ch01-applications/simple_vault/Scarb.toml +++ b/listings/ch01-applications/simple_vault/Scarb.toml @@ -5,7 +5,6 @@ version = "0.1.0" # See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest [dependencies] -starknet = "1.1.0" +starknet = ">=2.0.1" -[[target.starknet-contract]] -allowed-libfuncs-list.name = "experimental_v0.1.0" \ No newline at end of file +[[target.starknet-contract]] \ No newline at end of file diff --git a/listings/ch01-applications/simple_vault/src/simple_vault.cairo b/listings/ch01-applications/simple_vault/src/simple_vault.cairo index 976475c2..8151fd82 100644 --- a/listings/ch01-applications/simple_vault/src/simple_vault.cairo +++ b/listings/ch01-applications/simple_vault/src/simple_vault.cairo @@ -1,109 +1,95 @@ use starknet::{ContractAddress}; // In order to make contract calls within our Vault, -// we need to have the ABI of the remote contract defined to import the Dispatcher -#[abi] -trait IERC20 { - #[view] - fn name() -> felt252; - - #[view] - fn symbol() -> felt252; - - #[view] - fn decimals() -> u8; - - #[view] - fn total_supply() -> u256; - - #[view] - fn balance_of(account: ContractAddress) -> u256; - - #[view] - fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256; - - #[external] - fn transfer(recipient: ContractAddress, amount: u256) -> bool; - - #[external] - fn transfer_from(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool; - - #[external] - fn approve(spender: ContractAddress, amount: u256) -> bool; +// we need to have the interface of the remote contract defined to import the Dispatcher +#[starknet::interface] +trait IERC20 { + fn name(self: @TContractState) -> felt252; + fn symbol(self: @TContractState) -> felt252; + fn decimals(self: @TContractState) -> u8; + fn total_supply(self: @TContractState) -> u256; + fn balance_of(self: @TContractState, account: ContractAddress) -> u256; + fn allowance(self: @TContractState, owner: ContractAddress, spender: ContractAddress) -> u256; + fn transfer(ref self: TContractState, recipient: ContractAddress, amount: u256) -> bool; + fn transfer_from( + ref self: TContractState, sender: ContractAddress, recipient: ContractAddress, amount: u256 + ) -> bool; + fn approve(ref self: TContractState, spender: ContractAddress, amount: u256) -> bool; } -#[contract] +#[starknet::contract] mod SimpleVault { use super::{IERC20Dispatcher, IERC20DispatcherTrait}; - use starknet::{ - ContractAddress, - get_caller_address, - get_contract_address - }; - + use starknet::{ContractAddress, get_caller_address, get_contract_address}; + #[storage] struct Storage { - _token: IERC20Dispatcher, - _total_supply: u256, - _balance_of: LegacyMap + token: IERC20Dispatcher, + total_supply: u256, + balance_of: LegacyMap } #[constructor] - fn constructor(token: ContractAddress) { - _token::write(IERC20Dispatcher { contract_address: token }); + fn constructor(ref self: ContractState, token: ContractAddress) { + self.token.write(IERC20Dispatcher { contract_address: token }); } - fn _mint(to: ContractAddress, shares: u256) { - _total_supply::write(_total_supply::read() + shares); - _balance_of::write(to, _balance_of::read(to) + shares); - } - - fn _burn(from: ContractAddress, shares: u256) { - _total_supply::write(_total_supply::read() - shares); - _balance_of::write(from, _balance_of::read(from) - shares); - } - - #[external] - fn deposit(amount: u256) { - // a = amount - // B = balance of token before deposit - // T = total supply - // s = shares to mint - // - // (T + s) / T = (a + B) / B - // - // s = aT / B - let caller = get_caller_address(); - let this = get_contract_address(); - - let mut shares = 0; - if _total_supply::read() == 0 { - shares = amount; - } else { - let balance = _token::read().balance_of(this); - shares = (amount * _total_supply::read()) / balance; + #[generate_trait] + impl PrivateFunctions of PrivateFunctionsTrait { + fn _mint(ref self: ContractState, to: ContractAddress, shares: u256) { + self.total_supply.write(self.total_supply.read() + shares); + self.balance_of.write(to, self.balance_of.read(to) + shares); } - _mint(caller, shares); - _token::read().transfer_from(caller, this, amount); + fn _burn(ref self: ContractState, from: ContractAddress, shares: u256) { + self.total_supply.write(self.total_supply.read() - shares); + self.balance_of.write(from, self.balance_of.read(from) - shares); + } } - #[external] - fn withdraw(shares: u256) { - // a = amount - // B = balance of token before withdraw - // T = total supply - // s = shares to burn - // - // (T - s) / T = (B - a) / B - // - // a = sB / T - let caller = get_caller_address(); - let this = get_contract_address(); + #[external(v0)] + #[generate_trait] + impl SimpleVault of ISimpleVault { + fn deposit(ref self: ContractState, amount: u256) { + // a = amount + // B = balance of token before deposit + // T = total supply + // s = shares to mint + // + // (T + s) / T = (a + B) / B + // + // s = aT / B + let caller = get_caller_address(); + let this = get_contract_address(); + + let mut shares = 0; + if self.total_supply.read() == 0 { + shares = amount; + } else { + let balance = self.token.read().balance_of(this); + shares = (amount * self.total_supply.read()) / balance; + } + + PrivateFunctions::_mint(ref self, caller, shares); + self.token.read().transfer_from(caller, this, amount); + } - let balance = _token::read().balance_of(this); - let amount = (shares * balance) / _total_supply::read(); - _burn(caller, shares); - _token::read().transfer(caller, amount); + fn withdraw(ref self: ContractState, shares: u256) { + // a = amount + // B = balance of token before withdraw + // T = total supply + // s = shares to burn + // + // (T - s) / T = (B - a) / B + // + // a = sB / T + let caller = get_caller_address(); + let this = get_contract_address(); + + let balance = self.token.read().balance_of(this); + let amount = (shares * balance) / self.total_supply.read(); + PrivateFunctions::_burn(ref self, caller, shares); + self.token.read().transfer(caller, amount); + } } } diff --git a/listings/ch01-applications/upgradeable_contract/Scarb.toml b/listings/ch01-applications/upgradeable_contract/Scarb.toml index efdcd521..2203f76b 100644 --- a/listings/ch01-applications/upgradeable_contract/Scarb.toml +++ b/listings/ch01-applications/upgradeable_contract/Scarb.toml @@ -5,6 +5,6 @@ version = "0.1.0" # See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest [dependencies] -starknet = "1.1.0" +starknet = ">=2.0.1" [[target.starknet-contract]] \ No newline at end of file diff --git a/listings/ch01-applications/upgradeable_contract/src/upgradeable_contract_v0.cairo b/listings/ch01-applications/upgradeable_contract/src/upgradeable_contract_v0.cairo index d4e85005..f4bb24f0 100644 --- a/listings/ch01-applications/upgradeable_contract/src/upgradeable_contract_v0.cairo +++ b/listings/ch01-applications/upgradeable_contract/src/upgradeable_contract_v0.cairo @@ -1,24 +1,36 @@ -#[contract] +#[starknet::contract] mod UpgradeableContract_V0 { use starknet::class_hash::ClassHash; use zeroable::Zeroable; use result::ResultTrait; use starknet::SyscallResult; + #[storage] struct Storage {} + #[event] - fn Upgraded(implementation: ClassHash) {} + #[derive(Drop, starknet::Event)] + enum Event { + Upgraded: Upgraded + } - #[external] - fn upgrade(impl_hash: ClassHash) { - assert(!impl_hash.is_zero(), 'Class hash cannot be zero'); - starknet::replace_class_syscall(impl_hash).unwrap_syscall(); - Upgraded(impl_hash); + #[derive(Drop, starknet::Event)] + struct Upgraded { + implementation: ClassHash } - #[view] - fn version() -> u8 { - 0 + #[generate_trait] + #[external(v0)] + impl UpgradeableContract of IUpgradeableContract { + fn upgrade(ref self: ContractState, impl_hash: ClassHash) { + assert(!impl_hash.is_zero(), 'Class hash cannot be zero'); + starknet::replace_class_syscall(impl_hash).unwrap_syscall(); + self.emit(Event::Upgraded(Upgraded { implementation: impl_hash })) + } + + fn version(self: @ContractState) -> u8 { + 0 + } } } diff --git a/listings/ch01-applications/upgradeable_contract/src/upgradeable_contract_v1.cairo b/listings/ch01-applications/upgradeable_contract/src/upgradeable_contract_v1.cairo index 293b9701..7295cee5 100644 --- a/listings/ch01-applications/upgradeable_contract/src/upgradeable_contract_v1.cairo +++ b/listings/ch01-applications/upgradeable_contract/src/upgradeable_contract_v1.cairo @@ -1,24 +1,36 @@ -#[contract] +#[starknet::contract] mod UpgradeableContract_V1 { use starknet::class_hash::ClassHash; use zeroable::Zeroable; use result::ResultTrait; use starknet::SyscallResult; + #[storage] struct Storage {} + #[event] - fn Upgraded(implementation: ClassHash) {} + #[derive(Drop, starknet::Event)] + enum Event { + Upgraded: Upgraded + } - #[external] - fn upgrade(impl_hash: ClassHash) { - assert(!impl_hash.is_zero(), 'Class hash cannot be zero'); - starknet::replace_class_syscall(impl_hash).unwrap_syscall(); - Upgraded(impl_hash); + #[derive(Drop, starknet::Event)] + struct Upgraded { + implementation: ClassHash } - #[view] - fn version() -> u8 { - 1 + #[generate_trait] + #[external(v0)] + impl UpgradeableContract of IUpgradeableContract { + fn upgrade(ref self: ContractState, impl_hash: ClassHash) { + assert(!impl_hash.is_zero(), 'Class hash cannot be zero'); + starknet::replace_class_syscall(impl_hash).unwrap_syscall(); + self.emit(Event::Upgraded(Upgraded { implementation: impl_hash })) + } + + fn version(self: @ContractState) -> u8 { + 1 + } } } diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 869aa2e1..c11208cb 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -10,7 +10,7 @@ Summary - [Storing Arrays](./ch00-05-storing_arrays.md) - [Mappings](./ch00-06-mappings.md) - [Constructors](./ch00-07-constructor.md) - - [Function Attributes](./ch00-08-function_attributes.md) + - [Function Attributes](./ch00-08-visibility.md) - [If statements](./ch00-09-if_statements.md) - [Events](./ch00-10-events.md) - [Counter](./ch00-11-counter.md) diff --git a/src/ch00-08-function_attributes.md b/src/ch00-08-function_attributes.md index f30de36e..351faa8f 100644 --- a/src/ch00-08-function_attributes.md +++ b/src/ch00-08-function_attributes.md @@ -13,5 +13,5 @@ Let's explore the three main types of functions you can use: Let's take a look at a simple example contract to see these attributes in action: ```rust -{{#include ../listings/ch00-introduction/function_attributes/src/function_attributes.cairo}} +{{#include ../listings/ch00-introduction/visibility/src/visibility.cairo}} ``` From f619df2cbd3555f2b4fcbfb4fec8bbf8b3cbfcc1 Mon Sep 17 00:00:00 2001 From: msaug Date: Thu, 6 Jul 2023 21:32:04 +0200 Subject: [PATCH 3/4] refactor: update to v2.0.x --- .../calling_other_contracts/src/callee.cairo | 9 ++---- .../calling_other_contracts/src/caller.cairo | 10 +++---- .../constructor/src/lib.cairo | 4 ++- .../counter/src/counter.cairo | 5 ++-- .../errors/src/custom_errors.cairo | 2 +- .../errors/src/simple_errors.cairo | 2 +- .../errors/src/vault_errors.cairo | 2 +- .../events/src/counter.cairo | 6 +++- .../mappings/src/mappings.cairo | 3 +- .../storing_arrays/src/storing_arrays.cairo | 2 ++ .../variables/src/global_variables.cairo | 2 +- .../variables/src/local_variables.cairo | 5 ++-- .../visibility/src/visibility.cairo | 10 +++++-- .../simple_vault/src/simple_vault.cairo | 2 +- src/SUMMARY.md | 15 +++++----- src/ch00-00-introduction.md | 2 +- src/ch00-03-calling_other_contracts.md | 2 +- src/ch00-04-write_to_any_slot.md | 6 ++-- src/ch00-08-function_attributes.md | 17 ----------- src/ch00-08-visibility-mutability.md | 29 +++++++++++++++++++ src/ch00-09-if_statements.md | 11 ------- src/ch00-10-events.md | 3 +- src/ch00-11-counter.md | 2 +- 23 files changed, 80 insertions(+), 71 deletions(-) delete mode 100644 src/ch00-08-function_attributes.md create mode 100644 src/ch00-08-visibility-mutability.md delete mode 100644 src/ch00-09-if_statements.md diff --git a/listings/ch00-introduction/calling_other_contracts/src/callee.cairo b/listings/ch00-introduction/calling_other_contracts/src/callee.cairo index d2ef1aaf..25ed8680 100644 --- a/listings/ch00-introduction/calling_other_contracts/src/callee.cairo +++ b/listings/ch00-introduction/calling_other_contracts/src/callee.cairo @@ -1,9 +1,3 @@ -#[starknet::interface] -trait ICallee { - fn set_value(ref self: TContractState, value: u128) -> u128; -} - - #[starknet::contract] mod Callee { #[storage] @@ -12,7 +6,8 @@ mod Callee { } #[external(v0)] - impl ICalleeImpl of super::ICallee { + #[generate_trait] + impl ICalleeImpl of ICallee { fn set_value(ref self: ContractState, value: u128) -> u128 { self.value.write(value); value diff --git a/listings/ch00-introduction/calling_other_contracts/src/caller.cairo b/listings/ch00-introduction/calling_other_contracts/src/caller.cairo index 1cb9ede4..1378936e 100644 --- a/listings/ch00-introduction/calling_other_contracts/src/caller.cairo +++ b/listings/ch00-introduction/calling_other_contracts/src/caller.cairo @@ -1,9 +1,7 @@ use starknet::ContractAddress; -#[starknet::interface] -trait ICaller { - fn set_value_from_address(ref self: TContractState, addr: ContractAddress, value: u128); -} +// We need to have the interface of the callee contract defined +// so that we can import the Dispatcher. #[starknet::interface] trait ICallee { fn set_value(ref self: TContractState, value: u128) -> u128; @@ -11,14 +9,16 @@ trait ICallee { #[starknet::contract] mod Caller { + // We import the Dispatcher of the called contract use super::{ICalleeDispatcher, ICalleeDispatcherTrait}; use starknet::ContractAddress; #[storage] struct Storage {} + #[generate_trait] #[external(v0)] - impl ICallerImpl of super::ICaller { + impl ICallerImpl of ICaller { fn set_value_from_address(ref self: ContractState, addr: ContractAddress, value: u128) { ICalleeDispatcher { contract_address: addr }.set_value(value); } diff --git a/listings/ch00-introduction/constructor/src/lib.cairo b/listings/ch00-introduction/constructor/src/lib.cairo index a6db7d61..7bebaa31 100644 --- a/listings/ch00-introduction/constructor/src/lib.cairo +++ b/listings/ch00-introduction/constructor/src/lib.cairo @@ -1,5 +1,5 @@ #[starknet::contract] -mod example_constructor { +mod ExampleConstructor { use starknet::ContractAddress; #[storage] @@ -7,6 +7,8 @@ mod example_constructor { names: LegacyMap::, } + // The constructor is decorated with a `#[constructor]` attribute. + // It is not inside an `impl` block. #[constructor] fn constructor(ref self: ContractState, name: felt252, address: ContractAddress) { self.names.write(address, name); diff --git a/listings/ch00-introduction/counter/src/counter.cairo b/listings/ch00-introduction/counter/src/counter.cairo index 903b8dec..01acb7e0 100644 --- a/listings/ch00-introduction/counter/src/counter.cairo +++ b/listings/ch00-introduction/counter/src/counter.cairo @@ -7,15 +7,16 @@ trait ISimpleCounter { #[starknet::contract] -mod simple_counter { +mod SimpleCounter { #[storage] struct Storage { // Counter variable counter: u256, } + #[generate_trait] #[external(v0)] - impl SimpleCounterImpl of super::ISimpleCounter { + impl SimpleCounter of ISimpleCounter { fn get_current_count(self: @ContractState) -> u256 { return self.counter.read(); } diff --git a/listings/ch00-introduction/errors/src/custom_errors.cairo b/listings/ch00-introduction/errors/src/custom_errors.cairo index 189c780f..303f5738 100644 --- a/listings/ch00-introduction/errors/src/custom_errors.cairo +++ b/listings/ch00-introduction/errors/src/custom_errors.cairo @@ -13,7 +13,7 @@ mod CustomErrorsExample { #[generate_trait] #[external(v0)] - impl CustomErrorsExampleImpl of CustomErrorsExampleTrait { + impl CustomErrorsExample of ICustomErrorsExample{ fn test_assert(self: @ContractState, i: u256) { assert(i > 0, Errors::NOT_POSITIVE); } diff --git a/listings/ch00-introduction/errors/src/simple_errors.cairo b/listings/ch00-introduction/errors/src/simple_errors.cairo index ffec9f0d..593ef563 100644 --- a/listings/ch00-introduction/errors/src/simple_errors.cairo +++ b/listings/ch00-introduction/errors/src/simple_errors.cairo @@ -5,7 +5,7 @@ mod ErrorsExample { #[generate_trait] #[external(v0)] - impl ErrorsExampleImpl of ErrorsExampleTrait { + impl ErrorsExample of IErrorsExample { fn test_assert(self: @ContractState, i: u256) { // Assert used to validate a condition // and abort execution if the condition is not met diff --git a/listings/ch00-introduction/errors/src/vault_errors.cairo b/listings/ch00-introduction/errors/src/vault_errors.cairo index 7c10277e..0d7d7082 100644 --- a/listings/ch00-introduction/errors/src/vault_errors.cairo +++ b/listings/ch00-introduction/errors/src/vault_errors.cairo @@ -14,7 +14,7 @@ mod VaultErrorsExample { #[generate_trait] #[external(v0)] - impl VaultErrorsExampleImpl of VaultErrorsExampleTrait { + impl VaultErrorsExample of IVaultErrorsExample { fn deposit(ref self: ContractState, amount: u256) { let mut balance = self.balance.read(); balance = balance + amount; diff --git a/listings/ch00-introduction/events/src/counter.cairo b/listings/ch00-introduction/events/src/counter.cairo index a039a5b2..88a32af3 100644 --- a/listings/ch00-introduction/events/src/counter.cairo +++ b/listings/ch00-introduction/events/src/counter.cairo @@ -8,10 +8,14 @@ mod EventCounter { #[event] #[derive(Drop, starknet::Event)] + // The event enum must be annotated with the `#[event]` attribute. + // It must also derive the `Drop` and `starknet::Event` traits. enum Event { CounterIncreased: CounterIncreased } + // By deriving the `starknet::Event` trait, we indicate to the compiler that + // this struct will be used when emitting events. #[derive(Drop, starknet::Event)] struct CounterIncreased { amount: u128 @@ -19,7 +23,7 @@ mod EventCounter { #[generate_trait] #[external(v0)] - impl EventCounterImpl of EventCounterTrait { + impl EventCounter of IEventCounter { fn increment(ref self: ContractState) { let mut counter = self.counter.read(); counter += 1; diff --git a/listings/ch00-introduction/mappings/src/mappings.cairo b/listings/ch00-introduction/mappings/src/mappings.cairo index 25ddddc5..06ce7dc9 100644 --- a/listings/ch00-introduction/mappings/src/mappings.cairo +++ b/listings/ch00-introduction/mappings/src/mappings.cairo @@ -4,7 +4,8 @@ mod MapContract { #[storage] struct Storage { - map: LegacyMap::, + // The `LegacyMap` type is only available inside the `Storage` struct. + map: LegacyMap::, } #[generate_trait] diff --git a/listings/ch00-introduction/storing_arrays/src/storing_arrays.cairo b/listings/ch00-introduction/storing_arrays/src/storing_arrays.cairo index c73e7c31..ff9cba27 100644 --- a/listings/ch00-introduction/storing_arrays/src/storing_arrays.cairo +++ b/listings/ch00-introduction/storing_arrays/src/storing_arrays.cairo @@ -13,11 +13,13 @@ impl StorageAccessFelt252Array of StorageAccess> { fn read(address_domain: u32, base: StorageBaseAddress) -> SyscallResult> { StorageAccessFelt252Array::read_at_offset_internal(address_domain, base, 0) } + fn write( address_domain: u32, base: StorageBaseAddress, value: Array ) -> SyscallResult<()> { StorageAccessFelt252Array::write_at_offset_internal(address_domain, base, 0, value) } + fn read_at_offset_internal( address_domain: u32, base: StorageBaseAddress, mut offset: u8 ) -> SyscallResult> { diff --git a/listings/ch00-introduction/variables/src/global_variables.cairo b/listings/ch00-introduction/variables/src/global_variables.cairo index a96788b5..11fc757a 100644 --- a/listings/ch00-introduction/variables/src/global_variables.cairo +++ b/listings/ch00-introduction/variables/src/global_variables.cairo @@ -1,6 +1,6 @@ #[starknet::contract] mod GlobalExample { - // import the library function and types from the starknet core library + // import the required functions from the starknet core library use starknet::get_caller_address; #[storage] diff --git a/listings/ch00-introduction/variables/src/local_variables.cairo b/listings/ch00-introduction/variables/src/local_variables.cairo index c33a8de3..33daa2ae 100644 --- a/listings/ch00-introduction/variables/src/local_variables.cairo +++ b/listings/ch00-introduction/variables/src/local_variables.cairo @@ -5,13 +5,14 @@ mod LocalVariablesExample { #[generate_trait] #[external(v0)] - impl LocalVariablesExampleImpl of ILocalVariablsExample { + impl LocalVariablesExample of ILocalVariablesExample { fn do_something(self: @ContractState, value: u32) -> u32 { - // Declare a new local variable in the function + // This variable is local to the current block. It can't be accessed once it goes out of scope. let increment = 10; { // The scope of a code block allows for local variable declaration + // We can access variables defined in higher scopes. let sum = value + increment; sum } diff --git a/listings/ch00-introduction/visibility/src/visibility.cairo b/listings/ch00-introduction/visibility/src/visibility.cairo index 62c62477..4f8231de 100644 --- a/listings/ch00-introduction/visibility/src/visibility.cairo +++ b/listings/ch00-introduction/visibility/src/visibility.cairo @@ -6,16 +6,18 @@ mod VisiblityContract { } - #[generate_trait] + // The `external(v0)` attribute indicates that all the functions in this implementation can be called externally. + // Omitting this attribute would make all the functions in this implementation internal. #[external(v0)] + #[generate_trait] impl VisiblityContract of IVisibilityContract { // The `set` function can be called externally because it is written inside an implementation marked as `#[external]`. // It can modify the contract's state as it is passed as a reference. - fn set(ref self: ContractState,value: u32) { + fn set(ref self: ContractState, value: u32) { self.value.write(value); } - // The `set` function can be called externally because it is written inside an implementation marked as `#[external]`. + // The `get` function can be called externally because it is written inside an implementation marked as `#[external]`. // However, it can't modify the contract's state is passed as a snapshot: it is only a "view" function. fn get(self: @ContractState) -> u32 { // We can call an internal function from any functions within the contract @@ -23,6 +25,8 @@ mod VisiblityContract { } } + // The lack of the `external` attribute indicates that all the functions in this implementation can only be called internally. + // We name the trait `PrivateFunctionsTrait` to indicate that it is an internal trait allowing us to call internal functions. #[generate_trait] impl PrivateFunctions of PrivateFunctionsTrait { // The `_read_value` function is outside the implementation that is marked as `#[external(v0)]`, so it's an _internal_ function diff --git a/listings/ch01-applications/simple_vault/src/simple_vault.cairo b/listings/ch01-applications/simple_vault/src/simple_vault.cairo index 8151fd82..f8ef5404 100644 --- a/listings/ch01-applications/simple_vault/src/simple_vault.cairo +++ b/listings/ch01-applications/simple_vault/src/simple_vault.cairo @@ -1,7 +1,7 @@ use starknet::{ContractAddress}; // In order to make contract calls within our Vault, -// we need to have the interface of the remote contract defined to import the Dispatcher +// we need to have the interface of the remote ERC20 contract defined to import the Dispatcher. #[starknet::interface] trait IERC20 { fn name(self: @TContractState) -> felt252; diff --git a/src/SUMMARY.md b/src/SUMMARY.md index c11208cb..37cd73ca 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -1,19 +1,18 @@ Summary - [Starknet by Example](./starknet-by-example.md) -- [Introduction to Cairo](./ch00-00-introduction.md) +- [Basics of Smart Contracts in Cairo](./ch00-00-introduction.md) + - [Constructors](./ch00-07-constructor.md) + - [Visibility and Mutability](./ch00-08-visibility-mutability.md) + - [Events](./ch00-10-events.md) - [Variables](./ch00-01-variables.md) + - [Mappings](./ch00-06-mappings.md) + - [Counter contract example](./ch00-11-counter.md) - [Errors](./ch00-02-errors.md) - [Calling other contracts](./ch00-03-calling_other_contracts.md) - - [Write to Any Slot](./ch00-04-write_to_any_slot.md) + - [Writing to any storage slot](./ch00-04-write_to_any_slot.md) - [Storing Arrays](./ch00-05-storing_arrays.md) - - [Mappings](./ch00-06-mappings.md) - - [Constructors](./ch00-07-constructor.md) - - [Function Attributes](./ch00-08-visibility.md) - - [If statements](./ch00-09-if_statements.md) - - [Events](./ch00-10-events.md) - - [Counter](./ch00-11-counter.md) - [Applications](./ch01-00-applications.md) - [Upgradeable Contract](./ch01-01-upgradeable_contract.md) diff --git a/src/ch00-00-introduction.md b/src/ch00-00-introduction.md index 1f27792a..2f4f91c1 100644 --- a/src/ch00-00-introduction.md +++ b/src/ch00-00-introduction.md @@ -1,3 +1,3 @@ -# Introduction to Cairo for Starknet smart contracts +# Basics of Smart Contracts in Cairo The following chapters will introduce you to Starknet smart contracts and how to write them in Cairo. diff --git a/src/ch00-03-calling_other_contracts.md b/src/ch00-03-calling_other_contracts.md index 95d83904..8fff7f4b 100644 --- a/src/ch00-03-calling_other_contracts.md +++ b/src/ch00-03-calling_other_contracts.md @@ -7,7 +7,7 @@ You can read more about Dispatchers in the [Cairo Book](https://cairo-book.githu The other way is to use the `starknet::call_contract_syscall` syscall yourself. However, this method is not recommended. -In order to call other contracts using dispatchers, you will need to define the called contract's interface as a trait annotated with the `#[abi]` attribute, and then import the `IContractDispatcher` and `IContractDispatcherTrait` items in your contract. +In order to call other contracts using dispatchers, you will need to define the called contract's interface as a trait annotated with the `#[starknet::interface]` attribute, and then import the `IContractDispatcher` and `IContractDispatcherTrait` items in your contract. ```rust {{#include ../listings/ch00-introduction/calling_other_contracts/src/callee.cairo}} diff --git a/src/ch00-04-write_to_any_slot.md b/src/ch00-04-write_to_any_slot.md index 2edac866..12456a12 100644 --- a/src/ch00-04-write_to_any_slot.md +++ b/src/ch00-04-write_to_any_slot.md @@ -1,9 +1,7 @@ -# Write to Any Slot +# Writing to any storage slot On Starknet, a contract's storage is a map with 2^251 slots, where each slot is a felt which is initialized to 0. -The address of storage variables is computed at compile time using the formula: `storage variable address := pedersen(keccak(variable name), keys)`. Interactions with storage variables are commonly performed using the `var::read()` and `var::write()` functions. - - +The address of storage variables is computed at compile time using the formula: `storage variable address := pedersen(keccak(variable name), keys)`. Interactions with storage variables are commonly performed using the `self.var.read()` and `self.var.write()` functions. Nevertheless, we can use the `storage_write_syscall` and `storage_read_syscall` syscalls, to write to and read from any storage slot. This is useful when writing to storage variables that are not known at compile time, or to ensure that even if the contract is upgraded and the computation method of storage variable addresses changes, they remain accessible. diff --git a/src/ch00-08-function_attributes.md b/src/ch00-08-function_attributes.md deleted file mode 100644 index 351faa8f..00000000 --- a/src/ch00-08-function_attributes.md +++ /dev/null @@ -1,17 +0,0 @@ -# Function Attributes - -When you write functions in a contract using Cairo, you need to provide special annotations to inform the compiler about the nature of each function. These annotations are written as `#[attribute]` just before the function definition. - -Let's explore the three main types of functions you can use: - -- `#[external]`: These functions can be called from anywhere and have the ability to modify the contract's state. However, it's important to note that interacting with external functions requires sending a transaction, which incurs a gas cost. - -- `#[view]`: These functions can also be called from anywhere, but they are read-only and cannot modify the contract's state. The advantage of using view functions is that they can also be invoked without making a transaction. You can interact with them directly through a RPC node, making them essentially free to call! - -- Internal: These functions are only accessible within the contract itself and have the ability to modify the contract's state. They are private by default, unlike external and view functions. To mark a function as internal, you simply don't add any annotation to them. - -Let's take a look at a simple example contract to see these attributes in action: - -```rust -{{#include ../listings/ch00-introduction/visibility/src/visibility.cairo}} -``` diff --git a/src/ch00-08-visibility-mutability.md b/src/ch00-08-visibility-mutability.md new file mode 100644 index 00000000..264ab9be --- /dev/null +++ b/src/ch00-08-visibility-mutability.md @@ -0,0 +1,29 @@ +# Visibility and Mutability + +## Visibility + +There are two types of functions in Starknet contracts: + +- Functions that are accessible externally and can be called by anyone. +- Functions that are only accessible internally and can only be called by other functions in the contract. + +These functions are also typically divided into two different implementations blocks. The first `impl` block for externally accessible functions is explicitly annotated with an `#[external(v0)]` attribute. This indicates that all the functions inside this block can be queries either as a transaction or as a view function. The second `impl` block for internally accessible functions is not annotated with any attribute, which means that all the functions inside this block are private by default. + +## State Mutability + +Regardless of whether a function is internal or external, it can either modify the contract's state or not. When we declare functions that interact with storage variables inside a smart contract, +we need to explicitly state that we are accessing the `ContractState` by adding it as the first parameter of the function. This is can be done in two different ways: + +- If we want our function to be able to mutate the state of the contract, we pass it by reference like this: `ref self: ContractState`. +- If we want our function to be read-only and not mutate the state of the contract, we pass it by snapshot like this: `self: @ContractState`. + +Read-only functions, also called view functions, can be directly called without making a transaction. You can interact with them directly through a RPC node to read the contract's state, and they're free to call! +External functions, that modify the contract's state, on the other side can only be called by making a transaction. + +Internal functions can't be called externally, but the same principle applies regarding state mutability. + +Let's take a look at a simple example contract to see these in action: + +```rust +{{#include ../listings/ch00-introduction/visibility/src/visibility.cairo}} +``` diff --git a/src/ch00-09-if_statements.md b/src/ch00-09-if_statements.md deleted file mode 100644 index f34ac2af..00000000 --- a/src/ch00-09-if_statements.md +++ /dev/null @@ -1,11 +0,0 @@ -# If Statements - -Using an if expression allows you to execute certain code depending on conditions. Within the if statement provide a condition and then specify what you want to execute within the block of code. You can specify an else expression which is reached if the If condition is not met. - -Here's a simple example of a contract using if and else statements for role based access log: - -The contract will log a welcome message to the console depending on who called the function. If the owner called the function, the welcome message will be 'Welcome Admin!'. If a normal user called the function, the welcome message will be 'Welcome User!'. - -```rust -{{#include ../listings/ch00-introduction/if_else/src/access_log.cairo}} -``` diff --git a/src/ch00-10-events.md b/src/ch00-10-events.md index 417f36e1..d1536870 100644 --- a/src/ch00-10-events.md +++ b/src/ch00-10-events.md @@ -1,6 +1,7 @@ # Events -An event is defined as function with the #[event] attribute. The parameters of the function correspond to data that will be emitted. An event is to be logged for easy and fast access to querying the data at a later time. +Events are a way to emit data from a contract. All events must be defined in the `Event` enum, which must be annotated with the `#[event]` attribute. +An event is defined as struct that derives the `#[starknet::Event]` trait. The fields of that struct correspond to the data that will be emitted. An event can be indexed for easy and fast access when querying the data at a later time. Here's a simple example of a contract using events that emit an event each time a counter is incremented by the "increment" function: diff --git a/src/ch00-11-counter.md b/src/ch00-11-counter.md index b67017c2..06416a5f 100644 --- a/src/ch00-11-counter.md +++ b/src/ch00-11-counter.md @@ -1,6 +1,6 @@ # Simple Counter -This is a smiple counter contract. +This is a simple counter contract. Here's how it works: From 1e4537d63e4882d03d20b00f149cfb020804cd75 Mon Sep 17 00:00:00 2001 From: msaug Date: Fri, 7 Jul 2023 11:00:28 +0200 Subject: [PATCH 4/4] refactor: change structure --- .../visibility/src/visibility.cairo | 4 ++-- .../storing_arrays/.gitignore | 0 .../storing_arrays/Scarb.toml | 0 .../storing_arrays/src/lib.cairo | 0 .../storing_arrays/src/storing_arrays.cairo | 0 .../write_to_any_slot/.gitignore | 0 .../write_to_any_slot/Scarb.toml | 0 .../write_to_any_slot/src/lib.cairo | 0 .../src/test_write_any_slot.cairo | 0 .../write_to_any_slot/src/write_any_slot.cairo | 0 .../simple_vault/.gitignore | 0 .../simple_vault/Scarb.toml | 0 .../simple_vault/src/lib.cairo | 0 .../simple_vault/src/simple_vault.cairo | 0 .../upgradeable_contract/.gitignore | 0 .../upgradeable_contract/Scarb.toml | 0 .../upgradeable_contract/src/lib.cairo | 0 .../src/upgradeable_contract_v0.cairo | 0 .../src/upgradeable_contract_v1.cairo | 0 src/SUMMARY.md | 16 ++++++++++------ src/ch00-08-visibility-mutability.md | 2 +- src/ch01-00-advanced-concepts.md | 3 +++ ..._any_slot.md => ch01-01-write_to_any_slot.md} | 2 +- ...oring_arrays.md => ch01-02-storing_arrays.md} | 4 ++-- ...0-applications.md => ch02-00-applications.md} | 0 ...ntract.md => ch02-01-upgradeable_contract.md} | 4 ++-- ...2-simple_vault.md => ch02-02-simple_vault.md} | 6 +----- 27 files changed, 22 insertions(+), 19 deletions(-) rename listings/{ch00-introduction => ch01-advanced-concepts}/storing_arrays/.gitignore (100%) rename listings/{ch00-introduction => ch01-advanced-concepts}/storing_arrays/Scarb.toml (100%) rename listings/{ch00-introduction => ch01-advanced-concepts}/storing_arrays/src/lib.cairo (100%) rename listings/{ch00-introduction => ch01-advanced-concepts}/storing_arrays/src/storing_arrays.cairo (100%) rename listings/{ch00-introduction => ch01-advanced-concepts}/write_to_any_slot/.gitignore (100%) rename listings/{ch00-introduction => ch01-advanced-concepts}/write_to_any_slot/Scarb.toml (100%) rename listings/{ch00-introduction => ch01-advanced-concepts}/write_to_any_slot/src/lib.cairo (100%) rename listings/{ch00-introduction => ch01-advanced-concepts}/write_to_any_slot/src/test_write_any_slot.cairo (100%) rename listings/{ch00-introduction => ch01-advanced-concepts}/write_to_any_slot/src/write_any_slot.cairo (100%) rename listings/{ch01-applications => ch02-applications}/simple_vault/.gitignore (100%) rename listings/{ch01-applications => ch02-applications}/simple_vault/Scarb.toml (100%) rename listings/{ch01-applications => ch02-applications}/simple_vault/src/lib.cairo (100%) rename listings/{ch01-applications => ch02-applications}/simple_vault/src/simple_vault.cairo (100%) rename listings/{ch01-applications => ch02-applications}/upgradeable_contract/.gitignore (100%) rename listings/{ch01-applications => ch02-applications}/upgradeable_contract/Scarb.toml (100%) rename listings/{ch01-applications => ch02-applications}/upgradeable_contract/src/lib.cairo (100%) rename listings/{ch01-applications => ch02-applications}/upgradeable_contract/src/upgradeable_contract_v0.cairo (100%) rename listings/{ch01-applications => ch02-applications}/upgradeable_contract/src/upgradeable_contract_v1.cairo (100%) create mode 100644 src/ch01-00-advanced-concepts.md rename src/{ch00-04-write_to_any_slot.md => ch01-01-write_to_any_slot.md} (92%) rename src/{ch00-05-storing_arrays.md => ch01-02-storing_arrays.md} (81%) rename src/{ch01-00-applications.md => ch02-00-applications.md} (100%) rename src/{ch01-01-upgradeable_contract.md => ch02-01-upgradeable_contract.md} (93%) rename src/{ch01-02-simple_vault.md => ch02-02-simple_vault.md} (63%) diff --git a/listings/ch00-introduction/visibility/src/visibility.cairo b/listings/ch00-introduction/visibility/src/visibility.cairo index 4f8231de..8aca7d6f 100644 --- a/listings/ch00-introduction/visibility/src/visibility.cairo +++ b/listings/ch00-introduction/visibility/src/visibility.cairo @@ -1,5 +1,5 @@ #[starknet::contract] -mod VisiblityContract { +mod ExampleContract { #[storage] struct Storage { value: u32 @@ -10,7 +10,7 @@ mod VisiblityContract { // Omitting this attribute would make all the functions in this implementation internal. #[external(v0)] #[generate_trait] - impl VisiblityContract of IVisibilityContract { + impl ExampleContract of IExampleContract { // The `set` function can be called externally because it is written inside an implementation marked as `#[external]`. // It can modify the contract's state as it is passed as a reference. fn set(ref self: ContractState, value: u32) { diff --git a/listings/ch00-introduction/storing_arrays/.gitignore b/listings/ch01-advanced-concepts/storing_arrays/.gitignore similarity index 100% rename from listings/ch00-introduction/storing_arrays/.gitignore rename to listings/ch01-advanced-concepts/storing_arrays/.gitignore diff --git a/listings/ch00-introduction/storing_arrays/Scarb.toml b/listings/ch01-advanced-concepts/storing_arrays/Scarb.toml similarity index 100% rename from listings/ch00-introduction/storing_arrays/Scarb.toml rename to listings/ch01-advanced-concepts/storing_arrays/Scarb.toml diff --git a/listings/ch00-introduction/storing_arrays/src/lib.cairo b/listings/ch01-advanced-concepts/storing_arrays/src/lib.cairo similarity index 100% rename from listings/ch00-introduction/storing_arrays/src/lib.cairo rename to listings/ch01-advanced-concepts/storing_arrays/src/lib.cairo diff --git a/listings/ch00-introduction/storing_arrays/src/storing_arrays.cairo b/listings/ch01-advanced-concepts/storing_arrays/src/storing_arrays.cairo similarity index 100% rename from listings/ch00-introduction/storing_arrays/src/storing_arrays.cairo rename to listings/ch01-advanced-concepts/storing_arrays/src/storing_arrays.cairo diff --git a/listings/ch00-introduction/write_to_any_slot/.gitignore b/listings/ch01-advanced-concepts/write_to_any_slot/.gitignore similarity index 100% rename from listings/ch00-introduction/write_to_any_slot/.gitignore rename to listings/ch01-advanced-concepts/write_to_any_slot/.gitignore diff --git a/listings/ch00-introduction/write_to_any_slot/Scarb.toml b/listings/ch01-advanced-concepts/write_to_any_slot/Scarb.toml similarity index 100% rename from listings/ch00-introduction/write_to_any_slot/Scarb.toml rename to listings/ch01-advanced-concepts/write_to_any_slot/Scarb.toml diff --git a/listings/ch00-introduction/write_to_any_slot/src/lib.cairo b/listings/ch01-advanced-concepts/write_to_any_slot/src/lib.cairo similarity index 100% rename from listings/ch00-introduction/write_to_any_slot/src/lib.cairo rename to listings/ch01-advanced-concepts/write_to_any_slot/src/lib.cairo diff --git a/listings/ch00-introduction/write_to_any_slot/src/test_write_any_slot.cairo b/listings/ch01-advanced-concepts/write_to_any_slot/src/test_write_any_slot.cairo similarity index 100% rename from listings/ch00-introduction/write_to_any_slot/src/test_write_any_slot.cairo rename to listings/ch01-advanced-concepts/write_to_any_slot/src/test_write_any_slot.cairo diff --git a/listings/ch00-introduction/write_to_any_slot/src/write_any_slot.cairo b/listings/ch01-advanced-concepts/write_to_any_slot/src/write_any_slot.cairo similarity index 100% rename from listings/ch00-introduction/write_to_any_slot/src/write_any_slot.cairo rename to listings/ch01-advanced-concepts/write_to_any_slot/src/write_any_slot.cairo diff --git a/listings/ch01-applications/simple_vault/.gitignore b/listings/ch02-applications/simple_vault/.gitignore similarity index 100% rename from listings/ch01-applications/simple_vault/.gitignore rename to listings/ch02-applications/simple_vault/.gitignore diff --git a/listings/ch01-applications/simple_vault/Scarb.toml b/listings/ch02-applications/simple_vault/Scarb.toml similarity index 100% rename from listings/ch01-applications/simple_vault/Scarb.toml rename to listings/ch02-applications/simple_vault/Scarb.toml diff --git a/listings/ch01-applications/simple_vault/src/lib.cairo b/listings/ch02-applications/simple_vault/src/lib.cairo similarity index 100% rename from listings/ch01-applications/simple_vault/src/lib.cairo rename to listings/ch02-applications/simple_vault/src/lib.cairo diff --git a/listings/ch01-applications/simple_vault/src/simple_vault.cairo b/listings/ch02-applications/simple_vault/src/simple_vault.cairo similarity index 100% rename from listings/ch01-applications/simple_vault/src/simple_vault.cairo rename to listings/ch02-applications/simple_vault/src/simple_vault.cairo diff --git a/listings/ch01-applications/upgradeable_contract/.gitignore b/listings/ch02-applications/upgradeable_contract/.gitignore similarity index 100% rename from listings/ch01-applications/upgradeable_contract/.gitignore rename to listings/ch02-applications/upgradeable_contract/.gitignore diff --git a/listings/ch01-applications/upgradeable_contract/Scarb.toml b/listings/ch02-applications/upgradeable_contract/Scarb.toml similarity index 100% rename from listings/ch01-applications/upgradeable_contract/Scarb.toml rename to listings/ch02-applications/upgradeable_contract/Scarb.toml diff --git a/listings/ch01-applications/upgradeable_contract/src/lib.cairo b/listings/ch02-applications/upgradeable_contract/src/lib.cairo similarity index 100% rename from listings/ch01-applications/upgradeable_contract/src/lib.cairo rename to listings/ch02-applications/upgradeable_contract/src/lib.cairo diff --git a/listings/ch01-applications/upgradeable_contract/src/upgradeable_contract_v0.cairo b/listings/ch02-applications/upgradeable_contract/src/upgradeable_contract_v0.cairo similarity index 100% rename from listings/ch01-applications/upgradeable_contract/src/upgradeable_contract_v0.cairo rename to listings/ch02-applications/upgradeable_contract/src/upgradeable_contract_v0.cairo diff --git a/listings/ch01-applications/upgradeable_contract/src/upgradeable_contract_v1.cairo b/listings/ch02-applications/upgradeable_contract/src/upgradeable_contract_v1.cairo similarity index 100% rename from listings/ch01-applications/upgradeable_contract/src/upgradeable_contract_v1.cairo rename to listings/ch02-applications/upgradeable_contract/src/upgradeable_contract_v1.cairo diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 37cd73ca..48fa6500 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -3,7 +3,7 @@ Summary - [Starknet by Example](./starknet-by-example.md) - [Basics of Smart Contracts in Cairo](./ch00-00-introduction.md) - - [Constructors](./ch00-07-constructor.md) + - [Constructor](./ch00-07-constructor.md) - [Visibility and Mutability](./ch00-08-visibility-mutability.md) - [Events](./ch00-10-events.md) - [Variables](./ch00-01-variables.md) @@ -11,9 +11,13 @@ Summary - [Counter contract example](./ch00-11-counter.md) - [Errors](./ch00-02-errors.md) - [Calling other contracts](./ch00-03-calling_other_contracts.md) - - [Writing to any storage slot](./ch00-04-write_to_any_slot.md) - - [Storing Arrays](./ch00-05-storing_arrays.md) -- [Applications](./ch01-00-applications.md) - - [Upgradeable Contract](./ch01-01-upgradeable_contract.md) - - [Defi Vault](./ch01-02-simple_vault.md) +- [Advanced concepts](./ch01-00-advanced-concepts.md) + + - [Writing to any storage slot](./ch01-01-write_to_any_slot.md) + - [Storing Arrays](./ch01-02-storing_arrays.md) + +- [Applications](./ch02-00-applications.md) + + - [Upgradeable Contract](./ch02-01-upgradeable_contract.md) + - [Defi Vault](./ch02-02-simple_vault.md) diff --git a/src/ch00-08-visibility-mutability.md b/src/ch00-08-visibility-mutability.md index 264ab9be..a32861df 100644 --- a/src/ch00-08-visibility-mutability.md +++ b/src/ch00-08-visibility-mutability.md @@ -7,7 +7,7 @@ There are two types of functions in Starknet contracts: - Functions that are accessible externally and can be called by anyone. - Functions that are only accessible internally and can only be called by other functions in the contract. -These functions are also typically divided into two different implementations blocks. The first `impl` block for externally accessible functions is explicitly annotated with an `#[external(v0)]` attribute. This indicates that all the functions inside this block can be queries either as a transaction or as a view function. The second `impl` block for internally accessible functions is not annotated with any attribute, which means that all the functions inside this block are private by default. +These functions are also typically divided into two different implementations blocks. The first `impl` block for externally accessible functions is explicitly annotated with an `#[external(v0)]` attribute. This indicates that all the functions inside this block can be called either as a transaction or as a view function. The second `impl` block for internally accessible functions is not annotated with any attribute, which means that all the functions inside this block are private by default. ## State Mutability diff --git a/src/ch01-00-advanced-concepts.md b/src/ch01-00-advanced-concepts.md new file mode 100644 index 00000000..d53246b7 --- /dev/null +++ b/src/ch01-00-advanced-concepts.md @@ -0,0 +1,3 @@ +# Advanced Concepts + +In this section, we will present some advanced concepts that are not required for writing smart contracts, but are useful for writing more complex applications. diff --git a/src/ch00-04-write_to_any_slot.md b/src/ch01-01-write_to_any_slot.md similarity index 92% rename from src/ch00-04-write_to_any_slot.md rename to src/ch01-01-write_to_any_slot.md index 12456a12..392b6655 100644 --- a/src/ch00-04-write_to_any_slot.md +++ b/src/ch01-01-write_to_any_slot.md @@ -9,5 +9,5 @@ This is useful when writing to storage variables that are not known at compile t In the following example, we use the Poseidon hash function to compute the address of a storage variable. Poseidon is a ZK-friendly hash function that is cheaper and faster than Pedersen, making it an excellent choice for onchain computations. Once the address is computed, we use the storage syscalls to interact with it. ```rust -{{#include ../listings/ch00-introduction/write_to_any_slot/src/write_any_slot.cairo}} +{{#include ../listings/ch01-advanced-concepts/write_to_any_slot/src/write_any_slot.cairo}} ``` diff --git a/src/ch00-05-storing_arrays.md b/src/ch01-02-storing_arrays.md similarity index 81% rename from src/ch00-05-storing_arrays.md rename to src/ch01-02-storing_arrays.md index b91bdb38..ba1b4f76 100644 --- a/src/ch00-05-storing_arrays.md +++ b/src/ch01-02-storing_arrays.md @@ -5,11 +5,11 @@ On Starknet, complex values (e.g., tuples or structs), are stored in a continuou The following example demonstrates how to write a simple implementation of the `StorageAccess` trait for the `Array` type, allowing us to store arrays of up to 255 `felt252` elements. ```rust -{{#include ../listings/ch00-introduction/storing_arrays/src/storing_arrays.cairo:StorageAccessImpl}} +{{#include ../listings/ch01-advanced-concepts/storing_arrays/src/storing_arrays.cairo:StorageAccessImpl}} ``` You can then import this implementation in your contract and use it to store arrays in storage: ```rust -{{#include ../listings/ch00-introduction/storing_arrays/src/storing_arrays.cairo:StoreArrayContract}} +{{#include ../listings/ch01-advanced-concepts/storing_arrays/src/storing_arrays.cairo:StoreArrayContract}} ``` diff --git a/src/ch01-00-applications.md b/src/ch02-00-applications.md similarity index 100% rename from src/ch01-00-applications.md rename to src/ch02-00-applications.md diff --git a/src/ch01-01-upgradeable_contract.md b/src/ch02-01-upgradeable_contract.md similarity index 93% rename from src/ch01-01-upgradeable_contract.md rename to src/ch02-01-upgradeable_contract.md index d8bf30b3..127e74ac 100644 --- a/src/ch01-01-upgradeable_contract.md +++ b/src/ch02-01-upgradeable_contract.md @@ -23,9 +23,9 @@ To illustrate this concept, let's consider an example with two contracts: `Upgra Start by deploying `UpgradeableContract_V0` as the initial version. Next, send a transaction that invokes the `upgrade` function, with the class hash of `UpgradeableContract_V1` as parameter to upgrade the class hash of the deployed contract to the `UpgradeableContract_V1` one. Then, call the `version` method on the contract to see that the contract was upgraded to the V1 version. ```rust -{{#include ../listings/ch01-applications/upgradeable_contract/src/upgradeable_contract_v0.cairo}} +{{#include ../listings/ch02-applications/upgradeable_contract/src/upgradeable_contract_v0.cairo}} ``` ```rust -{{#include ../listings/ch01-applications/upgradeable_contract/src/upgradeable_contract_v1.cairo}} +{{#include ../listings/ch02-applications/upgradeable_contract/src/upgradeable_contract_v1.cairo}} ``` diff --git a/src/ch01-02-simple_vault.md b/src/ch02-02-simple_vault.md similarity index 63% rename from src/ch01-02-simple_vault.md rename to src/ch02-02-simple_vault.md index 69d1d395..10d4d33c 100644 --- a/src/ch01-02-simple_vault.md +++ b/src/ch02-02-simple_vault.md @@ -8,9 +8,5 @@ Here's how it works: - When a user withdraws, the contract burns their shares, calculates the yield, and withdraw both the yield and the initial amount of token deposited. ```rust -{{#include ../listings/ch01-applications/simple_vault/src/simple_vault.cairo}} +{{#include ../listings/ch02-applications/simple_vault/src/simple_vault.cairo}} ``` - -> **Note** -> As of version v1.1.0, we need to enable `experimental_v0.1.0` libfuncs to use `u256_divmod_safe` as it hasn't been audited yet. -> It'll be included in v2.0.0. \ No newline at end of file