diff --git a/examples/Ownable-Starknet/.env.example b/examples/Ownable-Starknet/.env.example new file mode 100644 index 000000000..679080215 --- /dev/null +++ b/examples/Ownable-Starknet/.env.example @@ -0,0 +1,3 @@ +export STARKNET_ACCOUNT=/home/gianm/.starkli-wallets/deployer/my_account_argent.json +export STARKNET_KEYSTORE=/home/gianm/.starkli-wallets/deployer/my_keystore_argent.json +export STARKNET_RPC=https://starknet-testnet.public.blastapi.io/rpc/v0_6 # you can keep this rpc url unchanged \ No newline at end of file diff --git a/examples/Ownable-Starknet/Scarb.lock b/examples/Ownable-Starknet/Scarb.lock index c7e6d3bff..356247dd8 100644 --- a/examples/Ownable-Starknet/Scarb.lock +++ b/examples/Ownable-Starknet/Scarb.lock @@ -4,11 +4,3 @@ version = 1 [[package]] name = "ownable_starknet" version = "0.1.0" -dependencies = [ - "snforge_std", -] - -[[package]] -name = "snforge_std" -version = "0.1.0" -source = "git+https://github.com/foundry-rs/starknet-foundry?tag=v0.7.1#d1bd8b9a361d437e8eaeb4ebffac291a48b4c920" diff --git a/examples/Ownable-Starknet/Scarb.toml b/examples/Ownable-Starknet/Scarb.toml index 61055bef9..1eaf62c44 100644 --- a/examples/Ownable-Starknet/Scarb.toml +++ b/examples/Ownable-Starknet/Scarb.toml @@ -5,8 +5,7 @@ version = "0.1.0" # See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest [dependencies] -snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry", tag = "v0.7.1" } #v0.7.0 -starknet = ">=2.2.0" +starknet = ">=2.5.0" [[target.starknet-contract]] sierra = true diff --git a/examples/Ownable-Starknet/data/calldata.txt b/examples/Ownable-Starknet/data/calldata.txt deleted file mode 100644 index 181a15cf7..000000000 --- a/examples/Ownable-Starknet/data/calldata.txt +++ /dev/null @@ -1 +0,0 @@ -'admin' \ No newline at end of file diff --git a/examples/Ownable-Starknet/src/lib.cairo b/examples/Ownable-Starknet/src/lib.cairo index 12d553bb1..2e4499ac6 100644 --- a/examples/Ownable-Starknet/src/lib.cairo +++ b/examples/Ownable-Starknet/src/lib.cairo @@ -40,14 +40,14 @@ mod ownable { } #[constructor] - fn constructor(ref self: ContractState, initial_owner: ContractAddress,) { + fn constructor(ref self: ContractState, initial_owner: ContractAddress) { self.owner.write(initial_owner); self.data.write(1); // Any variable of the storage that is not initialized // will have default value -> data = 0. } - #[external(v0)] + #[abi(embed_v0)] impl OwnableDataImpl of IData { fn other_func(self: @ContractState, other_contract: ContractAddress) -> felt252 { IDataDispatcher { contract_address: other_contract }.get_data() @@ -63,14 +63,14 @@ mod ownable { } } - #[external(v0)] + #[abi(embed_v0)] impl OwnableTraitImpl of OwnableTrait { fn transfer_ownership(ref self: ContractState, new_owner: ContractAddress) { self.only_owner(); let prev_owner = self.owner.read(); self.owner.write(new_owner); - self.emit(OwnershipTransferred { prev_owner, new_owner, }); + self.emit(OwnershipTransferred { prev_owner, new_owner }); } fn owner(self: @ContractState) -> ContractAddress { @@ -87,3 +87,27 @@ mod ownable { } } +#[cfg(test)] +mod tests { + use ownable_starknet::ownable; + use ownable_starknet::{OwnableTraitDispatcher, OwnableTraitDispatcherTrait}; + use starknet::{ContractAddress, Into, TryInto, OptionTrait}; + use starknet::syscalls::deploy_syscall; + use result::ResultTrait; + use array::{ArrayTrait, SpanTrait}; + + #[test] + #[available_gas(10_000_000)] + fn unit_test() { + let admin_address: ContractAddress = 'admin'.try_into().unwrap(); + let mut calldata = array![admin_address.into()]; + let (address0, _) = deploy_syscall( + ownable::TEST_CLASS_HASH.try_into().unwrap(), 0, calldata.span(), false + ) + .unwrap(); + let mut contract0 = OwnableTraitDispatcher { contract_address: address0 }; + + assert(contract0.owner() == admin_address, 'Wrong owner'); + } +} + diff --git a/examples/Ownable-Starknet/tests/test_ownable.cairo b/examples/Ownable-Starknet/tests/test_ownable.cairo deleted file mode 100644 index 53b1575fe..000000000 --- a/examples/Ownable-Starknet/tests/test_ownable.cairo +++ /dev/null @@ -1,87 +0,0 @@ -use starknet::{ContractAddress, Into, TryInto, OptionTrait}; -use starknet::syscalls::deploy_syscall; -use result::ResultTrait; -use array::{ArrayTrait, SpanTrait}; -use snforge_std::{declare, ContractClassTrait}; -use snforge_std::io::{FileTrait, read_txt}; -use snforge_std::{start_prank, stop_prank}; -use snforge_std::{start_mock_call, stop_mock_call}; - -use ownable_starknet::{OwnableTraitDispatcher, OwnableTraitDispatcherTrait}; -use ownable_starknet::{IDataSafeDispatcher, IDataSafeDispatcherTrait}; - -mod Errors { - const INVALID_OWNER: felt252 = 'Caller is not the owner'; - const INVALID_DATA: felt252 = 'Invalid data'; -} - -mod Accounts { - use traits::TryInto; - use starknet::ContractAddress; - - fn admin() -> ContractAddress { - 'admin'.try_into().unwrap() - } - fn new_admin() -> ContractAddress { - 'new_admin'.try_into().unwrap() - } - fn bad_guy() -> ContractAddress { - 'bad_guy'.try_into().unwrap() - } -} - -fn deploy_contract(name: felt252) -> ContractAddress { - // let account = Accounts::admin(); - let contract = declare(name); - - let file = FileTrait::new('data/calldata.txt'); - let calldata = read_txt(@file); - //deploy contract - contract.deploy(@calldata).unwrap() -} - -#[test] -fn test_construct_with_admin() { - let contract_address = deploy_contract('ownable'); - let dispatcher = OwnableTraitDispatcher { contract_address }; - let owner = dispatcher.owner(); - assert(owner == Accounts::admin(), Errors::INVALID_OWNER); -} - -#[test] -fn test_transfer_ownership() { - let contract_address = deploy_contract('ownable'); - let dispatcher = OwnableTraitDispatcher { contract_address }; - start_prank(contract_address, Accounts::admin()); - dispatcher.transfer_ownership(Accounts::new_admin()); - - assert(dispatcher.owner() == Accounts::new_admin(), Errors::INVALID_OWNER); -} - -#[test] -#[should_panic(expected: ('Caller is not the owner',))] -fn test_transfer_ownership_bad_guy() { - let contract_address = deploy_contract('ownable'); - let dispatcher = OwnableTraitDispatcher { contract_address }; - start_prank(contract_address, Accounts::bad_guy()); - dispatcher.transfer_ownership(Accounts::bad_guy()); - - assert(dispatcher.owner() == Accounts::bad_guy(), Errors::INVALID_OWNER); -} - -#[test] -fn test_data_mock_call_get_data() { - let contract_address = deploy_contract('ownable'); - let safe_dispatcher = IDataSafeDispatcher { contract_address }; - let mock_ret_data = 100; - start_mock_call(contract_address, 'get_data', mock_ret_data); - start_prank(contract_address, Accounts::admin()); - safe_dispatcher.set_data(20); - let data = safe_dispatcher.get_data().unwrap(); - assert(data == mock_ret_data, Errors::INVALID_DATA); - stop_mock_call(contract_address, 'get_data'); - - let data2 = safe_dispatcher.get_data().unwrap(); - assert(data2 == 20, Errors::INVALID_DATA); - stop_prank(contract_address); -} diff --git a/src/ch02-02-starkli-scarb-katana.md b/src/ch02-02-starkli-scarb-katana.md index 633643e79..a891599a4 100644 --- a/src/ch02-02-starkli-scarb-katana.md +++ b/src/ch02-02-starkli-scarb-katana.md @@ -89,7 +89,6 @@ mod hello { } #[external(v0)] fn set_name(ref self: ContractState, name: felt252) { - let previous = self.name.read(); self.name.write(name); } } diff --git a/src/ch02-05-testnet-deployment.md b/src/ch02-05-testnet-deployment.md index 9039b4ca1..e74bdb444 100644 --- a/src/ch02-05-testnet-deployment.md +++ b/src/ch02-05-testnet-deployment.md @@ -17,7 +17,7 @@ the Account Descriptor is a JSON file detailing the wallet’s address and public key. In order for an account to be used as a signer it must be deployed to the appropriate network, -Starknet Sepolia or mainnet, and funded. For this example we are going to use Sepolia Testnet. To deploy your wallet, visit [Smart Wallet Setup](https://book.starknet.io/ch01-00-getting-started.html#smart-wallet-setup). +Starknet Goerli, Sepolia or mainnet, and funded. For this example we are going to use Goerli Testnet. To deploy your wallet, visit [Smart Wallet Setup](https://book.starknet.io/ch01-00-getting-started.html#smart-wallet-setup). Now you’re ready to interact with Starknet smart contracts. ### Creating a Signer @@ -192,6 +192,9 @@ There are three main options for RPC providers, sorted by ease of use: Starknet Book](https://book.starknet.io/chapter_4/node.html) or [Kasar](https://www.kasar.io/) for setup guides. +3. **Free RPC vendor**: These 3 networks are eligible for free RPC vendors: mainet, goerli, sepolia. + You can choose [Blast](https://blastapi.io/public-api/starknet) or [Nethermind](https://data.voyager.online/) + ### Creating an Account Descriptor An Account Descriptor informs Starkli about your smart wallet’s unique @@ -202,10 +205,10 @@ input and generates the account descriptor file. The account descriptor file is a JSON file that contains the details of your smart wallet. We also have to pass the rpc provider here. ```bash - starkli account fetch --output ~/.starkli-wallets/deployer/my_account_1.json --rpc https://starknet-sepolia.infura.io/v3/ + starkli account fetch --output ~/.starkli-wallets/deployer/my_account_1.json --rpc https://starknet-testnet.public.blastapi.io/rpc/v0_6 ``` -Note: If you don't specify the rpc provider, Starkli will use Goerli, which will be deprecated soon. +Note: Here we used the Public RPC Endpoint v0.6 Starknet (Goerli) Testnet from **Blast**. If you don't specify the rpc provider, Starkli will use Goerli, which will be deprecated in the upcoming months. Thus you can check the rpc url for Sepolia network on [Blast](https://blastapi.io/public-api/starknet). > ⚠️ **Contract not found?** > @@ -217,14 +220,14 @@ Note: If you don't specify the rpc provider, Starkli will use Goerli, which will > > #### 🟩 Solution: > -> It means you probably just created a new wallet and it has **not been deployed yet**. To accomplish this you have to fund your wallet with tokens and **transfer tokens** to a **different** wallet address. Detailed intructons can be found in the [Get Seplia Tokens](./ch02-05-01-start-with-sepolia.md) section. +> It means you probably just created a new wallet and it has **not been deployed yet**. To accomplish this you have to fund your wallet with tokens and **transfer tokens** to a **different** wallet address. For goerli tokens you can check this [faucet](https://faucet.goerli.starknet.io/). For Sepolia tokens detailed intructons can be found in the [Get Sepolia Tokens](./ch02-05-01-start-with-sepolia.md) section. > > **Still doesn't work?** > -> Check if your wallet's testnet network isn't yet set with Sepolia, that means you have to after deploying your wallet testnet, use instead the soon to be deprecated Goerli network: +> Check if your wallet's testnet network isn't yet set with Goerli or Sepolia, try again with your blast rpc url. > > ```bash -> starknet account fetch ... --rpc https://starknet-goerli.infura.io/v3/ +> starknet account fetch ... --rpc https://starknet-testnet.public.blastapi.io/rpc/ > ``` > > ⚠️ And if you use Goerli, make sure you use it in subsequent commands as well. @@ -285,6 +288,7 @@ another for the Account Descriptor file. ```bash export STARKNET_ACCOUNT=~/.starkli-wallets/deployer/my_account_1.json export STARKNET_KEYSTORE=~/.starkli-wallets/deployer/my_keystore_1.json + export STARKNET_RPC=https://starknet-testnet.public.blastapi.io/rpc/v0_6 ``` Setting these variables makes running Starkli commands easier and more @@ -313,13 +317,6 @@ This creates a compiled contract in `target/dev/` as `ownable_starknet_ownable.compiled_contract_class.json` (in Chapter 2 of the book we will learn more details about Scarb). -With the smart contract compiled, we’re ready to declare it using -Starkli. Then we can set the STARKNET_RPC environment variable to make command invocations easier: - -```bash - export STARKNET_RPC="https://starknet-sepolia.infura.io/v3/" -``` - ### Declaring Your Contract Run this command to declare your contract using the default Starknet @@ -330,7 +327,7 @@ Sequencer’s Gateway: ``` According to the `STARKNET_RPC` url, starkli can recognize the target -blockchain network, in this case "sepolia", so it is not necessary +blockchain network, in this case "goerli", so it is not necessary explicitly specify it. Unless you’re working with custom networks where it’s infeasible for diff --git a/src/ch03-01-03-data-availability.md b/src/ch03-01-03-data-availability.md index 9465e7801..b55e80074 100644 --- a/src/ch03-01-03-data-availability.md +++ b/src/ch03-01-03-data-availability.md @@ -10,7 +10,6 @@ Base layer blockchains such as Ethereum are evolving towards becoming Data Avail In parallel, Ethereum is undergoing a significant transition. Historically an execution-focused blockchain, Ethereum is now incorporating new Ethereum Improvement Proposals (EIPs) to shift its focus towards DA. - ## Data Availability in Starknet 1. **State Transition Process**: In Starknet, as in most blockchain networks, the system transitions from a state $n$ to state $(n+1)$ by executing a series of transactions within a block. In Starknet's case, this is done through the Cairo language. @@ -25,7 +24,6 @@ If for some reason, both the sequencer and the Layer 2 full nodes stop respondin Although this situation is highly unlikely, its potential impact is significant. It would halt the progress of the network, preventing any state transitions and effectively freezing operations. - ## State Diffs Starknet addresses the liveness problem through the transmission of validity proofs and state differences to Layer 1. This process is critical for ensuring that the network remains operational and its state can be verified independently of the sequencer and Layer 2 full nodes. @@ -38,16 +36,16 @@ Starknet addresses the liveness problem through the transmission of validity pro The state diff involves a substantial amount of data. To manage this, the data is sent as 'cold data' to Layer 1. It implies that the data isn't directly stored but is made available in a way that requires significant transactional capacity to transfer to Layer 1. - ## Data Availability and State Changes in Transactions **Transmitting Changes, Not Balances**: What Starknet sends to Layer 1 for data availability are the changes in state, not the new balances. This involves capturing how each transaction within a validity proof alters the state. 1. **Example 1**: Consider a simple scenario with three participants: Jimmy, Rose, and Nick. + - **Transaction Sequence**: Jimmy sends one ETH to Rose, then Rose sends half an ETH to Nick. - **State Changes Sent to Layer 1**: The data sent to Layer 1 would reflect that Jimmy has one ETH less, Rose has half an ETH more, and Nick also gains half an ETH. -2. **Example 2**: The net changes are what matter. For instance, if Jimmy and Rose send ETH back and forth, but the end result is Jimmy having half an ETH more and Rose half an ETH less, only these net changes are sent to Layer 1. +2. **Example 2**: The net changes are what matter. For instance, if Jimmy and Rose send ETH back and forth, but the end result is Jimmy having half an ETH more and Rose half an ETH less, only these net changes are sent to Layer 1. @@ -57,7 +55,6 @@ In cases where transactions between parties nullify each other (e.g., Rose sends Since the cost of sending data to Ethereum as cold data constitutes about 90% of a Layer 2 transaction's cost, reducing the amount of data sent can significantly impact overall transaction costs. Projects on Starknet often use strategies to minimize state changes in their transactions, thereby reducing the data sent to Layer 1 and lowering transaction costs. - ## Reducing Data Availability Costs in Starknet Two main mechanisms to reduce data availability costs are currently under consideration: the implementation of EIP 4844 and the concept of Volition. Both aim to optimize how data is stored and reduce the associated costs. @@ -72,10 +69,9 @@ Starknet's adoption of this feature depends on its implementation on the Ethereu Volition introduces the concept of choosing where to store data for transaction liveness. Users can opt to post data either to Ethereum or off-chain alternatives such as a data availability committee, systems like Celestia, or EigenDA. The cost of using Volition varies based on the chosen storage option. Off-chain options are expected to be cheaper than using EIP 4844. -The timeline for enabling Volition on Starknet is not yet determined, but it's certain to follow the support of EIP 4844. - -While EIP 4844's blob data approach will be beneficial for multiple rollups, Volition offers a unique advantage for Starknet by providing more flexibility in data storage and potentially lowering costs further. The implementation of Volition requires having a virtual machine that is not limited by the adherence to emulate the EVM, so a custom virtual machine like Cairo is required. +The timeline for enabling Volition on Starknet is not yet determined, but it's certain to follow the support of EIP 4844. +While EIP 4844's blob data approach will be beneficial for multiple rollups, Volition offers a unique advantage for Starknet by providing more flexibility in data storage and potentially lowering costs further. The implementation of Volition requires having a virtual machine that is not limited by the adherence to emulate the EVM, so a custom virtual machine like Cairo is required. ## Recreating Starknet's State @@ -94,29 +90,29 @@ This process is a contingency plan for extreme scenarios where the sequencer and This process ensures that the network's state is never lost and can always be recovered from Layer 1 data. - - + ## The StarknetOS The StarknetOS, the last step inside the Sequencer, plays a crucial role in determining why the state diff is the output of the SHARP and how it interacts with the network's state. The StarknetOS is based on Cairo Zero, an older version of the Cairo programming language. - + The StarknetOS receives four main inputs: - - The current state of the network. - - New blocks created since the last validity proof was sent to Layer 1. These include declare_account and invoke transactions. - - Class hashes resulting from declared transactions. - - Compiled class hashes resulting from declared transactions. + +- The current state of the network. +- New blocks created since the last validity proof was sent to Layer 1. These include declare_account and invoke transactions. +- Class hashes resulting from declared transactions. +- Compiled class hashes resulting from declared transactions. The StarknetOS takes the current state and processes the new transactions and blocks. It evaluates what changes occur in the state as a result of these transactions. The output from this process includes: - - The state diff: Changes in the state. - - Class hashes of newly declared smart contracts. - - Compiled class hashes of newly declared smart contracts. - +- The state diff: Changes in the state. +- Class hashes of newly declared smart contracts. +- Compiled class hashes of newly declared smart contracts. -The sequencer executes numerous transactions and creates blocks. When enough blocks accumulate, they trigger the creation of a validity proof. These blocks are passed to the StarknetOS to calculate the state diff, class hashes, and compiled class hashes. This is the information that the Prover is tasked with proving. The output from the [Blockchain Writer](https://etherscan.io/address/0x16d5783a96ab20c9157d7933ac236646b29589a4), therefore, includes these three elements: state diff, class hashes, and compiled class hashes. This output is what gets sent to the memory pages smart contract on Ethereum. + +The sequencer executes numerous transactions and creates blocks. When enough blocks accumulate, they trigger the creation of a validity proof. These blocks are passed to the StarknetOS to calculate the state diff, class hashes, and compiled class hashes. This is the information that the Prover is tasked with proving. The output from the [Blockchain Writer](https://etherscan.io/address/0x16d5783a96ab20c9157d7933ac236646b29589a4), therefore, includes these three elements: state diff, class hashes, and compiled class hashes. This output is what gets sent to the memory pages smart contract on Ethereum. ## The Blockchain Writer Module @@ -130,7 +126,7 @@ Internally, SHARP utilizes an Externally Owned Account (EOA) specifically for in 3. **Final Step in Data Transmission**: The Blockchain Writer represents the final step in the process where the proven data from Starknet's internal operations is transmitted to Ethereum for storage and verification. - + This is Ethereum address of the Blockchain Writer, which is by itself an EOA holding resources: [0x16d5783a96ab20c9157d7933ac236646b29589a4](https://etherscan.io/address/0x16d5783a96ab20c9157d7933ac236646b29589a4). @@ -138,7 +134,6 @@ The cost for data availability in Starknet, as handled by SHARP, is a direct exp A closer look at the transactions emanating from the [Blockchain Writer](https://etherscan.io/address/0x16d5783a96ab20c9157d7933ac236646b29589a4), which are responsible for DA, reveals substantial costs. SHARP incurs millions of dollars in expenses for block space on Ethereum each month. - ## Data Availability Modes Currently, there are three primary modes, with two already in use and a third on the horizon. These modes are Rollup, Validium, and Volition. @@ -165,8 +160,8 @@ Currently, there are three primary modes, with two already in use and a third on The following table summarizes the key characteristics of each mode: -| Mode | Definition | Advantages | Cost | Example | -|----------|-----------------------------------------------|--------------------------------------------|----------------|-----------| -| Rollup | Data posted on Ethereum; a Layer 2 solution. | Reliable, robust data availability. | Higher cost. | Starknet | -| Validium | Data stored off-chain, not on Ethereum. | Lower transaction costs. | Lower cost. | StarkEx | -| Volition | Hybrid mode, choice of on-chain or off-chain. | Balance between cost and data availability. | - | - | +| Mode | Definition | Advantages | Cost | Example | +| -------- | --------------------------------------------- | ------------------------------------------- | ------------ | -------- | +| Rollup | Data posted on Ethereum; a Layer 2 solution. | Reliable, robust data availability. | Higher cost. | Starknet | +| Validium | Data stored off-chain, not on Ethereum. | Lower transaction costs. | Lower cost. | StarkEx | +| Volition | Hybrid mode, choice of on-chain or off-chain. | Balance between cost and data availability. | - | - |