├── .cargo └── config.toml ├── .gitattributes ├── .github ├── codecov.yml ├── pull_request_template.md └── workflows │ └── rust-tests.yml ├── .gitignore ├── .tarpaulin.toml ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── Makefile ├── README.md ├── bench ├── internals.rs ├── yas.rs └── yas │ ├── .gitignore │ ├── ERC20.json │ ├── ERC20.sierra.json │ ├── YASFactory.json │ ├── YASFactory.sierra.json │ ├── YASPool.json │ ├── YASPool.sierra.json │ ├── YASRouter.json │ ├── YASRouter.sierra.json │ ├── YasCustomAccount.cairo │ ├── YasCustomAccount.json │ └── YasCustomAccount.sierra.json ├── bench_integration.py ├── cairo_programs ├── compiled_class.cairo ├── constants.cairo ├── contract_class.cairo ├── deprecated_compiled_class.cairo ├── erc20.sierra ├── new_syscalls.cairo ├── not_main.cairo └── wallet.sierra ├── docs ├── starknetstate.deploy.pdf └── state_requirements_for_operation ├── examples ├── contract_execution │ ├── Cargo.toml │ ├── README.md │ └── src │ │ └── main.rs └── lru_cache │ └── main.rs ├── fuzzer ├── Cargo.toml ├── README.md └── src │ └── main.rs ├── replay ├── Cargo.toml └── src │ └── main.rs ├── requirements.txt ├── rpc_state_reader ├── Cargo.toml ├── src │ ├── lib.rs │ ├── rpc_state.rs │ ├── rpc_state_errors.rs │ ├── sir_state_reader.rs │ └── utils.rs ├── test-responses │ └── .gitkeep └── tests │ ├── blockifier_tests.rs │ └── sir_tests.rs ├── rust-toolchain.toml ├── scripts ├── bench-deploy-invoke.sh ├── bench-deploy.sh ├── bench-fibonacci.sh ├── bench-invoke.sh └── heaptrack.sh ├── src ├── bin │ ├── deploy.rs │ ├── deploy_invoke.rs │ ├── fibonacci.rs │ ├── invoke.rs │ ├── invoke_with_cachedstate.rs │ └── native_bench.rs ├── core │ ├── block_hash │ │ ├── mod.rs │ │ └── starknet_block_hash.rs │ ├── contract_address │ │ ├── casm_contract_address.rs │ │ ├── deprecated_contract_address.rs │ │ ├── mod.rs │ │ └── sierra_contract_address.rs │ ├── errors │ │ ├── contract_address_errors.rs │ │ ├── hash_errors.rs │ │ ├── mod.rs │ │ └── state_errors.rs │ ├── mod.rs │ └── transaction_hash │ │ ├── current.rs │ │ ├── deprecated.rs │ │ └── mod.rs ├── definitions │ ├── block_context.rs │ ├── constants.rs │ ├── mod.rs │ └── transaction_type.rs ├── execution │ ├── execution_entry_point.rs │ ├── gas_usage.rs │ ├── mod.rs │ └── os_usage.rs ├── hash_utils.rs ├── lib.rs ├── parser_errors.rs ├── runner │ └── mod.rs ├── serde_structs │ └── mod.rs ├── services │ ├── api │ │ ├── contract_class_errors.rs │ │ ├── contract_classes │ │ │ ├── compiled_class.rs │ │ │ ├── deprecated_contract_class.rs │ │ │ └── mod.rs │ │ ├── messages.rs │ │ └── mod.rs │ ├── eth_definitions │ │ ├── eth_gas_constants.rs │ │ └── mod.rs │ └── mod.rs ├── state │ ├── cached_state.rs │ ├── contract_class_cache.rs │ ├── contract_storage_state.rs │ ├── in_memory_state_reader.rs │ ├── mod.rs │ ├── state_api.rs │ └── state_cache.rs ├── syscalls │ ├── business_logic_syscall_handler.rs │ ├── deprecated_business_logic_syscall_handler.rs │ ├── deprecated_syscall_handler.rs │ ├── deprecated_syscall_request.rs │ ├── deprecated_syscall_response.rs │ ├── hint_code.rs │ ├── mod.rs │ ├── native_syscall_handler.rs │ ├── other_syscalls.rs │ ├── syscall_handler.rs │ ├── syscall_handler_errors.rs │ ├── syscall_info.rs │ ├── syscall_request.rs │ └── syscall_response.rs ├── transaction │ ├── declare.rs │ ├── declare_deprecated.rs │ ├── deploy.rs │ ├── deploy_account.rs │ ├── error.rs │ ├── fee.rs │ ├── invoke_function.rs │ ├── l1_handler.rs │ └── mod.rs └── utils.rs ├── starknet_logo.svg ├── starknet_programs ├── Account.cairo ├── AccountPreset.cairo ├── ERC165.cairo ├── ERC20.cairo ├── ERC721.cairo ├── account_without_validation.cairo ├── account_without_validation_and_expensive_constructor.cairo ├── amm.cairo ├── amm_proxy.cairo ├── blockifier │ ├── ERC20_without_some_syscalls │ │ ├── ERC20 │ │ │ ├── ERC20_base.cairo │ │ │ └── permitted.cairo │ │ └── upgradability_proxy │ │ │ └── initializable.cairo │ └── rabbitx │ │ └── contracts │ │ └── protocol │ │ └── libraries │ │ ├── helpers │ │ ├── bool_cmp.cairo │ │ └── constants.cairo │ │ ├── math │ │ └── safe_cmp.cairo │ │ └── types │ │ └── data_types.cairo ├── cairo2 │ ├── account_panic.cairo │ ├── callee.cairo │ ├── caller.cairo │ ├── contract_a.cairo │ ├── deploy.cairo │ ├── deploy_contract_no_args.cairo │ ├── deploy_erc20.cairo │ ├── deploy_with_constructor.cairo │ ├── deploy_without_constructor.cairo │ ├── echo.cairo │ ├── echo_caller.cairo │ ├── emit_event.cairo │ ├── erc20.cairo │ ├── event_emitter.cairo │ ├── events.cairo │ ├── example_contract.cairo │ ├── factorial.cairo │ ├── factorial_tr.cairo │ ├── failing_constructor.cairo │ ├── faulty_low_level_storage_read.cairo │ ├── faulty_low_level_storage_write.cairo │ ├── faulty_math_lib.cairo │ ├── fibonacci.cairo │ ├── fibonacci_dispatcher.cairo │ ├── get_block_hash_basic.cairo │ ├── get_execution_info.cairo │ ├── get_execution_info_v2.cairo │ ├── get_number_a.cairo │ ├── get_number_b.cairo │ ├── get_number_wrapper.cairo │ ├── hello_world_account.cairo │ ├── math_lib.cairo │ ├── multi_syscall_test.cairo │ ├── send_message_to_l1.cairo │ ├── send_messages_contract_call.cairo │ ├── send_simple_message_to_l1.cairo │ ├── simple_wallet.cairo │ ├── square_root.cairo │ ├── square_root_recursive.cairo │ ├── test_cairo_keccak.cairo │ └── wallet_wrapper.cairo ├── constructor.cairo ├── delegate_call.cairo ├── delegate_l1_handler.cairo ├── deployer.cairo ├── empty_contract.cairo ├── factorial.cairo ├── fibonacci.cairo ├── first_contract.cairo ├── get_number.cairo ├── get_number_c.cairo ├── get_number_d.cairo ├── get_number_l1_handler.cairo ├── increase_balance.cairo ├── internal_calls.cairo ├── l1l2.cairo ├── rabbit.cairo ├── raw_contract_classes │ ├── 0x00801ad5dc7c995addf7fbce1c4c74413586acb44f9ff44ba903a08a6153fa80.json │ ├── 0x025ec026985a3bf9d0cc1fe17326b245dfdc3ff89b8fde106542a3ea56c5a918.json │ ├── 0x02c3348ad109f7f3967df6494b3c48741d61675d9a7915b265aa7101a631dc33.json │ ├── 0x03131fa018d520a037686ce3efddeab8f28895662f019ca3ca18a626650f7d1e.json │ ├── 0x04d07e40e93398ed3c76981e72dd1fd22557a78ce36c0515f679e27f0bb5bc5f_goerli.json │ ├── 0x04d07e40e93398ed3c76981e72dd1fd22557a78ce36c0515f679e27f0bb5bc5f_mainnet.json │ ├── 0x113bf26d112a164297e04381212c9bd7409f07591f0a04f539bdf56693eaaf3.sierra │ ├── 0x1354433237b0039baa138bf95b98fe4a8ae3df7ac4fd4d4845f0b41cd11bec4.json │ ├── 0x4479c3b883b34f1eafa5065418225d78a11ee7957c371e1b285e4b77afc6dad.json │ ├── 0x472a8c75c832b112ac174abc3b46e7e79464ad52ecdad80079ddfe486ca5eef.casm │ ├── 3010533bd60cb0e70ac1bf776e171713f0e5229a084989d3894c171c160ace2.casm │ ├── 321aadcf42b0a4ad905616598d16c42fa9b87c812dc398e49b57bf77930629f.casm │ ├── 53ad3bfb13f39cf1a9940108be4f9c6a8d9cc48a59d5f9b3c73432f877f8cf0.casm │ ├── 6638ce6c9bf336d1781a388668fa2206d928df5d1fa6b92e4cb41004c7e3f89.casm │ ├── 7c48d040ceb3183837a0aff2adf33d879f790e202eb2c4b8622005c12252641.casm │ ├── class_with_abi.json │ ├── fibonacci.sierra │ ├── program_without_attributes.json │ └── program_without_attributes_2.json ├── send_message_to_l1.cairo ├── send_messages_contract_call.cairo ├── starknet_libs_storage.cairo ├── storage.cairo ├── storage_var_and_constructor.cairo ├── syscalls-lib.cairo ├── syscalls.cairo └── test_contract.cairo └── tests ├── integration_tests ├── account_panic.rs ├── cairo_1_syscalls.rs ├── cairo_native.rs ├── complex_contracts │ ├── amm_contracts │ │ ├── amm.rs │ │ ├── amm_proxy.rs │ │ └── mod.rs │ ├── erc20.rs │ ├── mod.rs │ ├── nft │ │ ├── erc721.rs │ │ └── mod.rs │ └── utils.rs ├── delegate_call.rs ├── delegate_l1_handler.rs ├── deploy_account.rs ├── fibonacci.rs ├── increase_balance.rs ├── internal_calls.rs ├── internals.rs ├── mod.rs ├── multi_syscall_test.rs ├── storage.rs ├── syscalls.rs ├── syscalls_errors.rs └── yas_bench_test.rs └── tests.rs /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | # needed for mac https://pyo3.rs/v0.14.2/building_and_distribution.html#macos 2 | [target.x86_64-apple-darwin] 3 | rustflags = ["-C", "link-arg=-undefined", "-C", "link-arg=dynamic_lookup"] 4 | 5 | [target.aarch64-apple-darwin] 6 | rustflags = ["-C", "link-arg=-undefined", "-C", "link-arg=dynamic_lookup"] 7 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.sierra linguist-generated 2 | *.casm linguist-generated 3 | -------------------------------------------------------------------------------- /.github/codecov.yml: -------------------------------------------------------------------------------- 1 | ignore: 2 | - "./src/bin" 3 | comment: 4 | layout: "reach, diff, flags, files" 5 | behavior: default 6 | require_changes: true # if true: only post the comment if coverage changes 7 | require_base: false # [yes :: must have a base report to post] 8 | require_head: true # [yes :: must have a head report to post] 9 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # TITLE 2 | 3 | ## Description 4 | 5 | Description of the pull request changes and motivation. 6 | 7 | ## Checklist 8 | - [ ] Linked to Github Issue 9 | - [ ] Unit tests added 10 | - [ ] Integration tests added. 11 | - [ ] This change requires new documentation. 12 | - [ ] Documentation has been added/updated. 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # BEGIN AUTOGENERATED 2 | 3 | ### Rust ### 4 | # Generated by Cargo 5 | # will have compiled files and executables 6 | debug/ 7 | target/ 8 | 9 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 10 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 11 | #Cargo.lock 12 | 13 | # These are backup files generated by rustfmt 14 | **/*.rs.bk 15 | 16 | # MSVC Windows builds of rustc generate these, which store debugging information 17 | *.pdb 18 | 19 | ### VisualStudioCode ### 20 | .vscode/* 21 | !.vscode/settings.json 22 | !.vscode/tasks.json 23 | !.vscode/launch.json 24 | !.vscode/extensions.json 25 | !.vscode/*.code-snippets 26 | 27 | # Local History for Visual Studio Code 28 | .history/ 29 | 30 | # Built Visual Studio Code Extensions 31 | *.vsix 32 | 33 | ### VisualStudioCode Patch ### 34 | # Ignore all local history of files 35 | .history 36 | .ionide 37 | 38 | # END AUTOGENERATED 39 | 40 | .env 41 | # the starting `/` assures this matches only on the repo's root 42 | /cairo2 43 | 44 | starknet-venv/ 45 | **/*.json 46 | 47 | starknet_programs/cairo2/*.casm 48 | starknet_programs/cairo2/*.sierra 49 | default.profraw 50 | **.DS_Store 51 | /scripts/reports 52 | __pycache__/ 53 | .pytest_cache/ 54 | # codecov report 55 | lcov.info 56 | .rusty-hook.toml 57 | !/starknet_programs/raw_contract_classes/*.json 58 | cairo-*.tar 59 | starknet-pypy-env/ -------------------------------------------------------------------------------- /.tarpaulin.toml: -------------------------------------------------------------------------------- 1 | [starknet-rs] 2 | exclude-files = [] 3 | 4 | [report] 5 | output-dir = "target/tarpaulin" 6 | out = ["Html", "Xml"] 7 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "starknet_in_rust" 3 | version = "0.4.0" 4 | edition = "2021" 5 | description = "A Rust implementation of Starknet execution logic" 6 | license = "Apache-2.0" 7 | 8 | [features] 9 | default = ["with_mimalloc"] 10 | with_mimalloc = ["dep:mimalloc"] 11 | metrics = [] 12 | # Disclaimer: This feature enables state modifications being applied on reverted and failings txs, and also disables address availability check when deploying contracts. 13 | # Only use for benchmarking using the replay binary 14 | replay_benchmark = [] 15 | 16 | [workspace] 17 | members = [ 18 | "fuzzer", 19 | "rpc_state_reader", 20 | "replay", 21 | "examples/contract_execution", 22 | ] 23 | 24 | [workspace.dependencies] 25 | cairo-lang-casm = "=2.5.4" 26 | cairo-lang-sierra = "=2.5.4" 27 | cairo-lang-starknet = "=2.5.4" 28 | cairo-lang-utils = "=2.5.4" 29 | cairo-vm = { git = "https://github.com/lambdaclass/cairo-vm", rev = "3547089579dd74f815edbc2d1caa91e00fc8a2f7", features = ["cairo-1-hints"] } 30 | num-traits = "0.2.15" 31 | starknet = "0.7.0" # todo: update to 0.9.0+ once cairo-lang is 2.6.0+ 32 | starknet_api = "0.7.0-dev.0" # todo: update to 0.9.0+ once cairo-lang is 2.6.0+ 33 | thiserror = "1.0.32" 34 | 35 | [dependencies] 36 | anyhow = "1.0" 37 | base64 = { version = "0.21.0", default-features = false, features = ["alloc"] } 38 | cairo-lang-casm = { workspace = true } 39 | cairo-lang-sierra = { workspace = true } 40 | cairo-lang-starknet = { workspace = true } 41 | cairo-lang-utils = { workspace = true } 42 | cairo-native = { git = "https://github.com/lambdaclass/cairo_native", rev = "baf57d2dde0036ac4848fc40c672826fb7ffcde4", optional = true } 43 | k256 = "0.13.3" 44 | p256 = "0.13.2" 45 | sec1 = "0.7.3" 46 | 47 | cairo-vm = { workspace = true } 48 | flate2 = "1.0.25" 49 | getset = "0.1.2" 50 | hex = "0.4.3" 51 | # TODO: Replace with sha3. We should look how to integrate it correctly to calculate sn_keccak 52 | keccak = "0.1.3" 53 | lazy_static = "1.4.0" 54 | mimalloc = { version = "0.1.29", default-features = false, optional = true } 55 | num-bigint = { version = "0.4", features = ["serde"] } 56 | num-integer = "0.1.45" 57 | num-traits = { workspace = true } 58 | once_cell = "1.17.1" 59 | sha3 = "0.10.1" 60 | serde = { version = "1.0.152", features = ["derive"] } 61 | serde_json = { version = "1.0", features = [ 62 | "arbitrary_precision", 63 | "raw_value", 64 | ] } 65 | serde_json_pythonic = "0.1.2" 66 | starknet = { workspace = true } 67 | starknet_api = { workspace = true } 68 | starknet-crypto = "0.6.1" 69 | thiserror = { workspace = true } 70 | tracing = "0.1.37" 71 | 72 | [dev-dependencies] 73 | assert_matches = "1.5.0" 74 | coverage-helper = "0.2.0" 75 | lru = "0.11.0" 76 | pretty_assertions_sorted = "1.2.3" 77 | tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } 78 | 79 | [[bench]] 80 | path = "bench/internals.rs" 81 | name = "internals" 82 | harness = false 83 | 84 | [[bin]] 85 | path = "src/bin/native_bench.rs" 86 | name = "cairo_native" 87 | required-features = ["cairo-native"] 88 | 89 | [[bench]] 90 | path = "bench/yas.rs" 91 | name = "yas" 92 | harness = false 93 | 94 | [profile.release] 95 | codegen-units = 1 96 | lto = "fat" 97 | -------------------------------------------------------------------------------- /bench/yas/.gitignore: -------------------------------------------------------------------------------- 1 | !*.json 2 | -------------------------------------------------------------------------------- /bench/yas/YasCustomAccount.cairo: -------------------------------------------------------------------------------- 1 | use core::starknet::{account::Call, ContractAddress}; 2 | 3 | #[starknet::interface] 4 | trait IAccount { 5 | fn __execute__(ref self: TContractState, calls: Array) -> Span; 6 | fn __validate__(self: @TContractState, calls: Array) -> felt252; 7 | fn __validate_declare__(self: @TContractState, class_hash: felt252) -> felt252; 8 | fn __validate_deploy__( 9 | self: @TContractState, 10 | class_hash: felt252, 11 | contract_address_salt: felt252, 12 | public_key: felt252, 13 | ) -> felt252; 14 | 15 | fn deploy( 16 | self: @TContractState, 17 | class_hash: felt252, 18 | contract_address_salt: felt252, 19 | call_data: Array, 20 | ) -> (ContractAddress, Span); 21 | } 22 | 23 | #[starknet::contract] 24 | mod Account { 25 | use core::array::ArrayTrait; 26 | use core::result::ResultTrait; 27 | use core::option::OptionTrait; 28 | use core::traits::TryInto; 29 | use super::{Call, IAccount}; 30 | use core::starknet::{ContractAddress, deploy_syscall}; 31 | 32 | #[storage] 33 | struct Storage { 34 | public_key: felt252, 35 | } 36 | 37 | #[constructor] 38 | fn constructor(ref self: ContractState, public_key: felt252) { 39 | self.public_key.write(public_key); 40 | } 41 | 42 | fn validate_transaction(self: @ContractState) -> felt252 { 43 | core::starknet::VALIDATED 44 | } 45 | 46 | #[external(v0)] 47 | impl Account of IAccount { 48 | fn __execute__(ref self: ContractState, mut calls: Array) -> Span { 49 | assert(calls.len() == 1_u32, 'MULTI_CALL_NOT_SUPPORTED'); 50 | 51 | let Call{to, selector, calldata } = calls.pop_front().unwrap(); 52 | match core::starknet::call_contract_syscall( 53 | address: to, entry_point_selector: selector, calldata: calldata.span(), 54 | ) { 55 | Result::Ok(x) => x, 56 | Result::Err(e) => core::panic(e), 57 | } 58 | } 59 | 60 | fn __validate__(self: @ContractState, calls: Array) -> felt252 { 61 | validate_transaction(self) 62 | } 63 | 64 | fn __validate_declare__(self: @ContractState, class_hash: felt252) -> felt252 { 65 | validate_transaction(self) 66 | } 67 | 68 | fn __validate_deploy__( 69 | self: @ContractState, 70 | class_hash: felt252, 71 | contract_address_salt: felt252, 72 | public_key: felt252, 73 | ) -> felt252 { 74 | validate_transaction(self) 75 | } 76 | 77 | fn deploy( 78 | self: @ContractState, 79 | class_hash: felt252, 80 | contract_address_salt: felt252, 81 | call_data: Array, 82 | ) -> (ContractAddress, Span) { 83 | match deploy_syscall( 84 | class_hash.try_into().unwrap(), contract_address_salt, call_data.span(), false 85 | ) { 86 | Result::Ok(x) => x, 87 | Result::Err(e) => core::panic(e), 88 | } 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /bench_integration.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import pytest 4 | import pytest_asyncio 5 | from starkware.starknet.compiler.compile import compile_starknet_files 6 | from starkware.starknet.testing.starknet import StarknetState 7 | from starkware.starknet.services.api.contract_class import ContractClass 8 | CONTRACT_FILE = os.path.join(os.path.dirname(__file__), "starknet_programs/first_contract.json") 9 | FIBONACCI_FILE = os.path.join(os.path.dirname(__file__), "starknet_programs/fibonacci.json") 10 | 11 | 12 | @pytest.mark.asyncio 13 | async def test_invoke(): 14 | runs = 10000 15 | starknet = await StarknetState.empty() 16 | json_program = open(CONTRACT_FILE).read() 17 | contract_class = ContractClass.loads(json_program) 18 | contract_address, _ = await starknet.deploy(contract_class=contract_class, constructor_calldata=[]) 19 | for i in range(runs): 20 | # take into account that you need to comment verify_version() 21 | # from cairo-lang in order to be able to run the selectors below 22 | # because invoke_raw inserts a default version=0 that throws an 23 | # error. 24 | res_1 = await starknet.invoke_raw(contract_address=contract_address, selector="increase_balance", calldata=[1000], max_fee=0) 25 | res_2 = await starknet.invoke_raw(contract_address=contract_address, selector="get_balance", calldata=[], max_fee=0) 26 | assert(res_2.call_info.retdata == [i*1000 + 1000]) 27 | 28 | @pytest.mark.asyncio 29 | async def test_deploy(): 30 | runs = 100 31 | starknet = await StarknetState.empty() 32 | json_program = open(CONTRACT_FILE).read() 33 | contract_class = ContractClass.loads(json_program) 34 | for i in range(runs): 35 | contract_address, _ = await starknet.deploy(contract_class=contract_class, constructor_calldata=[], contract_address_salt=i) 36 | 37 | @pytest.mark.asyncio 38 | async def test_fibonacci(): 39 | runs = 1000 40 | starknet = await StarknetState.empty() 41 | json_program = open(FIBONACCI_FILE).read() 42 | contract_class = ContractClass.loads(json_program) 43 | contract_address, _ = await starknet.deploy(contract_class=contract_class, constructor_calldata=[]) 44 | for i in range(runs): 45 | call = await starknet.invoke_raw(contract_address=contract_address, selector="fib", calldata=[1, 1, 1000], max_fee=0) 46 | assert(call.call_info.retdata == [222450955505511890955301767713383614666194461405743219770606958667979327682]) 47 | -------------------------------------------------------------------------------- /cairo_programs/constants.cairo: -------------------------------------------------------------------------------- 1 | // An entry point offset that indicates that nothing needs to be done. 2 | // Used to implement an empty constructor. 3 | const NOP_ENTRY_POINT_OFFSET = -1; 4 | 5 | const ENTRY_POINT_TYPE_EXTERNAL = 0; 6 | const ENTRY_POINT_TYPE_L1_HANDLER = 1; 7 | const ENTRY_POINT_TYPE_CONSTRUCTOR = 2; 8 | 9 | const DECLARE_VERSION = 2; 10 | const TRANSACTION_VERSION = 1; 11 | const L1_HANDLER_VERSION = 0; 12 | 13 | const SIERRA_ARRAY_LEN_BOUND = 2 ** 32; 14 | 15 | // get_selector_from_name('constructor'). 16 | const CONSTRUCTOR_ENTRY_POINT_SELECTOR = ( 17 | 0x28ffe4ff0f226a9107253e17a904099aa4f63a02a5621de0576e5aa71bc5194 18 | ); 19 | 20 | // get_selector_from_name('__execute__'). 21 | const EXECUTE_ENTRY_POINT_SELECTOR = ( 22 | 0x15d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad 23 | ); 24 | 25 | // get_selector_from_name('__validate__'). 26 | const VALIDATE_ENTRY_POINT_SELECTOR = ( 27 | 0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775 28 | ); 29 | 30 | // get_selector_from_name('__validate_declare__'). 31 | const VALIDATE_DECLARE_ENTRY_POINT_SELECTOR = ( 32 | 0x289da278a8dc833409cabfdad1581e8e7d40e42dcaed693fa4008dcdb4963b3 33 | ); 34 | 35 | // get_selector_from_name('__validate_deploy__'). 36 | const VALIDATE_DEPLOY_ENTRY_POINT_SELECTOR = ( 37 | 0x36fcbf06cd96843058359e1a75928beacfac10727dab22a3972f0af8aa92895 38 | ); 39 | 40 | // get_selector_from_name('transfer'). 41 | const TRANSFER_ENTRY_POINT_SELECTOR = ( 42 | 0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e 43 | ); 44 | 45 | const DEFAULT_ENTRY_POINT_SELECTOR = 0; 46 | 47 | // Gas constants. 48 | const STEP_GAS_COST = 100; 49 | const INITIAL_GAS_COST = (10 ** 8) * STEP_GAS_COST; 50 | 51 | // Compiler gas costs. 52 | 53 | // The initial budget at an entry point. This needs to be high enough to cover the initial get_gas. 54 | // The entry point may refund whatever remains from the initial budget. 55 | const ENTRY_POINT_INITIAL_BUDGET = 100 * STEP_GAS_COST; 56 | // The gas cost of each syscall libfunc (this value is hard-coded by the compiler). 57 | // This needs to be high enough to cover OS costs in the case of failure due to out of gas. 58 | const SYSCALL_BASE_GAS_COST = 100 * STEP_GAS_COST; 59 | 60 | // OS gas costs. 61 | 62 | // The base amount of gas for executing an entry point. This amount is reduced from the gas 63 | // counter by the OS. The rest of the required gas will be taken from the gas counter by the 64 | // contract. 65 | const ENTRY_POINT_GAS_COST = ENTRY_POINT_INITIAL_BUDGET + 500 * STEP_GAS_COST; 66 | 67 | const FEE_TRANSFER_GAS_COST = ENTRY_POINT_GAS_COST + 100 * STEP_GAS_COST; 68 | // The base amount of gas for executing a transaction. For example, this includes the cost of the 69 | // fee transfer and execution of two entry points ('validate' and 'execute'). 70 | const TRANSACTION_GAS_COST = (2 * ENTRY_POINT_GAS_COST) + FEE_TRANSFER_GAS_COST + ( 71 | 100 * STEP_GAS_COST 72 | ); 73 | // Syscall gas costs. 74 | const CALL_CONTRACT_GAS_COST = SYSCALL_BASE_GAS_COST + 10 * STEP_GAS_COST + ENTRY_POINT_GAS_COST; 75 | const DEPLOY_GAS_COST = SYSCALL_BASE_GAS_COST + 200 * STEP_GAS_COST + ENTRY_POINT_GAS_COST; 76 | const GET_EXECUTION_INFO_GAS_COST = SYSCALL_BASE_GAS_COST + 10 * STEP_GAS_COST; 77 | const LIBRARY_CALL_GAS_COST = CALL_CONTRACT_GAS_COST; 78 | const REPLACE_CLASS_GAS_COST = SYSCALL_BASE_GAS_COST + 50 * STEP_GAS_COST; 79 | const STORAGE_READ_GAS_COST = SYSCALL_BASE_GAS_COST + 50 * STEP_GAS_COST; 80 | const STORAGE_WRITE_GAS_COST = SYSCALL_BASE_GAS_COST + 50 * STEP_GAS_COST; 81 | const EMIT_EVENT_GAS_COST = SYSCALL_BASE_GAS_COST + 10 * STEP_GAS_COST; 82 | const SEND_MESSAGE_TO_L1_GAS_COST = SYSCALL_BASE_GAS_COST + 50 * STEP_GAS_COST; 83 | const GET_BLOCK_HASH_GAS_COST = SYSCALL_BASE_GAS_COST + 50 * STEP_GAS_COST; 84 | 85 | 86 | // Cairo 1.0 error codes. 87 | const ERROR_OUT_OF_GAS = 'Out of gas'; 88 | -------------------------------------------------------------------------------- /cairo_programs/contract_class.cairo: -------------------------------------------------------------------------------- 1 | from starkware.cairo.common.cairo_builtins import PoseidonBuiltin 2 | from starkware.cairo.common.hash_state_poseidon import ( 3 | HashState, 4 | hash_finalize, 5 | hash_init, 6 | hash_update_single, 7 | hash_update_with_nested_hash, 8 | ) 9 | 10 | const CONTRACT_CLASS_VERSION = 'CONTRACT_CLASS_V0.1.0'; 11 | 12 | struct ContractEntryPoint { 13 | // A field element that encodes the signature of the called function. 14 | selector: felt, 15 | function_idx: felt, 16 | } 17 | 18 | struct ContractClass { 19 | contract_class_version: felt, 20 | 21 | // The length and pointer to the external entry point table of the contract. 22 | n_external_functions: felt, 23 | external_functions: ContractEntryPoint*, 24 | 25 | // The length and pointer to the L1 handler entry point table of the contract. 26 | n_l1_handlers: felt, 27 | l1_handlers: ContractEntryPoint*, 28 | 29 | // The length and pointer to the constructor entry point table of the contract. 30 | n_constructors: felt, 31 | constructors: ContractEntryPoint*, 32 | 33 | // starknet_keccak of the contract ABI. 34 | // Note that the OS does not enforce any constraints on this value. 35 | abi_hash: felt, 36 | 37 | // The length and pointer of the Sierra program. 38 | sierra_program_length: felt, 39 | sierra_program_ptr: felt*, 40 | } 41 | 42 | func class_hash{poseidon_ptr: PoseidonBuiltin*}(contract_class: ContractClass*) -> (hash: felt) { 43 | let hash_state: HashState = hash_init(); 44 | with hash_state { 45 | hash_update_single(item=contract_class.contract_class_version); 46 | 47 | // Hash external entry points. 48 | hash_update_with_nested_hash( 49 | data_ptr=contract_class.external_functions, 50 | data_length=contract_class.n_external_functions * ContractEntryPoint.SIZE, 51 | ); 52 | 53 | // Hash L1 handler entry points. 54 | hash_update_with_nested_hash( 55 | data_ptr=contract_class.l1_handlers, 56 | data_length=contract_class.n_l1_handlers * ContractEntryPoint.SIZE, 57 | ); 58 | 59 | // Hash constructor entry points. 60 | hash_update_with_nested_hash( 61 | data_ptr=contract_class.constructors, 62 | data_length=contract_class.n_constructors * ContractEntryPoint.SIZE, 63 | ); 64 | 65 | // Hash abi_hash. 66 | hash_update_single(item=contract_class.abi_hash); 67 | 68 | // Hash Sierra program. 69 | hash_update_with_nested_hash( 70 | data_ptr=contract_class.sierra_program_ptr, 71 | data_length=contract_class.sierra_program_length, 72 | ); 73 | 74 | let hash: felt = hash_finalize(hash_state=hash_state); 75 | } 76 | return (hash=hash); 77 | } 78 | -------------------------------------------------------------------------------- /cairo_programs/new_syscalls.cairo: -------------------------------------------------------------------------------- 1 | // Syscall selectors. 2 | 3 | const CALL_CONTRACT_SELECTOR = 'CallContract'; 4 | const DEPLOY_SELECTOR = 'Deploy'; 5 | const EMIT_EVENT_SELECTOR = 'EmitEvent'; 6 | const GET_EXECUTION_INFO_SELECTOR = 'GetExecutionInfo'; 7 | const LIBRARY_CALL_SELECTOR = 'LibraryCall'; 8 | const REPLACE_CLASS_SELECTOR = 'ReplaceClass'; 9 | const SEND_MESSAGE_TO_L1_SELECTOR = 'SendMessageToL1'; 10 | const STORAGE_READ_SELECTOR = 'StorageRead'; 11 | const STORAGE_WRITE_SELECTOR = 'StorageWrite'; 12 | 13 | // Syscall structs. 14 | 15 | struct ExecutionInfo { 16 | block_info: BlockInfo*, 17 | tx_info: TxInfo*, 18 | 19 | // Entry-point-specific info. 20 | 21 | caller_address: felt, 22 | // The execution is done in the context of the contract at this address. 23 | // It controls the storage being used, messages sent to L1, calling contracts, etc. 24 | contract_address: felt, 25 | // The entry point selector. 26 | selector: felt, 27 | } 28 | 29 | struct BlockInfo { 30 | block_number: felt, 31 | block_timestamp: felt, 32 | // The address of the sequencer that is creating this block. 33 | sequencer_address: felt, 34 | } 35 | 36 | struct TxInfo { 37 | // The version of the transaction. It is fixed in the OS, and should be signed by the account 38 | // contract. 39 | // This field allows invalidating old transactions, whenever the meaning of the other 40 | // transaction fields is changed (in the OS). 41 | version: felt, 42 | // The account contract from which this transaction originates. 43 | account_contract_address: felt, 44 | // The max_fee field of the transaction. 45 | max_fee: felt, 46 | // The signature of the transaction. 47 | signature_start: felt*, 48 | signature_end: felt*, 49 | // The hash of the transaction. 50 | transaction_hash: felt, 51 | // The identifier of the chain. 52 | // This field can be used to prevent replay of testnet transactions on mainnet. 53 | chain_id: felt, 54 | // The transaction's nonce. 55 | nonce: felt, 56 | } 57 | 58 | // Shared attributes. 59 | 60 | struct RequestHeader { 61 | // The syscall selector. 62 | selector: felt, 63 | // The amount of gas left before the syscall execution. 64 | gas: felt, 65 | } 66 | 67 | struct ResponseHeader { 68 | // The amount of gas left after the syscall execution. 69 | gas: felt, 70 | // 0 if the syscall succeeded; 1 otherwise. 71 | failure_flag: felt, 72 | } 73 | 74 | struct FailureReason { 75 | start: felt*, 76 | end: felt*, 77 | } 78 | 79 | // Syscall requests. 80 | 81 | struct CallContractRequest { 82 | // The address of the L2 contract to call. 83 | contract_address: felt, 84 | // The selector of the function to call. 85 | selector: felt, 86 | // The calldata. 87 | calldata_start: felt*, 88 | calldata_end: felt*, 89 | } 90 | 91 | struct LibraryCallRequest { 92 | // The hash of the class to run. 93 | class_hash: felt, 94 | // The selector of the function to call. 95 | selector: felt, 96 | // The calldata. 97 | calldata_start: felt*, 98 | calldata_end: felt*, 99 | } 100 | 101 | struct EmptyRequest { 102 | } 103 | 104 | struct DeployRequest { 105 | // The hash of the class to deploy. 106 | class_hash: felt, 107 | // A salt for the new contract address calculation. 108 | contract_address_salt: felt, 109 | // The calldata for the constructor. 110 | constructor_calldata_start: felt*, 111 | constructor_calldata_end: felt*, 112 | // Used for deterministic contract address deployment. 113 | deploy_from_zero: felt, 114 | } 115 | 116 | struct StorageReadRequest { 117 | reserved: felt, 118 | key: felt, 119 | } 120 | 121 | struct StorageWriteRequest { 122 | reserved: felt, 123 | key: felt, 124 | value: felt, 125 | } 126 | 127 | struct EmitEventRequest { 128 | keys_start: felt*, 129 | keys_end: felt*, 130 | data_start: felt*, 131 | data_end: felt*, 132 | } 133 | 134 | struct ReplaceClassRequest { 135 | class_hash: felt, 136 | } 137 | 138 | struct SendMessageToL1Request { 139 | to_address: felt, 140 | payload_start: felt*, 141 | payload_end: felt*, 142 | } 143 | 144 | // Syscall responses. 145 | 146 | struct CallContractResponse { 147 | retdata_start: felt*, 148 | retdata_end: felt*, 149 | } 150 | 151 | struct DeployResponse { 152 | contract_address: felt, 153 | constructor_retdata_start: felt*, 154 | constructor_retdata_end: felt*, 155 | } 156 | 157 | struct StorageReadResponse { 158 | value: felt, 159 | } 160 | 161 | struct GetExecutionInfoResponse { 162 | execution_info: ExecutionInfo*, 163 | } 164 | -------------------------------------------------------------------------------- /cairo_programs/not_main.cairo: -------------------------------------------------------------------------------- 1 | func not_main() { 2 | [ap] = 123; 3 | ret; 4 | } 5 | 6 | func main() { 7 | ret; 8 | } 9 | -------------------------------------------------------------------------------- /docs/starknetstate.deploy.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambdaclass/starknet_in_rust/3e8e67518278f33115677360531c14718e071d1b/docs/starknetstate.deploy.pdf -------------------------------------------------------------------------------- /docs/state_requirements_for_operation: -------------------------------------------------------------------------------- 1 | In general, in order to perform operations on the state we need at least one funded account X and a fee token contract deployed. 2 | 3 | Lets divide the requirements in differents scenarios: 4 | 5 | - Non-account: X declares the contract using an external *Declare* transaction and pays for its __validate_declare__ execution. Then, the only way to deploy the account is through the **syscall deploy()** which will eventually be called during an **InvokeTransaction** which a funded account pays for. 6 | - Account (not first one): it's declared the same. To deploy, you can either use DeployAccount external transaction (which indeed exists especially for the first account deployment, but can also be used regularly for accounts); or, through the syscall deploy() as above. Again, a funded account needs to pay for this. 7 | In case of DeployAccount the account being deployed can pay for itself if the money was prepared beforehand in the fee token contract using a deposit from L1 (the addresses in ERC20 can be of a nonexistent account). 8 | - First account: you can't execute transactions on an entirely empty state. 9 | Minimal content of a state to allow full system operation (which will not be paid for): 10 | - A deployed fee token contract with at least one funded account. 11 | - A declared account contract. 12 | From there, the first account must be deployed using an external DeployAccount transaction (and pay for itself, preparing the money in advance in the ERC20, as above). 13 | 14 | Now you have an L2 deployed account and can continue. -------------------------------------------------------------------------------- /examples/contract_execution/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "contract_execution" 3 | version = "0.4.0" 4 | edition = "2021" 5 | 6 | [features] 7 | cairo-native = ["starknet_in_rust/cairo-native"] 8 | 9 | [dependencies] 10 | cairo-vm = { workspace = true } 11 | starknet_in_rust = { path = "../../", version = "0.4.0" } 12 | serde_json = { version = "1.0", features = [ 13 | "arbitrary_precision", 14 | "raw_value", 15 | ] } 16 | -------------------------------------------------------------------------------- /examples/contract_execution/README.md: -------------------------------------------------------------------------------- 1 | ## Running simple contracts 2 | 3 | The idea of this small tutorial is to introduce how to run simple contracts using starknet_in_rust, specifically how to call *external* functions given a already declared (contract class defined in the starknet state) and deploy (a given instance of a contract class, with storage assigned to it) contract. 4 | 5 | As declare and deploy transactions are currently WIP, we encapsulate all the functionality (declaring, deploying and executing a given entrypoint) in ```main.rs```. 6 | 7 | ## How to use 8 | 9 | - First run ```make deps``` in order to setup the environment. 10 | 11 | - Add your contract to this directory. 12 | 13 | - Compile the contract: 14 | - ```source starknet-venv/bin/activate``` 15 | - ```cairo2/bin/starknet-compile your_contract.cairo --single-file your_contract.json``` 16 | 17 | - Add a test for your contract calling ```test_contract``` passing: 18 | - Your compiled contract path 19 | - The entrypoint you are wanting to execute 20 | - The parameters needed in order to call that entrypoint 21 | - The expected returned value 22 | -------------------------------------------------------------------------------- /examples/lru_cache/main.rs: -------------------------------------------------------------------------------- 1 | // #![deny(warnings)] 2 | 3 | use cairo_vm::Felt252; 4 | use lru::LruCache; 5 | use starknet_in_rust::{ 6 | definitions::{block_context::BlockContext, constants::TRANSACTION_VERSION}, 7 | services::api::contract_classes::{ 8 | compiled_class::CompiledClass, deprecated_contract_class::ContractClass, 9 | }, 10 | state::{ 11 | cached_state::CachedState, 12 | contract_class_cache::{ContractClassCache, PermanentContractClassCache}, 13 | in_memory_state_reader::InMemoryStateReader, 14 | }, 15 | transaction::{Address, ClassHash, DeclareDeprecated, Deploy, InvokeFunction}, 16 | utils::calculate_sn_keccak, 17 | }; 18 | use std::{ 19 | num::NonZeroUsize, 20 | path::Path, 21 | sync::{Arc, Mutex}, 22 | }; 23 | 24 | fn main() { 25 | let shared_cache = Arc::new(LruContractCache::new(NonZeroUsize::new(64).unwrap())); 26 | 27 | let ret_data = run_contract( 28 | "starknet_programs/factorial.json", 29 | "factorial", 30 | [10.into()], 31 | shared_cache, 32 | ); 33 | 34 | println!("{ret_data:?}"); 35 | } 36 | 37 | fn run_contract( 38 | contract_path: impl AsRef, 39 | entry_point: impl AsRef, 40 | calldata: impl Into>, 41 | contract_cache: Arc, 42 | ) -> Vec { 43 | let block_context = BlockContext::default(); 44 | let chain_id = *block_context.starknet_os_config().chain_id(); 45 | let sender_address = Address(1.into()); 46 | let signature = vec![]; 47 | 48 | let state_reader = Arc::new(InMemoryStateReader::default()); 49 | let mut state = CachedState::new( 50 | state_reader, 51 | Arc::new(PermanentContractClassCache::default()), 52 | ); 53 | 54 | let contract_class = ContractClass::from_path(contract_path.as_ref()).unwrap(); 55 | 56 | let declare_tx = DeclareDeprecated::new( 57 | contract_class.clone(), 58 | chain_id, 59 | sender_address, 60 | 0, 61 | 0.into(), 62 | signature.clone(), 63 | 0.into(), 64 | ) 65 | .unwrap(); 66 | 67 | declare_tx 68 | .execute( 69 | &mut state, 70 | &block_context, 71 | #[cfg(feature = "cairo-native")] 72 | None, 73 | ) 74 | .unwrap(); 75 | 76 | let deploy_tx = Deploy::new( 77 | Default::default(), 78 | contract_class, 79 | Vec::new(), 80 | *block_context.starknet_os_config().chain_id(), 81 | *TRANSACTION_VERSION, 82 | ) 83 | .unwrap(); 84 | 85 | deploy_tx 86 | .execute( 87 | &mut state, 88 | &block_context, 89 | #[cfg(feature = "cairo-native")] 90 | None, 91 | ) 92 | .unwrap(); 93 | 94 | let entry_point_selector = 95 | Felt252::from_bytes_be(&calculate_sn_keccak(entry_point.as_ref().as_bytes())); 96 | 97 | let invoke_tx = InvokeFunction::new( 98 | deploy_tx.contract_address.clone(), 99 | entry_point_selector, 100 | Default::default(), 101 | *TRANSACTION_VERSION, 102 | calldata.into(), 103 | signature, 104 | chain_id, 105 | Some(0.into()), 106 | ) 107 | .unwrap(); 108 | 109 | let invoke_tx_execution_info = invoke_tx 110 | .execute( 111 | &mut state, 112 | &block_context, 113 | 0, 114 | #[cfg(feature = "cairo-native")] 115 | None, 116 | ) 117 | .unwrap(); 118 | 119 | // Store the local cache changes into the shared cache. This updates the shared cache with all 120 | // the contracts used on this state. 121 | contract_cache.extend(state.drain_private_contract_class_cache().unwrap()); 122 | 123 | invoke_tx_execution_info.call_info.unwrap().retdata 124 | } 125 | 126 | pub struct LruContractCache { 127 | storage: Mutex>, 128 | } 129 | 130 | impl LruContractCache { 131 | pub fn new(cap: NonZeroUsize) -> Self { 132 | Self { 133 | storage: Mutex::new(LruCache::new(cap)), 134 | } 135 | } 136 | 137 | pub fn extend(&self, other: I) 138 | where 139 | I: IntoIterator, 140 | { 141 | other.into_iter().for_each(|(k, v)| { 142 | self.storage.lock().unwrap().put(k, v); 143 | }); 144 | } 145 | } 146 | 147 | impl ContractClassCache for LruContractCache { 148 | fn get_contract_class(&self, class_hash: ClassHash) -> Option { 149 | self.storage.lock().unwrap().get(&class_hash).cloned() 150 | } 151 | 152 | fn set_contract_class(&self, class_hash: ClassHash, compiled_class: CompiledClass) { 153 | self.storage.lock().unwrap().put(class_hash, compiled_class); 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /fuzzer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fuzzer" 3 | version = "0.4.0" 4 | edition = "2021" 5 | 6 | [features] 7 | cairo-native = ["starknet_in_rust/cairo-native"] 8 | 9 | [dependencies] 10 | honggfuzz = "0.5.55" 11 | starknet_in_rust = { path = "../", version = "0.4.0" } 12 | num-traits = { workspace = true } 13 | starknet_api = { workspace = true } 14 | serde_json = { version = "1.0", features = ["arbitrary_precision"] } 15 | tempfile = "3.2.0" 16 | cairo-vm = { workspace = true, features = ["cairo-1-hints"] } 17 | -------------------------------------------------------------------------------- /fuzzer/README.md: -------------------------------------------------------------------------------- 1 | # To run this fuzzer 2 | 3 | ## 1. Create a container to run it 4 | 5 | Please refer to the user guide section in this [repository](https://github.com/lambdaclass/fuzzing_examples#user-guide) to create a container with the included Dockerfile. 6 | 7 | ## 2. Run the fuzzer 8 | 9 | 1. Start the container as explained in last section. 10 | 2. Clone the proyect in the container with `git clone -b main --single-branch --depth 1 https://github.com/lambdaclass/starknet_in_rust.git`. 11 | 3. Install dependencies with `apt-get install -y libgmp-dev python3-venv python3-dev`. 12 | 4. Run `make deps` and `source starknet-venv/bin/activate` to have a working environment. 13 | 5. Run the command `HFUZZ_RUN_ARGS="-n 1" cargo hfuzz run fuzzer` within the _fuzzer_ folder. 14 | 15 | The crashes found will be stored in the _hfuzz_workspace_ folder along with the reports and all the inputs used. 16 | 17 | ## 3. Analyze the crash 18 | 19 | Once you find a crash, use the command `cargo hfuzz run-debug fuzzer ` to debug. 20 | -------------------------------------------------------------------------------- /replay/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "replay" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [features] 9 | benchmark = ["starknet_in_rust/replay_benchmark"] 10 | 11 | [dependencies] 12 | # starknet specific crates 13 | starknet_in_rust = { path = "../", version = "0.4.0" } 14 | rpc_state_reader = { path = "../rpc_state_reader", features = ["starknet_in_rust"] } 15 | starknet_api = { workspace = true } 16 | # CLI specific crates 17 | clap = { version = "4.4.6", features = ["derive"] } 18 | indicatif = "0.17.7" 19 | # logs 20 | tracing = "0.1" 21 | tracing-subscriber = "0.3.17" 22 | # error handling 23 | anyhow = "1.0" 24 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | fastecdsa 2 | cairo-lang==0.11 3 | openzeppelin-cairo-contracts==0.6.1 4 | -------------------------------------------------------------------------------- /rpc_state_reader/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rpc_state_reader" 3 | version = "0.4.0" 4 | edition = "2021" 5 | 6 | [features] 7 | default = ["starknet_in_rust"] 8 | starknet_in_rust = [] 9 | cairo-native = ["starknet_in_rust/cairo-native"] 10 | 11 | [dependencies] 12 | ureq = { version = "2.7.1", features = ["json"] } 13 | serde = { version = "1.0", features = ["derive"] } 14 | serde_json = { version = "1.0", features = [ 15 | "arbitrary_precision", 16 | "raw_value", 17 | ] } 18 | starknet_api = "0.7.0-dev.0" 19 | cairo-lang-starknet = { workspace = true } 20 | cairo-lang-utils = { workspace = true } 21 | starknet = { workspace = true } 22 | thiserror = { workspace = true } 23 | flate2 = "1.0.25" 24 | serde_with = "3.0.0" 25 | dotenv = "0.15.0" 26 | cairo-vm = { workspace = true } 27 | cairo-vm-blockifier = { package = "cairo-vm", version = "0.9.1" } 28 | blockifier = "=0.5.0-dev.0" 29 | starknet_in_rust = { path = "../", version = "0.4.0" } 30 | 31 | [dev-dependencies] 32 | pretty_assertions_sorted = "1.2.3" 33 | test-case = "3.1.0" 34 | -------------------------------------------------------------------------------- /rpc_state_reader/src/rpc_state_errors.rs: -------------------------------------------------------------------------------- 1 | use thiserror::Error; 2 | 3 | #[derive(Debug, Error)] 4 | pub enum RpcStateError { 5 | #[error("Missing .env file")] 6 | MissingEnvFile, 7 | #[error("Missing rpc endpoints")] 8 | MissingRpcEndpoints, 9 | #[error("RPC call failed with error: {0}")] 10 | RpcCall(String), 11 | #[error("Request failed with error: {0}")] 12 | Request(String), 13 | #[error(transparent)] 14 | Io(#[from] std::io::Error), 15 | #[error(transparent)] 16 | SerdeJson(#[from] serde_json::Error), 17 | #[error("Object {0} obtained from rpc call has no field {1}")] 18 | RpcObjectHasNoField(String, String), 19 | #[error("Failed to convert StarkFelt to PatriciaKey")] 20 | StarkFeltToParticiaKeyConversion, 21 | #[error("The service is down")] 22 | RpcConnectionNotAvailable, 23 | #[error("The response does not have a field named '{0}'")] 24 | MissingRpcResponseField(String), 25 | #[error("Wrong type for response field '{0}'")] 26 | RpcResponseWrongType(String), 27 | } 28 | -------------------------------------------------------------------------------- /rpc_state_reader/test-responses/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambdaclass/starknet_in_rust/3e8e67518278f33115677360531c14718e071d1b/rpc_state_reader/test-responses/.gitkeep -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "1.74.1" 3 | components = ["rustfmt", "clippy"] 4 | profile = "minimal" 5 | -------------------------------------------------------------------------------- /scripts/bench-deploy-invoke.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | hyperfine -N -w 3 -r 5 \ 3 | -n "cairo-lang (CPython) read/write storage 10k with deploy" "pytest bench_integration.py::test_invoke" \ 4 | -n "starknet_in_rust read/write storage 10k with deploy" "./target/release/deploy_invoke" 5 | -------------------------------------------------------------------------------- /scripts/bench-deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | hyperfine -N -w 3 -r 5 \ 3 | -n "cairo-lang (CPython) deploy 10k" "pytest bench_integration.py::test_deploy" \ 4 | -n "starknet_in_rust deploy 10k" "./target/release/deploy" 5 | -------------------------------------------------------------------------------- /scripts/bench-fibonacci.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | hyperfine -N -w 3 -r 5 \ 3 | -n "cairo-lang (CPython) fib 15k" "pytest bench_integration.py::test_fibonacci" \ 4 | -n "starknet_in_rust fib 15k" "./target/release/fibonacci" 5 | -------------------------------------------------------------------------------- /scripts/bench-invoke.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | hyperfine -N -w 3 -r 5 \ 3 | -n "cairo-lang (CPython) read/write storage 10k" "pytest bench_integration.py::test_invoke" \ 4 | -n "starknet_in_rust read/write storage 10k without deploy" "./target/release/invoke" 5 | -------------------------------------------------------------------------------- /scripts/heaptrack.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | declare -a tests=("fibonacci" 4 | "internals" 5 | "storage" 6 | ) 7 | 8 | mkdir -p reports reports/heaptrack reports/heaptrack/outfile reports/heaptrack/analysis 9 | 10 | for test in "${tests[@]}" 11 | do 12 | FILE_PREFIX="heaptrack.${test}" 13 | OUTFILE="reports/heaptrack/outfile/${FILE_PREFIX}" 14 | ANALYSIS="reports/heaptrack/analysis/${FILE_PREFIX}" 15 | echo "Heaptracking ${test}" 16 | # Runs the process and starts the heaptrack. 17 | heaptrack -o "${OUTFILE}" "cargo" "test" "--test" "${test}" 18 | # Analyze the file. 19 | heaptrack -a "${OUTFILE}.gz" > ${ANALYSIS}.txt 20 | echo "Heaptracked ${test}" 21 | done 22 | -------------------------------------------------------------------------------- /src/bin/deploy.rs: -------------------------------------------------------------------------------- 1 | use lazy_static::lazy_static; 2 | use starknet_in_rust::{ 3 | definitions::{block_context::BlockContext, constants::TRANSACTION_VERSION}, 4 | services::api::contract_classes::compiled_class::CompiledClass, 5 | services::api::contract_classes::deprecated_contract_class::ContractClass, 6 | state::{cached_state::CachedState, in_memory_state_reader::InMemoryStateReader}, 7 | state::{contract_class_cache::PermanentContractClassCache, state_api::State}, 8 | transaction::{Deploy, Transaction}, 9 | }; 10 | use std::sync::Arc; 11 | 12 | #[cfg(feature = "with_mimalloc")] 13 | use mimalloc::MiMalloc; 14 | 15 | #[cfg(feature = "with_mimalloc")] 16 | #[global_allocator] 17 | static ALLOC: MiMalloc = MiMalloc; 18 | 19 | lazy_static! { 20 | // include_str! doesn't seem to work in CI 21 | static ref CONTRACT_CLASS: ContractClass = ContractClass::from_path( 22 | "starknet_programs/first_contract.json", 23 | ).unwrap(); 24 | } 25 | 26 | fn main() { 27 | const RUNS: usize = 100; 28 | 29 | let block_context = BlockContext::default(); 30 | let state_reader = Arc::new(InMemoryStateReader::default()); 31 | 32 | let mut state = CachedState::new( 33 | state_reader, 34 | Arc::new(PermanentContractClassCache::default()), 35 | ); 36 | let call_data = vec![]; 37 | 38 | for n in 0..RUNS { 39 | let contract_address_salt = n.into(); 40 | 41 | let deploy = Deploy::new( 42 | contract_address_salt, 43 | CONTRACT_CLASS.clone(), 44 | call_data.clone(), 45 | *block_context.starknet_os_config().chain_id(), 46 | *TRANSACTION_VERSION, 47 | ) 48 | .unwrap(); 49 | 50 | state 51 | .set_contract_class( 52 | &deploy.contract_hash, 53 | &CompiledClass::Deprecated(Arc::new(CONTRACT_CLASS.clone())), 54 | ) 55 | .unwrap(); 56 | let tx = Transaction::Deploy(deploy); 57 | 58 | tx.execute( 59 | &mut state, 60 | &block_context, 61 | 0, 62 | #[cfg(feature = "cairo-native")] 63 | None, 64 | ) 65 | .unwrap(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/bin/deploy_invoke.rs: -------------------------------------------------------------------------------- 1 | use cairo_vm::Felt252; 2 | use lazy_static::lazy_static; 3 | 4 | use starknet_in_rust::{ 5 | definitions::{block_context::BlockContext, constants::TRANSACTION_VERSION}, 6 | services::api::contract_classes::{ 7 | compiled_class::CompiledClass, deprecated_contract_class::ContractClass, 8 | }, 9 | state::{ 10 | cached_state::CachedState, contract_class_cache::PermanentContractClassCache, 11 | in_memory_state_reader::InMemoryStateReader, state_api::State, 12 | }, 13 | transaction::Address, 14 | transaction::{Deploy, InvokeFunction, Transaction}, 15 | }; 16 | use std::{path::PathBuf, sync::Arc}; 17 | 18 | #[cfg(feature = "with_mimalloc")] 19 | use mimalloc::MiMalloc; 20 | 21 | #[cfg(feature = "with_mimalloc")] 22 | #[global_allocator] 23 | static ALLOC: MiMalloc = MiMalloc; 24 | 25 | lazy_static! { 26 | // include_str! doesn't seem to work in CI 27 | static ref CONTRACT_CLASS: ContractClass = ContractClass::from_path( 28 | "starknet_programs/first_contract.json", 29 | ).unwrap(); 30 | 31 | static ref CONTRACT_PATH: PathBuf = PathBuf::from("starknet_programs/first_contract.json"); 32 | 33 | static ref CONTRACT_CLASS_HASH: [u8; 32] = [5, 133, 114, 83, 104, 231, 159, 23, 87, 255, 235, 75, 170, 4, 84, 140, 49, 77, 101, 41, 147, 198, 201, 231, 38, 189, 215, 84, 231, 141, 140, 122]; 34 | 35 | static ref CONTRACT_ADDRESS: Address = Address(1.into()); 36 | 37 | static ref INCREASE_BALANCE_SELECTOR: Felt252 = Felt252::from_dec_str("1530486729947006463063166157847785599120665941190480211966374137237989315360").unwrap(); 38 | 39 | static ref GET_BALANCE_SELECTOR: Felt252 = Felt252::from_dec_str("1636223440827086009537493065587328807418413867743950350615962740049133672085").unwrap(); 40 | } 41 | 42 | fn main() { 43 | const RUNS: usize = 10000; 44 | 45 | let block_context = BlockContext::default(); 46 | let state_reader = Arc::new(InMemoryStateReader::default()); 47 | let mut state = CachedState::new( 48 | state_reader, 49 | Arc::new(PermanentContractClassCache::default()), 50 | ); 51 | 52 | let call_data = vec![]; 53 | let contract_address_salt = 1.into(); 54 | let chain_id = *block_context.starknet_os_config().chain_id(); 55 | 56 | let deploy = Deploy::new( 57 | contract_address_salt, 58 | CONTRACT_CLASS.clone(), 59 | call_data, 60 | *block_context.starknet_os_config().chain_id(), 61 | *TRANSACTION_VERSION, 62 | ) 63 | .unwrap(); 64 | 65 | let contract_address = deploy.contract_address.clone(); 66 | state 67 | .set_contract_class( 68 | &deploy.contract_hash, 69 | &CompiledClass::Deprecated(Arc::new(CONTRACT_CLASS.clone())), 70 | ) 71 | .unwrap(); 72 | let deploy_tx = Transaction::Deploy(deploy); 73 | 74 | let _tx_exec_info = deploy_tx 75 | .execute( 76 | &mut state, 77 | &block_context, 78 | 0, 79 | #[cfg(feature = "cairo-native")] 80 | None, 81 | ) 82 | .unwrap(); 83 | 84 | let signature = Vec::new(); 85 | 86 | // Statement **not** in blockifier. 87 | state 88 | .cache_mut() 89 | .nonce_initial_values_mut() 90 | .insert(contract_address.clone(), Felt252::ZERO); 91 | 92 | for i in 0..RUNS { 93 | let nonce_first = Felt252::from(i * 2); 94 | let nonce_second = Felt252::from((i * 2) + 1); 95 | 96 | let invoke_first = InvokeFunction::new( 97 | contract_address.clone(), 98 | *INCREASE_BALANCE_SELECTOR, 99 | Default::default(), 100 | *TRANSACTION_VERSION, 101 | vec![1000.into()], 102 | signature.clone(), 103 | chain_id, 104 | Some(nonce_first), 105 | ) 106 | .unwrap(); 107 | 108 | let tx = Transaction::InvokeFunction(invoke_first); 109 | tx.execute( 110 | &mut state, 111 | &block_context, 112 | 0, 113 | #[cfg(feature = "cairo-native")] 114 | None, 115 | ) 116 | .unwrap(); 117 | 118 | let invoke_second = InvokeFunction::new( 119 | contract_address.clone(), 120 | *GET_BALANCE_SELECTOR, 121 | Default::default(), 122 | *TRANSACTION_VERSION, 123 | vec![], 124 | signature.clone(), 125 | chain_id, 126 | Some(nonce_second), 127 | ) 128 | .unwrap(); 129 | 130 | let tx = Transaction::InvokeFunction(invoke_second); 131 | let tx_exec_info = tx 132 | .execute( 133 | &mut state, 134 | &block_context, 135 | 0, 136 | #[cfg(feature = "cairo-native")] 137 | None, 138 | ) 139 | .unwrap(); 140 | 141 | assert_eq!( 142 | tx_exec_info.call_info.unwrap().retdata, 143 | vec![((1000 * i) + 1000).into()] 144 | ); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/bin/invoke.rs: -------------------------------------------------------------------------------- 1 | use cairo_vm::Felt252; 2 | use lazy_static::lazy_static; 3 | 4 | use starknet_in_rust::{ 5 | definitions::{block_context::BlockContext, constants::TRANSACTION_VERSION}, 6 | services::api::contract_classes::{ 7 | compiled_class::CompiledClass, deprecated_contract_class::ContractClass, 8 | }, 9 | state::{ 10 | cached_state::CachedState, contract_class_cache::PermanentContractClassCache, 11 | in_memory_state_reader::InMemoryStateReader, 12 | }, 13 | transaction::{Address, ClassHash, InvokeFunction, Transaction}, 14 | }; 15 | use std::{path::PathBuf, sync::Arc}; 16 | 17 | #[cfg(feature = "with_mimalloc")] 18 | use mimalloc::MiMalloc; 19 | 20 | #[cfg(feature = "with_mimalloc")] 21 | #[global_allocator] 22 | static ALLOC: MiMalloc = MiMalloc; 23 | 24 | lazy_static! { 25 | // include_str! doesn't seem to work in CI 26 | static ref CONTRACT_CLASS: ContractClass = ContractClass::from_path( 27 | "starknet_programs/first_contract.json", 28 | ).unwrap(); 29 | 30 | static ref CONTRACT_PATH: PathBuf = PathBuf::from("starknet_programs/first_contract.json"); 31 | 32 | static ref CONTRACT_CLASS_HASH: ClassHash = ClassHash([1; 32]); 33 | 34 | static ref CONTRACT_ADDRESS: Address = Address(1.into()); 35 | 36 | static ref INCREASE_BALANCE_SELECTOR: Felt252 = Felt252::from_dec_str("1530486729947006463063166157847785599120665941190480211966374137237989315360").unwrap(); 37 | 38 | static ref GET_BALANCE_SELECTOR: Felt252 = Felt252::from_dec_str("1636223440827086009537493065587328807418413867743950350615962740049133672085").unwrap(); 39 | } 40 | 41 | fn main() { 42 | const RUNS: usize = 10000; 43 | 44 | let block_context = BlockContext::default(); 45 | 46 | let mut state = CachedState::new( 47 | { 48 | let mut state_reader = InMemoryStateReader::default(); 49 | state_reader 50 | .address_to_class_hash_mut() 51 | .insert(CONTRACT_ADDRESS.clone(), *CONTRACT_CLASS_HASH); 52 | 53 | state_reader 54 | .address_to_nonce_mut() 55 | .insert(CONTRACT_ADDRESS.clone(), Felt252::ZERO); 56 | state_reader.class_hash_to_compiled_class_mut().insert( 57 | *CONTRACT_CLASS_HASH, 58 | CompiledClass::Deprecated(Arc::new(CONTRACT_CLASS.clone())), 59 | ); 60 | 61 | state_reader 62 | .address_to_storage_mut() 63 | .insert((CONTRACT_ADDRESS.clone(), [0; 32]), Felt252::ZERO); 64 | Arc::new(state_reader) 65 | }, 66 | Arc::new(PermanentContractClassCache::default()), 67 | ); 68 | let chain_id = *block_context.starknet_os_config().chain_id(); 69 | let signature = Vec::new(); 70 | 71 | state 72 | .cache_mut() 73 | .nonce_initial_values_mut() 74 | .insert(CONTRACT_ADDRESS.clone(), Felt252::ZERO); 75 | 76 | for i in 0..RUNS { 77 | let invoke_first = InvokeFunction::new( 78 | CONTRACT_ADDRESS.clone(), 79 | *INCREASE_BALANCE_SELECTOR, 80 | Default::default(), 81 | *TRANSACTION_VERSION, 82 | vec![1000.into()], 83 | signature.clone(), 84 | chain_id, 85 | Some(Felt252::from(i * 2)), 86 | ) 87 | .unwrap(); 88 | 89 | let tx = Transaction::InvokeFunction(invoke_first); 90 | tx.execute( 91 | &mut state, 92 | &block_context, 93 | 0, 94 | #[cfg(feature = "cairo-native")] 95 | None, 96 | ) 97 | .unwrap(); 98 | 99 | let invoke_second = InvokeFunction::new( 100 | CONTRACT_ADDRESS.clone(), 101 | *GET_BALANCE_SELECTOR, 102 | Default::default(), 103 | *TRANSACTION_VERSION, 104 | vec![], 105 | signature.clone(), 106 | chain_id, 107 | Some(Felt252::from((i * 2) + 1)), 108 | ) 109 | .unwrap(); 110 | 111 | let tx = Transaction::InvokeFunction(invoke_second); 112 | let tx_exec_info = tx 113 | .execute( 114 | &mut state, 115 | &block_context, 116 | 0, 117 | #[cfg(feature = "cairo-native")] 118 | None, 119 | ) 120 | .unwrap(); 121 | 122 | assert_eq!( 123 | tx_exec_info.call_info.unwrap().retdata, 124 | vec![((1000 * i) + 1000).into()] 125 | ); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/core/block_hash/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | hash_utils::compute_hash_on_elements, syscalls::syscall_handler_errors::SyscallHandlerError, 3 | }; 4 | use crate::core::errors::hash_errors::HashError; 5 | use cairo_vm::Felt252; 6 | use starknet_crypto::{pedersen_hash, FieldElement}; 7 | use std::iter::zip; 8 | 9 | // -------------------------------------------------------------- 10 | // TODO: 11 | // * calculate_block_hash 12 | // * calculate_patricia_root 13 | // there are missing structures to implement this functions yet 14 | // ------------------------------------------------------------- 15 | 16 | pub fn calculate_tx_hashes_with_signatures( 17 | tx_hashes: Vec, 18 | tx_signatures: Vec>, 19 | ) -> Result, HashError> { 20 | zip(tx_hashes, tx_signatures) 21 | .map(|(hash, signature)| calculate_single_tx_hash_with_signature(hash, signature)) 22 | .collect::, _>>() 23 | } 24 | 25 | /// Hashes the signature with the given transaction hash, to get a hash that takes into account the 26 | /// entire transaction, as the original hash does not include the signature. 27 | 28 | pub fn calculate_single_tx_hash_with_signature( 29 | tx_hash: Felt252, 30 | tx_signature: Vec, 31 | ) -> Result { 32 | let signature_hash = compute_hash_on_elements(&tx_signature)?; 33 | let signature_str = signature_hash.to_str_radix(10); 34 | let tx_hash_str = tx_hash.to_str_radix(10); 35 | let hash = FieldElement::from_dec_str(&tx_hash_str) 36 | .map_err(|_| HashError::FailToComputeHash)?; 37 | let signature = FieldElement::from_dec_str(&signature_str) 38 | .map_err(|_| HashError::FailToComputeHash)?; 39 | let new_hash = pedersen_hash(&hash, &signature); 40 | Ok(Felt252::from_bytes_be(&new_hash.to_bytes_be())) 41 | } 42 | 43 | /// Calculates and returns the hash of an event, given its separate fields. 44 | /// I.e., H(from_address, H(keys), H(data)), where each hash chain computation begins 45 | /// with 0 as initialization and ends with its length appended. 46 | pub fn calculate_event_hash( 47 | from_address: Felt252, 48 | keys: Vec, 49 | data: Vec, 50 | ) -> Result { 51 | let key_hash = compute_hash_on_elements(&keys)?; 52 | let data_hash = compute_hash_on_elements(&data)?; 53 | compute_hash_on_elements(&[from_address, key_hash, data_hash]) 54 | } 55 | 56 | #[cfg(test)] 57 | mod tests { 58 | use super::*; 59 | use coverage_helper::test; 60 | 61 | #[test] 62 | fn calculate_event_hash_test() { 63 | let from_address = 1.into(); 64 | let keys = vec![300.into(), 301.into()]; 65 | let data = vec![302.into(), 303.into()]; 66 | 67 | assert!(calculate_event_hash(from_address, keys, data).is_ok()); 68 | } 69 | 70 | #[test] 71 | fn calculate_single_tx_hash_test() { 72 | let tx_hash = 21325412.into(); 73 | let signatures = vec![300.into(), 301.into()]; 74 | 75 | assert!(calculate_single_tx_hash_with_signature(tx_hash, signatures).is_ok()); 76 | } 77 | 78 | #[test] 79 | fn calculate_tx_hashes_with_signatures_test() { 80 | let tx_hash = vec![21325412.into(), 21322.into(), 212.into()]; 81 | let signatures = vec![ 82 | vec![300.into(), 301.into()], 83 | vec![30.into(), 32.into()], 84 | vec![500.into(), 400.into()], 85 | ]; 86 | 87 | assert!(calculate_tx_hashes_with_signatures(tx_hash, signatures).is_ok()); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/core/block_hash/starknet_block_hash.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | hash_utils::compute_hash_on_elements, syscalls::syscall_handler_errors::SyscallHandlerError, 3 | }; 4 | use crate::core::errors::hash_errors::HashError; 5 | use cairo_vm::Felt252; 6 | use starknet_crypto::{pedersen_hash, FieldElement}; 7 | use std::iter::zip; 8 | 9 | /// Hashes the signatures with the given transaction hashes, to get hashes that take into account the 10 | /// entire transactions, as the original hashes do not include the signatures. 11 | 12 | pub fn calculate_tx_hashes_with_signatures( 13 | tx_hashes: Vec, 14 | tx_signatures: Vec>, 15 | ) -> Result, HashError> { 16 | zip(tx_hashes, tx_signatures) 17 | .map(|(hash, signature)| calculate_single_tx_hash_with_signature(hash, signature)) 18 | .collect::, _>>() 19 | } 20 | 21 | /// Hashes the signature with the given transaction hash, to get a hash that takes into account the 22 | /// entire transaction, as the original hash does not include the signature. 23 | 24 | pub fn calculate_single_tx_hash_with_signature( 25 | tx_hash: Felt252, 26 | tx_signature: Vec, 27 | ) -> Result { 28 | let signature_hash = compute_hash_on_elements(&tx_signature)?; 29 | let signature_str = signature_hash.to_str_radix(10); 30 | let tx_hash_str = tx_hash.to_str_radix(10); 31 | let hash = FieldElement::from_dec_str(&tx_hash_str) 32 | .map_err(|_| HashError::FailToComputeHash)?; 33 | let signature = FieldElement::from_dec_str(&signature_str) 34 | .map_err(|_| HashError::FailToComputeHash)?; 35 | let new_hash = pedersen_hash(&hash, &signature); 36 | Ok(Felt252::from_bytes_be(&new_hash.to_bytes_be())) 37 | } 38 | 39 | /// Calculates and returns the hash of an event, given its separate fields. 40 | /// I.e., H(from_address, H(keys), H(data)), where each hash chain computation begins 41 | /// with 0 as initialization and ends with its length appended. 42 | pub fn calculate_event_hash( 43 | from_address: Felt252, 44 | keys: Vec, 45 | data: Vec, 46 | ) -> Result { 47 | let key_hash = compute_hash_on_elements(&keys)?; 48 | let data_hash = compute_hash_on_elements(&data)?; 49 | compute_hash_on_elements(&[from_address, key_hash, data_hash]) 50 | } 51 | 52 | #[cfg(test)] 53 | mod tests { 54 | use super::*; 55 | use coverage_helper::test; 56 | 57 | #[test] 58 | fn calculate_event_hash_test() { 59 | let from_address = 1.into(); 60 | let keys = vec![300.into(), 301.into()]; 61 | let data = vec![302.into(), 303.into()]; 62 | 63 | assert!(calculate_event_hash(from_address, keys, data).is_ok()); 64 | } 65 | 66 | #[test] 67 | fn calculate_single_tx_hash_test() { 68 | let tx_hash = 21325412.into(); 69 | let signatures = vec![300.into(), 301.into()]; 70 | 71 | assert!(calculate_single_tx_hash_with_signature(tx_hash, signatures).is_ok()); 72 | } 73 | 74 | #[test] 75 | fn calculate_tx_hashes_with_signatures_test() { 76 | let tx_hash = vec![21325412.into(), 21322.into(), 212.into()]; 77 | let signatures = vec![ 78 | vec![300.into(), 301.into()], 79 | vec![30.into(), 32.into()], 80 | vec![500.into(), 400.into()], 81 | ]; 82 | 83 | assert!(calculate_tx_hashes_with_signatures(tx_hash, signatures).is_ok()); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/core/contract_address/mod.rs: -------------------------------------------------------------------------------- 1 | mod casm_contract_address; 2 | mod deprecated_contract_address; 3 | mod sierra_contract_address; 4 | 5 | pub use casm_contract_address::compute_casm_class_hash; 6 | pub use deprecated_contract_address::compute_deprecated_class_hash; 7 | pub(crate) use deprecated_contract_address::compute_hinted_class_hash; 8 | pub use deprecated_contract_address::CairoProgramToHash; 9 | pub use sierra_contract_address::compute_sierra_class_hash; 10 | -------------------------------------------------------------------------------- /src/core/errors/contract_address_errors.rs: -------------------------------------------------------------------------------- 1 | use crate::core::errors::hash_errors::HashError; 2 | use cairo_vm::{ 3 | types::errors::program_errors::ProgramError, 4 | vm::errors::{ 5 | cairo_run_errors::CairoRunError, memory_errors::MemoryError, runner_errors::RunnerError, 6 | vm_errors::VirtualMachineError, 7 | }, 8 | }; 9 | use thiserror::Error; 10 | 11 | use crate::syscalls::syscall_handler_errors::SyscallHandlerError; 12 | 13 | #[derive(Debug, Error)] 14 | pub enum ContractAddressError { 15 | #[error(transparent)] 16 | Program(#[from] ProgramError), 17 | #[error("Missing identifier: {0}")] 18 | MissingIdentifier(String), 19 | #[error("None existing EntryPointType")] 20 | NoneExistingEntryPointType, 21 | #[error("Invalid offset: {0}")] 22 | InvalidOffset(usize), 23 | #[error("Api version can't be None")] 24 | NoneApiVersion, 25 | #[error(transparent)] 26 | Memory(#[from] MemoryError), 27 | #[error("Index out of range")] 28 | IndexOutOfRange, 29 | #[error("Missing abi in sierra contract class")] 30 | MissingAbi, 31 | #[error(transparent)] 32 | CairoRunner(#[from] RunnerError), 33 | #[error(transparent)] 34 | CairoRun(#[from] CairoRunError), 35 | #[error(transparent)] 36 | VirtualMachine(#[from] VirtualMachineError), 37 | #[error("Could not remove suffix from builtin")] 38 | BuiltinSuffix, 39 | #[error(transparent)] 40 | SyscallHandler(#[from] SyscallHandlerError), 41 | #[error("Failed to cast {0} into {1}")] 42 | Cast(String, String), 43 | #[error("MaybeRelocatable is not an Int variant")] 44 | NoneIntMaybeRelocatable, 45 | #[error("Invalid program JSON, message: {0}")] 46 | InvalidProgramJson(String), 47 | #[error("Couldn't compute hash: {0}")] 48 | HashError(HashError), 49 | } 50 | 51 | impl From for ContractAddressError { 52 | fn from(error: HashError) -> Self { 53 | ContractAddressError::HashError(error) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/core/errors/hash_errors.rs: -------------------------------------------------------------------------------- 1 | use thiserror::Error; 2 | 3 | #[derive(Debug, Error)] 4 | pub enum HashError { 5 | #[error("Failed to compute hash {0}")] 6 | FailedToComputeHash(String), 7 | } 8 | -------------------------------------------------------------------------------- /src/core/errors/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod contract_address_errors; 2 | pub mod hash_errors; 3 | pub mod state_errors; 4 | -------------------------------------------------------------------------------- /src/core/errors/state_errors.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | services::api::contract_class_errors::ContractClassError, 3 | state::state_cache::StorageEntry, 4 | transaction::{Address, ClassHash}, 5 | }; 6 | use starknet::core::types::FromByteArrayError; 7 | use thiserror::Error; 8 | 9 | #[derive(Debug, Error)] 10 | pub enum StateError { 11 | #[error("Missing key in StorageUpdate Map")] 12 | EmptyKeyInStorage, 13 | #[error("Try to create a CarriedState from a None parent")] 14 | ParentCarriedStateIsNone, 15 | #[error("Cache already initialized")] 16 | StateCacheAlreadyInitialized, 17 | #[error("No contract state assigned for contract address: {0:?}")] 18 | NoneContractState(Address), 19 | #[error("No class hash assigned for contract address: {0:?}")] 20 | NoneClassHash(Address), 21 | #[error("No nonce assigned for contract address: {0:?}")] 22 | NoneNonce(Address), 23 | #[error("No storage value assigned for entry: {0:?}")] 24 | NoneStorage(StorageEntry), 25 | #[error("No storage leaf assigned for key: {0:?}")] 26 | NoneStoragLeaf(ClassHash), 27 | #[error("Cannot deploy contract at address: {0:?}")] 28 | ContractAddressOutOfRangeAddress(Address), 29 | #[error("Requested contract address {} is unavailable for deployment", (.0).0)] 30 | ContractAddressUnavailable(Address), 31 | #[error(transparent)] 32 | ContractClass(#[from] ContractClassError), 33 | #[error("Constructor calldata is empty")] 34 | ConstructorCalldataEmpty, 35 | #[error("Error in ExecutionEntryPoint")] 36 | ExecutionEntryPoint, 37 | #[error("No compiled class found for compiled_class_hash {0:?}")] 38 | NoneCompiledClass(ClassHash), 39 | #[error("No compiled class hash found for class_hash {0:?}")] 40 | NoneCompiledHash(ClassHash), 41 | #[error("Missing casm class for hash {0:?}")] 42 | MissingCasmClass(ClassHash), 43 | #[error("Uninitializes class_hash")] 44 | UninitiaizedClassHash, 45 | #[error(transparent)] 46 | Io(#[from] std::io::Error), 47 | #[error("{0:?}")] 48 | CustomError(String), 49 | #[error(transparent)] 50 | ByteArray(#[from] FromByteArrayError), 51 | #[error("Failed to read contract class cache")] 52 | FailedToReadContractClassCache, 53 | } 54 | -------------------------------------------------------------------------------- /src/core/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod contract_address; 2 | pub mod errors; 3 | pub mod transaction_hash; 4 | -------------------------------------------------------------------------------- /src/definitions/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod block_context; 2 | pub mod constants; 3 | pub mod transaction_type; 4 | -------------------------------------------------------------------------------- /src/definitions/transaction_type.rs: -------------------------------------------------------------------------------- 1 | /// TransactionType is an enum that represents the type of transaction. 2 | /// 3 | /// It is used in the transaction header and in the transaction execution info. 4 | #[derive(Debug, PartialEq, Copy, Clone, Eq, Hash)] 5 | pub enum TransactionType { 6 | Declare, 7 | Deploy, 8 | DeployAccount, 9 | InitializeBlockInfo, 10 | InvokeFunction, 11 | L1Handler, 12 | } 13 | 14 | impl From for u64 { 15 | /// Converts a [TransactionType] into a [u64]. 16 | fn from(tx_type: TransactionType) -> Self { 17 | match tx_type { 18 | TransactionType::Declare => 0, 19 | TransactionType::Deploy => 1, 20 | TransactionType::DeployAccount => 2, 21 | TransactionType::InitializeBlockInfo => 3, 22 | TransactionType::InvokeFunction => 4, 23 | TransactionType::L1Handler => 5, 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/parser_errors.rs: -------------------------------------------------------------------------------- 1 | use crate::services::api::contract_classes::deprecated_contract_class::EntryPointType; 2 | use crate::{ 3 | core::errors::{ 4 | contract_address_errors::ContractAddressError, hash_errors::HashError, 5 | state_errors::StateError, 6 | }, 7 | syscalls::syscall_handler_errors::SyscallHandlerError, 8 | transaction::error::TransactionError, 9 | }; 10 | use thiserror::Error; 11 | 12 | #[derive(Debug, Error)] 13 | pub enum ParserError { 14 | #[error(transparent)] 15 | Io(#[from] std::io::Error), 16 | #[error(transparent)] 17 | ContractAddress(#[from] ContractAddressError), 18 | #[error(transparent)] 19 | Syscall(#[from] SyscallHandlerError), 20 | #[error(transparent)] 21 | Hashes(#[from] HashError), 22 | #[error("Failed to convert {0} to Felt")] 23 | ParseFelt(String), 24 | #[error("Failed to get entry point for function `{0}`")] 25 | FunctionEntryPoint(String), 26 | #[error("Failed to get entry point selector by type`{0:?}`")] 27 | EntryPointType(EntryPointType), 28 | #[error("Failed to get entry point at array position `{0}`")] 29 | EntryPointIndex(usize), 30 | #[error(transparent)] 31 | State(#[from] StateError), 32 | #[error(transparent)] 33 | Transaction(#[from] TransactionError), 34 | } 35 | -------------------------------------------------------------------------------- /src/serde_structs/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::services::api::contract_classes::deprecated_contract_class::EntryPointType; 2 | use serde::Deserialize; 3 | use serde_json::Value; 4 | use std::{collections::HashMap, fs::File, path::PathBuf}; 5 | 6 | #[allow(dead_code)] 7 | #[derive(Deserialize, Debug)] 8 | struct Signature { 9 | inputs: Value, 10 | name: String, 11 | outputs: Value, 12 | #[serde(default, rename = "stateMutability")] 13 | state_mutability: Option, 14 | #[serde(rename = "type")] 15 | type_name: String, 16 | } 17 | 18 | // We should should consider reading all the information from the abi in the future. Right now we are not considering: 19 | // - type: "event" 20 | // - type: "struct" 21 | pub fn read_abi(abi_name: &PathBuf) -> HashMap { 22 | let abi: Vec = serde_json::from_reader(&File::open(abi_name).unwrap()).unwrap(); 23 | let mut func_type_counter: HashMap = HashMap::new(); 24 | let mut result_hash_map: HashMap = HashMap::new(); 25 | 26 | for function in abi { 27 | let function_address = match func_type_counter.get(&function.type_name) { 28 | Some(number) => number + 1, 29 | None => 0, 30 | }; 31 | 32 | let entry_point_type = match &function.type_name { 33 | type_name if type_name == "function" => EntryPointType::External, 34 | type_name if type_name == "constructor" => EntryPointType::Constructor, 35 | _ => EntryPointType::L1Handler, 36 | }; 37 | 38 | func_type_counter.insert(function.type_name, function_address); 39 | result_hash_map.insert(function.name, (function_address, entry_point_type)); 40 | } 41 | 42 | result_hash_map 43 | } 44 | 45 | #[test] 46 | fn test_read_abi_simple_contract() { 47 | let path_a = PathBuf::from(r"starknet_programs/fibonacci_abi.json"); 48 | // using the function to read an abi 49 | let result = read_abi(&path_a); 50 | 51 | // this is the expected result of the function above 52 | let expected_result: HashMap = 53 | HashMap::from([(String::from("fib"), (0_usize, EntryPointType::External))]); 54 | 55 | // final check 56 | assert_eq!(result, expected_result) 57 | } 58 | 59 | #[test] 60 | fn test_read_abi_complex_contract() { 61 | let path_a = PathBuf::from(r"starknet_programs/constructor_abi.json"); 62 | 63 | let result = read_abi(&path_a); 64 | 65 | // this is the expected result of the function above 66 | 67 | let expected_result: HashMap = HashMap::from([ 68 | ( 69 | String::from("constructor"), 70 | (0_usize, EntryPointType::Constructor), 71 | ), 72 | ( 73 | String::from("get_owner"), 74 | (0_usize, EntryPointType::External), 75 | ), 76 | ]); 77 | 78 | // final check 79 | assert_eq!(result, expected_result) 80 | } 81 | 82 | #[test] 83 | fn test_read_abi_with_l1_handler_and_multiple_functions() { 84 | let path_a = PathBuf::from(r"starknet_programs/l1l2_abi.json"); 85 | 86 | let result = read_abi(&path_a); 87 | 88 | // this is the expected result of the function above 89 | 90 | let expected_result: HashMap = HashMap::from([ 91 | ( 92 | String::from("increase_balance"), 93 | (1_usize, EntryPointType::External), 94 | ), 95 | ( 96 | String::from("withdraw"), 97 | (2_usize, EntryPointType::External), 98 | ), 99 | ( 100 | String::from("get_balance"), 101 | (0_usize, EntryPointType::External), 102 | ), 103 | ( 104 | String::from("deposit"), 105 | (0_usize, EntryPointType::L1Handler), 106 | ), 107 | ]); 108 | 109 | // final check 110 | assert_eq!(result, expected_result) 111 | } 112 | -------------------------------------------------------------------------------- /src/services/api/contract_class_errors.rs: -------------------------------------------------------------------------------- 1 | use crate::services::api::contract_classes::deprecated_contract_class::ContractEntryPoint; 2 | use thiserror::Error; 3 | 4 | #[derive(Debug, PartialEq, Eq, Error)] 5 | pub enum ContractClassError { 6 | #[error("Given builtins are not in appropiate order")] 7 | DisorderedBuiltins, 8 | #[error("Entry point type not found")] 9 | NoneEntryPointType, 10 | #[error("Entry points must be unique and sorted. Found: {0:?}")] 11 | EntrypointError(Vec), 12 | #[error("Not a casm contract class")] 13 | NotACasmContractClass, 14 | #[error("Not a deprecated contract class")] 15 | NotADeprecatedContractClass, 16 | #[error("Parse error")] 17 | ParseError, 18 | #[error("Program error: {0}")] 19 | ProgramError(String), 20 | } 21 | -------------------------------------------------------------------------------- /src/services/api/contract_classes/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod compiled_class; 2 | pub mod deprecated_contract_class; 3 | -------------------------------------------------------------------------------- /src/services/api/messages.rs: -------------------------------------------------------------------------------- 1 | use cairo_vm::Felt252; 2 | use num_traits::ToPrimitive; 3 | use sha3::{Digest, Keccak256}; 4 | 5 | use crate::transaction::Address; 6 | 7 | /// A StarkNet Message from L2 to L1. 8 | #[derive(Debug, Clone)] 9 | pub struct StarknetMessageToL1 { 10 | from_address: Address, 11 | to_address: Address, 12 | payload: Vec, 13 | } 14 | 15 | impl StarknetMessageToL1 { 16 | pub fn new(from_address: Address, to_address: Address, payload: Vec) -> Self { 17 | StarknetMessageToL1 { 18 | from_address, 19 | to_address, 20 | payload, 21 | } 22 | } 23 | 24 | pub fn encode(&self) -> Vec { 25 | let mut encoding = Vec::with_capacity(self.payload.len() + 3); 26 | encoding.push(self.from_address.0); 27 | encoding.push(self.to_address.0); 28 | encoding.push(self.payload.len().into()); 29 | encoding.extend_from_slice(&self.payload); 30 | 31 | encoding 32 | } 33 | 34 | pub fn get_hash(&self) -> Vec { 35 | let data = self 36 | .encode() 37 | .iter() 38 | .map(|elem| elem.to_usize().unwrap() as u8) 39 | .collect::>(); 40 | let mut hasher = Keccak256::new(); 41 | hasher.update(data); 42 | let finalized_hash = hasher.finalize(); 43 | finalized_hash.as_slice().to_vec() 44 | } 45 | } 46 | 47 | #[test] 48 | fn create_starknet_message_to_l1() { 49 | let from_address = Address(42.into()); 50 | let to_address = Address(1729.into()); 51 | let payload: Vec = vec![1.into(), 2.into(), 3.into(), 4.into()]; 52 | let message = StarknetMessageToL1::new(from_address, to_address, payload); 53 | 54 | assert_eq!(message.from_address, Address(42.into())); 55 | assert_eq!(message.to_address, Address(1729.into())); 56 | assert_eq!( 57 | message.payload, 58 | vec![1.into(), 2.into(), 3.into(), 4.into()] 59 | ) 60 | } 61 | 62 | #[test] 63 | fn encode_starknet_message_to_l1() { 64 | let message = StarknetMessageToL1::new( 65 | Address(42.into()), 66 | Address(1729.into()), 67 | vec![1.into(), 2.into(), 3.into(), 4.into()], 68 | ); 69 | 70 | let expected_output = vec![ 71 | 42.into(), 72 | 1729.into(), 73 | 4.into(), 74 | 1.into(), 75 | 2.into(), 76 | 3.into(), 77 | 4.into(), 78 | ]; 79 | 80 | assert_eq!(message.encode(), expected_output); 81 | } 82 | 83 | #[test] 84 | fn get_hash_for_starknet_message_to_l1() { 85 | let message = StarknetMessageToL1::new( 86 | Address(42.into()), 87 | Address(1729.into()), 88 | vec![1.into(), 2.into(), 3.into(), 4.into()], 89 | ); 90 | 91 | assert_eq!( 92 | message.get_hash(), 93 | Vec::from([ 94 | 35, 146, 105, 229, 123, 197, 150, 164, 71, 161, 100, 157, 18, 54, 233, 219, 32, 150, 95 | 155, 238, 74, 8, 254, 114, 153, 144, 74, 32, 110, 104, 86, 42 96 | ]) 97 | ) 98 | } 99 | -------------------------------------------------------------------------------- /src/services/api/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod contract_class_errors; 2 | pub mod contract_classes; 3 | pub mod messages; 4 | -------------------------------------------------------------------------------- /src/services/eth_definitions/eth_gas_constants.rs: -------------------------------------------------------------------------------- 1 | // Ethereum gas usage constants; for more details, see 2 | // page 27 in https://ethereum.github.io/yellowpaper/paper.pdf. 3 | 4 | // Calldata. 5 | pub(crate) const GAS_PER_MEMORY_ZERO_BYTE: usize = 4; 6 | pub(crate) const GAS_PER_MEMORY_BYTE: usize = 16; 7 | pub(crate) const WORD_WIDTH: usize = 32; 8 | pub(crate) const GAS_PER_MEMORY_WORD: usize = GAS_PER_MEMORY_BYTE * WORD_WIDTH; 9 | 10 | pub(crate) const GAS_PER_LOG_DATA_BYTE: usize = 8; 11 | pub(crate) const GAS_PER_LOG_TOPIC: usize = 375; 12 | pub(crate) const GAS_PER_LOG: usize = 375; 13 | pub(crate) const GAS_PER_LOG_DATA_WORD: usize = GAS_PER_LOG_DATA_BYTE * WORD_WIDTH; 14 | pub(crate) const GAS_PER_ZERO_TO_NONZERO_STORAGE_SET: usize = 20000; 15 | pub(crate) const GAS_PER_COLD_STORAGE_ACCESS: usize = 2100; 16 | pub(crate) const GAS_PER_NONZERO_TO_INT_STORAGE_SET: usize = 2900; 17 | pub(crate) const GAS_PER_COUNTER_DECREASE: usize = 18 | GAS_PER_COLD_STORAGE_ACCESS + GAS_PER_NONZERO_TO_INT_STORAGE_SET; 19 | pub(crate) const SHARP_ADDITIONAL_GAS_PER_MEMORY_WORD: usize = 100; //This value is not accurate. 20 | pub(crate) const SHARP_GAS_PER_MEMORY_WORD: usize = 21 | GAS_PER_MEMORY_WORD + SHARP_ADDITIONAL_GAS_PER_MEMORY_WORD; 22 | 23 | // Constants used to calculate discounts in onchain data cost calculation 24 | 25 | // 10% discount for data availability. 26 | pub(crate) const DISCOUNT_PER_DA_WORD: usize = (SHARP_GAS_PER_MEMORY_WORD * 10) / 100; 27 | pub(crate) const SHARP_GAS_PER_DA_WORD: usize = SHARP_GAS_PER_MEMORY_WORD - DISCOUNT_PER_DA_WORD; 28 | 29 | // For each modified contract, the expected non-zeros bytes in the second word are: 30 | // 1 bytes for class hash flag; 2 for number of storage updates (up to 64K); 31 | // 3 for nonce update (up to 16M). 32 | const MODIFIED_CONTRACT_COST: usize = 33 | 6 * GAS_PER_MEMORY_BYTE + (WORD_WIDTH - 6) * GAS_PER_MEMORY_ZERO_BYTE; 34 | pub(crate) const MODIFIED_CONTRACT_DISCOUNT: usize = GAS_PER_MEMORY_WORD - MODIFIED_CONTRACT_COST; 35 | 36 | // Up to balance of 8*(10**10) ETH. 37 | pub(crate) const FEE_BALANCE_VALUE_COST: usize = 38 | 12 * GAS_PER_MEMORY_BYTE + (WORD_WIDTH - 12) * GAS_PER_MEMORY_ZERO_BYTE; 39 | -------------------------------------------------------------------------------- /src/services/eth_definitions/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod eth_gas_constants; 2 | -------------------------------------------------------------------------------- /src/services/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod api; 2 | pub mod eth_definitions; 3 | -------------------------------------------------------------------------------- /src/state/contract_class_cache.rs: -------------------------------------------------------------------------------- 1 | //! # Contract cache system 2 | //! 3 | //! The contract caches allow the application to keep some contracts within itself, providing them 4 | //! efficiently when they are needed. 5 | //! 6 | //! The trait `ContractClassCache` provides methods for retrieving and inserting elements into the 7 | //! cache. It also contains a method to extend the shared cache from an iterator so that it can be 8 | //! used with the private caches. 9 | 10 | use crate::{ 11 | services::api::contract_classes::compiled_class::CompiledClass, transaction::ClassHash, 12 | }; 13 | use std::{collections::HashMap, sync::RwLock}; 14 | 15 | /// The contract class cache trait, which must be implemented by all caches. 16 | pub trait ContractClassCache { 17 | /// Provides the stored contract class associated with a specific class hash, or `None` if not 18 | /// present. 19 | fn get_contract_class(&self, class_hash: ClassHash) -> Option; 20 | /// Inserts or replaces a contract class associated with a specific class hash. 21 | fn set_contract_class(&self, class_hash: ClassHash, compiled_class: CompiledClass); 22 | } 23 | 24 | /// A contract class cache which stores nothing. In other words, using this as a cache means there's 25 | /// effectively no cache. 26 | #[derive(Clone, Copy, Debug, Default, Hash)] 27 | pub struct NullContractClassCache; 28 | 29 | impl ContractClassCache for NullContractClassCache { 30 | fn get_contract_class(&self, _class_hash: ClassHash) -> Option { 31 | None 32 | } 33 | 34 | fn set_contract_class(&self, _class_hash: ClassHash, _compiled_class: CompiledClass) { 35 | // Nothing needs to be done here. 36 | } 37 | } 38 | 39 | /// A contract class cache which stores everything. This cache is useful for testing but will 40 | /// probably end up taking all the memory available if the application is long running. 41 | #[derive(Debug, Default)] 42 | pub struct PermanentContractClassCache { 43 | storage: RwLock>, 44 | } 45 | 46 | impl PermanentContractClassCache { 47 | pub fn extend(&self, other: I) 48 | where 49 | I: IntoIterator, 50 | { 51 | self.storage.write().unwrap().extend(other); 52 | } 53 | } 54 | 55 | impl ContractClassCache for PermanentContractClassCache { 56 | fn get_contract_class(&self, class_hash: ClassHash) -> Option { 57 | self.storage.read().unwrap().get(&class_hash).cloned() 58 | } 59 | 60 | fn set_contract_class(&self, class_hash: ClassHash, compiled_class: CompiledClass) { 61 | self.storage 62 | .write() 63 | .unwrap() 64 | .insert(class_hash, compiled_class); 65 | } 66 | } 67 | 68 | impl Clone for PermanentContractClassCache { 69 | fn clone(&self) -> Self { 70 | Self { 71 | storage: RwLock::new(self.storage.read().unwrap().clone()), 72 | } 73 | } 74 | } 75 | 76 | impl IntoIterator for PermanentContractClassCache { 77 | type Item = (ClassHash, CompiledClass); 78 | type IntoIter = as IntoIterator>::IntoIter; 79 | 80 | fn into_iter(self) -> Self::IntoIter { 81 | self.storage.into_inner().unwrap().into_iter() 82 | } 83 | } 84 | 85 | impl IntoIterator for &PermanentContractClassCache { 86 | type Item = (ClassHash, CompiledClass); 87 | type IntoIter = as IntoIterator>::IntoIter; 88 | 89 | fn into_iter(self) -> Self::IntoIter { 90 | self.storage.read().unwrap().clone().into_iter() 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/state/contract_storage_state.rs: -------------------------------------------------------------------------------- 1 | use super::{ 2 | cached_state::CachedState, 3 | contract_class_cache::ContractClassCache, 4 | state_api::{State, StateReader}, 5 | }; 6 | use crate::{ 7 | core::errors::state_errors::StateError, 8 | transaction::{Address, ClassHash}, 9 | }; 10 | use cairo_vm::Felt252; 11 | use std::collections::HashSet; 12 | 13 | #[derive(Debug)] 14 | pub(crate) struct ContractStorageState<'a, S: StateReader, C: ContractClassCache> { 15 | pub(crate) state: &'a mut CachedState, 16 | pub(crate) contract_address: Address, 17 | /// Maintain all read request values in chronological order 18 | pub(crate) read_values: Vec, 19 | pub(crate) accessed_keys: HashSet, 20 | } 21 | 22 | impl<'a, S: StateReader, C: ContractClassCache> ContractStorageState<'a, S, C> { 23 | pub(crate) fn new(state: &'a mut CachedState, contract_address: Address) -> Self { 24 | Self { 25 | state, 26 | contract_address, 27 | read_values: Vec::new(), 28 | accessed_keys: HashSet::new(), 29 | } 30 | } 31 | 32 | /// Read a value from contract storage given an address. 33 | pub(crate) fn read(&mut self, address: Address) -> Result { 34 | self.accessed_keys.insert(ClassHash::from(address.0)); 35 | let value = self 36 | .state 37 | .get_storage_at(&(self.contract_address.clone(), (address).0.to_bytes_be()))?; 38 | 39 | self.read_values.push(value); 40 | Ok(value) 41 | } 42 | 43 | /// Write a value to contract storage at a given address. 44 | pub(crate) fn write(&mut self, address: Address, value: Felt252) { 45 | self.accessed_keys.insert(ClassHash::from(address.0)); 46 | self.state.set_storage_at( 47 | &(self.contract_address.clone(), (address).0.to_bytes_be()), 48 | value, 49 | ); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/state/state_api.rs: -------------------------------------------------------------------------------- 1 | use super::state_cache::StorageEntry; 2 | use crate::{ 3 | core::errors::state_errors::StateError, 4 | definitions::block_context::{BlockContext, FeeType}, 5 | services::api::contract_classes::compiled_class::CompiledClass, 6 | state::StateDiff, 7 | transaction::{Address, ClassHash, CompiledClassHash}, 8 | utils::get_erc20_balance_var_addresses, 9 | }; 10 | use cairo_lang_utils::bigint::BigUintAsHex; 11 | use cairo_vm::Felt252; 12 | 13 | pub trait StateReader { 14 | /// Returns the contract class of the given class hash or compiled class hash. 15 | fn get_contract_class(&self, class_hash: &ClassHash) -> Result; 16 | /// Returns the class hash of the contract class at the given address. 17 | /// Returns zero by default if the value is not present 18 | fn get_class_hash_at(&self, contract_address: &Address) -> Result; 19 | /// Returns the nonce of the given contract instance. 20 | fn get_nonce_at(&self, contract_address: &Address) -> Result; 21 | /// Returns the storage value under the given key in the given contract instance. 22 | /// Returns zero by default if the value is not present 23 | fn get_storage_at(&self, storage_entry: &StorageEntry) -> Result; 24 | /// Return the class hash of the given casm contract class 25 | fn get_compiled_class_hash( 26 | &self, 27 | class_hash: &ClassHash, 28 | ) -> Result; 29 | } 30 | 31 | #[derive(Debug, Clone, Eq, PartialEq)] 32 | pub struct StateChangesCount { 33 | pub n_storage_updates: usize, 34 | pub n_class_hash_updates: usize, 35 | pub n_compiled_class_hash_updates: usize, 36 | pub n_modified_contracts: usize, 37 | } 38 | 39 | pub trait State { 40 | fn set_contract_class( 41 | &mut self, 42 | class_hash: &ClassHash, 43 | contract_class: &CompiledClass, 44 | ) -> Result<(), StateError>; 45 | 46 | fn deploy_contract( 47 | &mut self, 48 | contract_address: Address, 49 | class_hash: ClassHash, 50 | ) -> Result<(), StateError>; 51 | 52 | fn increment_nonce(&mut self, contract_address: &Address) -> Result<(), StateError>; 53 | 54 | fn set_storage_at(&mut self, storage_entry: &StorageEntry, value: Felt252); 55 | 56 | fn set_class_hash_at( 57 | &mut self, 58 | contract_address: Address, 59 | class_hash: ClassHash, 60 | ) -> Result<(), StateError>; 61 | 62 | fn set_compiled_class_hash( 63 | &mut self, 64 | class_hash: &Felt252, 65 | compiled_class_hash: &Felt252, 66 | ) -> Result<(), StateError>; 67 | 68 | fn apply_state_update(&mut self, sate_updates: &StateDiff) -> Result<(), StateError>; 69 | 70 | /// Counts the amount of state changes 71 | fn count_actual_state_changes( 72 | &mut self, 73 | fee_token_and_sender_address: Option<(&Address, &Address)>, 74 | ) -> Result; 75 | 76 | /// Returns the class hash of the contract class at the given address. 77 | /// Returns zero by default if the value is not present 78 | fn get_class_hash_at(&mut self, contract_address: &Address) -> Result; 79 | 80 | /// Default: 0 for an uninitialized contract address. 81 | fn get_nonce_at(&mut self, contract_address: &Address) -> Result; 82 | 83 | /// Returns storage data for a given storage entry. 84 | /// Returns zero as default value if missing 85 | fn get_storage_at(&mut self, storage_entry: &StorageEntry) -> Result; 86 | 87 | fn get_compiled_class_hash(&mut self, class_hash: &ClassHash) -> Result; 88 | 89 | fn get_contract_class(&mut self, class_hash: &ClassHash) -> Result; 90 | 91 | fn get_sierra_program( 92 | &mut self, 93 | class_hash: &ClassHash, 94 | ) -> Result, StateError>; 95 | 96 | /// Returns the storage value representing the balance (in fee token) at the given address as a (low, high) pair 97 | fn get_fee_token_balance( 98 | &mut self, 99 | block_context: &BlockContext, 100 | contract_address: &Address, 101 | fee_type: &FeeType, 102 | ) -> Result<(Felt252, Felt252), StateError> { 103 | let (low_key, high_key) = get_erc20_balance_var_addresses(contract_address)?; 104 | let low = self.get_storage_at(&( 105 | block_context 106 | .get_fee_token_address_by_fee_type(fee_type) 107 | .clone(), 108 | low_key, 109 | ))?; 110 | let high = self.get_storage_at(&( 111 | block_context 112 | .get_fee_token_address_by_fee_type(fee_type) 113 | .clone(), 114 | high_key, 115 | ))?; 116 | 117 | Ok((low, high)) 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/syscalls/hint_code.rs: -------------------------------------------------------------------------------- 1 | // ************************* 2 | // Syscall hints 3 | // ************************* 4 | 5 | pub(crate) const DEPLOY: &str = 6 | "syscall_handler.deploy(segments=segments, syscall_ptr=ids.syscall_ptr)"; 7 | 8 | pub(crate) const EMIT_EVENT_CODE: &str = 9 | "syscall_handler.emit_event(segments=segments, syscall_ptr=ids.syscall_ptr)"; 10 | 11 | pub(crate) const GET_SEQUENCER_ADDRESS: &str = 12 | "syscall_handler.get_sequencer_address(segments=segments, syscall_ptr=ids.syscall_ptr)"; 13 | 14 | pub(crate) const STORAGE_WRITE: &str = 15 | "syscall_handler.storage_write(segments=segments, syscall_ptr=ids.syscall_ptr)"; 16 | 17 | pub(crate) const STORAGE_READ: &str = 18 | "syscall_handler.storage_read(segments=segments, syscall_ptr=ids.syscall_ptr)"; 19 | 20 | pub(crate) const SEND_MESSAGE_TO_L1: &str = 21 | "syscall_handler.send_message_to_l1(segments=segments, syscall_ptr=ids.syscall_ptr)"; 22 | 23 | pub(crate) const LIBRARY_CALL_L1_HANDLER: &str = 24 | "syscall_handler.library_call_l1_handler(segments=segments, syscall_ptr=ids.syscall_ptr)"; 25 | 26 | pub(crate) const LIBRARY_CALL: &str = 27 | "syscall_handler.library_call(segments=segments, syscall_ptr=ids.syscall_ptr)"; 28 | 29 | pub(crate) const CALL_CONTRACT: &str = 30 | "syscall_handler.call_contract(segments=segments, syscall_ptr=ids.syscall_ptr)"; 31 | 32 | pub(crate) const GET_TX_SIGNATURE: &str = 33 | "syscall_handler.get_tx_signature(segments=segments, syscall_ptr=ids.syscall_ptr)"; 34 | 35 | pub(crate) const GET_TX_INFO: &str = 36 | "syscall_handler.get_tx_info(segments=segments, syscall_ptr=ids.syscall_ptr)"; 37 | 38 | pub(crate) const GET_CONTRACT_ADDRESS: &str = 39 | "syscall_handler.get_contract_address(segments=segments, syscall_ptr=ids.syscall_ptr)"; 40 | 41 | pub(crate) const GET_CALLER_ADDRESS: &str = 42 | "syscall_handler.get_caller_address(segments=segments, syscall_ptr=ids.syscall_ptr)"; 43 | 44 | pub(crate) const GET_BLOCK_TIMESTAMP: &str = 45 | "syscall_handler.get_block_timestamp(segments=segments, syscall_ptr=ids.syscall_ptr)"; 46 | 47 | pub(crate) const GET_BLOCK_NUMBER: &str = 48 | "syscall_handler.get_block_number(segments=segments, syscall_ptr=ids.syscall_ptr)"; 49 | 50 | pub(crate) const DELEGATE_CALL: &str = 51 | "syscall_handler.delegate_call(segments=segments, syscall_ptr=ids.syscall_ptr)"; 52 | 53 | pub(crate) const DELEGATE_L1_HANDLER: &str = 54 | "syscall_handler.delegate_l1_handler(segments=segments, syscall_ptr=ids.syscall_ptr)"; 55 | 56 | pub(crate) const REPLACE_CLASS: &str = 57 | "syscall_handler.replace_class(segments=segments, syscall_ptr=ids.syscall_ptr)"; 58 | 59 | // ************************* 60 | // Normal hints 61 | // ************************* 62 | 63 | pub(crate) const ADDR_BOUND_PRIME: &str = 64 | "# Verify the assumptions on the relationship between 2**250, ADDR_BOUND and PRIME.\nADDR_BOUND = ids.ADDR_BOUND % PRIME\nassert (2**250 < ADDR_BOUND <= 2**251) and (2 * 2**250 < PRIME) and (\n ADDR_BOUND * 2 > PRIME), \\\n 'normalize_address() cannot be used with the current constants.'\nids.is_small = 1 if ids.addr < ADDR_BOUND else 0"; 65 | pub(crate) const ADDR_IS_250: &str = "ids.is_250 = 1 if ids.addr < 2**250 else 0"; 66 | -------------------------------------------------------------------------------- /src/syscalls/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod business_logic_syscall_handler; 2 | pub mod deprecated_business_logic_syscall_handler; 3 | pub mod deprecated_syscall_handler; 4 | pub mod deprecated_syscall_request; 5 | pub mod deprecated_syscall_response; 6 | pub mod hint_code; 7 | #[cfg(feature = "cairo-native")] 8 | pub mod native_syscall_handler; 9 | pub mod other_syscalls; 10 | pub mod syscall_handler; 11 | pub mod syscall_handler_errors; 12 | pub mod syscall_info; 13 | pub mod syscall_request; 14 | pub mod syscall_response; 15 | -------------------------------------------------------------------------------- /src/syscalls/other_syscalls.rs: -------------------------------------------------------------------------------- 1 | use crate::syscalls::syscall_handler_errors::SyscallHandlerError; 2 | use cairo_vm::Felt252; 3 | use cairo_vm::{ 4 | hint_processor::builtin_hint_processor::{ 5 | builtin_hint_processor_definition::HintProcessorData, 6 | hint_utils::{get_integer_from_var_name, insert_value_from_var_name}, 7 | }, 8 | vm::{errors::hint_errors::HintError, vm_core::VirtualMachine}, 9 | }; 10 | 11 | use std::collections::HashMap; 12 | 13 | pub fn addr_bound_prime( 14 | vm: &mut VirtualMachine, 15 | hint_data: &HintProcessorData, 16 | constants: &HashMap, 17 | ) -> Result<(), SyscallHandlerError> { 18 | let addr_bound = constants 19 | .get("starkware.starknet.common.storage.ADDR_BOUND") 20 | .ok_or(HintError::MissingConstant( 21 | "starkware.starknet.common.storage.ADDR_BOUND".into(), 22 | ))?; 23 | 24 | let lower_bound = Felt252::TWO.pow(250u32); 25 | let upper_bound = Felt252::TWO.pow(251u32); 26 | if !(&lower_bound < addr_bound && addr_bound <= &upper_bound) { 27 | return Err(HintError::AssertionFailed( 28 | "normalize_address() cannot be used with the current constants." 29 | .to_string() 30 | .into_boxed_str(), 31 | ) 32 | .into()); 33 | } 34 | 35 | let addr = get_integer_from_var_name("addr", vm, &hint_data.ids_data, &hint_data.ap_tracking)?; 36 | let is_small = if addr.as_ref() < addr_bound { 37 | Felt252::ONE 38 | } else { 39 | Felt252::ZERO 40 | }; 41 | 42 | insert_value_from_var_name( 43 | "is_small", 44 | is_small, 45 | vm, 46 | &hint_data.ids_data, 47 | &hint_data.ap_tracking, 48 | )?; 49 | 50 | Ok(()) 51 | } 52 | 53 | pub fn addr_is_250( 54 | vm: &mut VirtualMachine, 55 | hint_data: &HintProcessorData, 56 | ) -> Result<(), SyscallHandlerError> { 57 | let addr = get_integer_from_var_name("addr", vm, &hint_data.ids_data, &hint_data.ap_tracking)?; 58 | let is_250 = if addr.as_ref().bits() <= 250 { 59 | Felt252::ONE 60 | } else { 61 | Felt252::ZERO 62 | }; 63 | 64 | insert_value_from_var_name( 65 | "is_250", 66 | is_250, 67 | vm, 68 | &hint_data.ids_data, 69 | &hint_data.ap_tracking, 70 | )?; 71 | 72 | Ok(()) 73 | } 74 | -------------------------------------------------------------------------------- /src/syscalls/syscall_handler_errors.rs: -------------------------------------------------------------------------------- 1 | use crate::core::errors::hash_errors::HashError; 2 | use crate::core::errors::state_errors::StateError; 3 | use cairo_vm::Felt252; 4 | use cairo_vm::{ 5 | types::errors::math_errors::MathError, 6 | vm::errors::{ 7 | hint_errors::HintError, memory_errors::MemoryError, vm_errors::VirtualMachineError, 8 | }, 9 | }; 10 | use thiserror::Error; 11 | 12 | #[derive(Debug, Error)] 13 | pub enum SyscallHandlerError { 14 | #[error("Unknown syscall: {0}")] 15 | UnknownSyscall(String), 16 | #[error("The selector '{0}' is not in the syscall handler's selector to syscall map")] 17 | SelectorNotInHandlerMap(String), 18 | #[error("The selector '{0}' does not have an associated cost")] 19 | SelectorDoesNotHaveAssociatedGas(String), 20 | #[error("Couldn't execute syscall: {0}")] 21 | ExecutionError(String), 22 | #[error("Couldn't convert from {0} to {1}")] 23 | Conversion(String, String), 24 | #[error("Couldn't compute hash: {0}")] 25 | HashError(#[from] HashError), 26 | #[error("Expected a struct of type: {0:?}, received: {1:?}")] 27 | ExpectedStruct(String, String), 28 | #[error("Unsopported address domain: {0}")] 29 | UnsopportedAddressDomain(Felt252), 30 | #[error("The deploy_from_zero field in the deploy system call must be 0 or 1, found: {0}")] 31 | DeployFromZero(usize), 32 | #[error("Hint not implemented: {0}")] 33 | NotImplemented(String), 34 | #[error("HintData is incorrect")] 35 | WrongHintData, 36 | #[error("Iterator is not empty")] 37 | IteratorNotEmpty, 38 | #[error("Iterator is empty")] 39 | IteratorEmpty, 40 | #[error("List is empty")] 41 | ListIsEmpty, 42 | #[error("{0} should be None")] 43 | ShouldBeNone(String), 44 | #[error("Unexpected construct retdata")] 45 | UnexpectedConstructorRetdata, 46 | #[error("Key not found")] 47 | KeyNotFound, 48 | #[error("The requested syscall read was not of the expected type")] 49 | InvalidSyscallReadRequest, 50 | #[error("tx_info_ptr is None")] 51 | TxInfoPtrIsNone, 52 | #[error("Virtual machine error: {0}")] 53 | VirtualMachine(#[from] VirtualMachineError), 54 | #[error("Memory error: {0}")] 55 | Memory(#[from] MemoryError), 56 | #[error("Expected a ptr but received invalid data")] 57 | InvalidTxInfoPtr, 58 | #[error("Could not compute hash")] 59 | ErrorComputingHash, 60 | #[error("Inconsistent start and end segment indices")] 61 | InconsistentSegmentIndices, 62 | #[error("Start offset greater than end offset")] 63 | StartOffsetGreaterThanEndOffset, 64 | #[error("Incorrect request in syscall {0}")] 65 | IncorrectSyscall(String), 66 | #[error(transparent)] 67 | State(#[from] StateError), 68 | #[error(transparent)] 69 | MathError(#[from] MathError), 70 | #[error(transparent)] 71 | Hint(#[from] HintError), 72 | #[error("Unsupported address domain: {0}")] 73 | UnsupportedAddressDomain(String), 74 | #[error("{0:?}")] 75 | CustomError(String), 76 | #[error("Event exceeded the maximum keys length, keys length: {0}, max keys length: {1}.")] 77 | EventMaxKeysLengthExceeded(usize, usize), 78 | #[error("Event exceeded the maximum data length, data length: {0}, max data length: {1}.")] 79 | EventMaxDataLengthExceeded(usize, usize), 80 | #[error("Maximum number of events reached: {0}, can't emit another event.")] 81 | MaxNumberOfEmittedEventsExceeded(u64), 82 | } 83 | -------------------------------------------------------------------------------- /src/syscalls/syscall_info.rs: -------------------------------------------------------------------------------- 1 | pub fn get_syscall_size_from_name(syscall_name: &str) -> usize { 2 | match syscall_name { 3 | "emit_event" => 4, 4 | "deploy" => 5, 5 | "library_call" => 4, 6 | "storage_write" => 3, 7 | "storage_read" => 2, 8 | "send_message_to_l1" => 3, 9 | "get_execution_info" => 0, 10 | "call_contract" => 4, 11 | "replace_class" => 1, 12 | "keccak" => 2, 13 | "get_block_hash" => 1, 14 | _ => unimplemented!(), 15 | } 16 | } 17 | 18 | pub fn get_deprecated_syscall_size_from_name(syscall_name: &str) -> usize { 19 | match syscall_name { 20 | "call_contract" => 7, 21 | "deploy" => 9, 22 | "emit_event" => 5, 23 | "get_block_number" => 2, 24 | "get_block_timestamp" => 2, 25 | "get_caller_address" => 2, 26 | "get_contract_address" => 2, 27 | "get_sequencer_address" => 2, 28 | "get_tx_info" => 2, 29 | "get_tx_signature" => 3, 30 | "library_call" => 7, 31 | "library_call_l1_handler" => 7, 32 | "send_message_to_l1" => 4, 33 | "storage_read" => 3, 34 | "storage_write" => 3, 35 | "replace_class" => 2, 36 | "delegate_call" => 7, 37 | "delegate_l1_handler" => 7, 38 | _ => unreachable!(), 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /starknet_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /starknet_programs/AccountPreset.cairo: -------------------------------------------------------------------------------- 1 | // @compile-flags += --account_contract --no_debug_info 2 | // see deserialize_contract_class 3 | 4 | // SPDX-License-Identifier: MIT 5 | // OpenZeppelin Contracts for Cairo v0.5.1 (account/presets/Account.cairo) 6 | 7 | %lang starknet 8 | 9 | from starkware.cairo.common.cairo_builtins import HashBuiltin, SignatureBuiltin, BitwiseBuiltin 10 | from starkware.starknet.common.syscalls import get_tx_info 11 | 12 | from openzeppelin.account.library import Account, AccountCallArray 13 | 14 | // 15 | // Constructor 16 | // 17 | 18 | @constructor 19 | func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(publicKey: felt) { 20 | Account.initializer(publicKey); 21 | return (); 22 | } 23 | 24 | // 25 | // Getters 26 | // 27 | 28 | @view 29 | func getPublicKey{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> ( 30 | publicKey: felt 31 | ) { 32 | let (publicKey: felt) = Account.get_public_key(); 33 | return (publicKey=publicKey); 34 | } 35 | 36 | @view 37 | func supportsInterface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( 38 | interfaceId: felt 39 | ) -> (success: felt) { 40 | return Account.supports_interface(interfaceId); 41 | } 42 | 43 | // 44 | // Setters 45 | // 46 | 47 | @external 48 | func setPublicKey{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( 49 | newPublicKey: felt 50 | ) { 51 | Account.set_public_key(newPublicKey); 52 | return (); 53 | } 54 | 55 | // 56 | // Business logic 57 | // 58 | 59 | @view 60 | func isValidSignature{ 61 | syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, ecdsa_ptr: SignatureBuiltin*, range_check_ptr 62 | }(hash: felt, signature_len: felt, signature: felt*) -> (isValid: felt) { 63 | let (isValid: felt) = Account.is_valid_signature(hash, signature_len, signature); 64 | return (isValid=isValid); 65 | } 66 | 67 | @external 68 | func __validate__{ 69 | syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, ecdsa_ptr: SignatureBuiltin*, range_check_ptr 70 | }(call_array_len: felt, call_array: AccountCallArray*, calldata_len: felt, calldata: felt*) { 71 | let (tx_info) = get_tx_info(); 72 | Account.is_valid_signature(tx_info.transaction_hash, tx_info.signature_len, tx_info.signature); 73 | return (); 74 | } 75 | 76 | @external 77 | func __validate_declare__{ 78 | syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, ecdsa_ptr: SignatureBuiltin*, range_check_ptr 79 | }(class_hash: felt) { 80 | let (tx_info) = get_tx_info(); 81 | Account.is_valid_signature(tx_info.transaction_hash, tx_info.signature_len, tx_info.signature); 82 | return (); 83 | } 84 | 85 | @external 86 | func __validate_deploy__{ 87 | syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, ecdsa_ptr: SignatureBuiltin*, range_check_ptr 88 | }(class_hash: felt, salt: felt, publicKey: felt) { 89 | let (tx_info) = get_tx_info(); 90 | Account.is_valid_signature(tx_info.transaction_hash, tx_info.signature_len, tx_info.signature); 91 | return (); 92 | } 93 | 94 | @external 95 | func __execute__{ 96 | syscall_ptr: felt*, 97 | pedersen_ptr: HashBuiltin*, 98 | ecdsa_ptr: SignatureBuiltin*, 99 | bitwise_ptr: BitwiseBuiltin*, 100 | range_check_ptr, 101 | }(call_array_len: felt, call_array: AccountCallArray*, calldata_len: felt, calldata: felt*) -> ( 102 | response_len: felt, response: felt* 103 | ) { 104 | let (response_len, response) = Account.execute( 105 | call_array_len, call_array, calldata_len, calldata 106 | ); 107 | return (response_len, response); 108 | } 109 | -------------------------------------------------------------------------------- /starknet_programs/ERC165.cairo: -------------------------------------------------------------------------------- 1 | // This contract is a modification from: 2 | // https://github.com/OpenZeppelin/cairo-contracts/blob/main/src/openzeppelin/introspection/erc165/IERC165.cairo 3 | 4 | %lang starknet 5 | 6 | from starkware.cairo.common.cairo_builtins import HashBuiltin 7 | from starkware.cairo.common.bool import FALSE 8 | 9 | @external 10 | func supportsInterface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( 11 | interface_id: felt 12 | ) -> (success: felt) { 13 | return (success=FALSE); 14 | } 15 | -------------------------------------------------------------------------------- /starknet_programs/ERC721.cairo: -------------------------------------------------------------------------------- 1 | // Contract taken from Starknet-Edu: 2 | // https://github.com/starknet-edu/starknet-erc721/blob/b21972ca1c976afb7a401f8c4bedaa35606bd028/contracts/token/ERC721/ERC721.cairo 3 | 4 | %lang starknet 5 | 6 | from starkware.cairo.common.cairo_builtins import HashBuiltin, SignatureBuiltin 7 | from starkware.cairo.common.uint256 import Uint256 8 | 9 | from openzeppelin.token.erc721.library import ERC721 10 | 11 | // 12 | // Constructor 13 | // 14 | 15 | @constructor 16 | func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( 17 | name: felt, symbol: felt, to_: felt 18 | ) { 19 | ERC721.initializer(name, symbol); 20 | let to = to_; 21 | let token_id: Uint256 = Uint256(1, 0); 22 | ERC721._mint(to, token_id); 23 | return (); 24 | } 25 | 26 | // 27 | // Getters 28 | // 29 | 30 | @view 31 | func name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (name: felt) { 32 | let (name) = ERC721.name(); 33 | return (name,); 34 | } 35 | 36 | @view 37 | func symbol{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (symbol: felt) { 38 | let (symbol) = ERC721.symbol(); 39 | return (symbol,); 40 | } 41 | 42 | @view 43 | func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(owner: felt) -> ( 44 | balance: Uint256 45 | ) { 46 | let (balance: Uint256) = ERC721.balance_of(owner); 47 | return (balance,); 48 | } 49 | 50 | @view 51 | func ownerOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( 52 | token_id: Uint256 53 | ) -> (owner: felt) { 54 | let (owner: felt) = ERC721.owner_of(token_id); 55 | return (owner,); 56 | } 57 | 58 | @view 59 | func getApproved{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( 60 | token_id: Uint256 61 | ) -> (approved: felt) { 62 | let (approved: felt) = ERC721.get_approved(token_id); 63 | return (approved,); 64 | } 65 | 66 | @view 67 | func isApprovedForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( 68 | owner: felt, operator: felt 69 | ) -> (is_approved: felt) { 70 | let (is_approved: felt) = ERC721.is_approved_for_all(owner, operator); 71 | return (is_approved,); 72 | } 73 | 74 | // 75 | // Externals 76 | // 77 | 78 | @external 79 | func approve{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( 80 | to: felt, token_id: Uint256 81 | ) { 82 | ERC721.approve(to, token_id); 83 | return (); 84 | } 85 | 86 | @external 87 | func setApprovalForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( 88 | operator: felt, approved: felt 89 | ) { 90 | ERC721.set_approval_for_all(operator, approved); 91 | return (); 92 | } 93 | 94 | @external 95 | func transferFrom{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( 96 | _from: felt, to: felt, token_id: Uint256 97 | ) { 98 | ERC721.transfer_from(_from, to, token_id); 99 | return (); 100 | } 101 | 102 | @external 103 | func safeTransferFrom{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}( 104 | _from: felt, to: felt, token_id: Uint256, data_len: felt, data: felt* 105 | ) { 106 | ERC721.safe_transfer_from(_from, to, token_id, data_len, data); 107 | return (); 108 | } 109 | -------------------------------------------------------------------------------- /starknet_programs/account_without_validation.cairo: -------------------------------------------------------------------------------- 1 | // @compile-flags += --account_contract 2 | 3 | // A dummy account contract without any validations. 4 | 5 | %lang starknet 6 | 7 | from starkware.cairo.common.bool import FALSE 8 | from starkware.cairo.common.cairo_builtins import HashBuiltin 9 | from starkware.starknet.common.syscalls import ( 10 | call_contract, 11 | deploy, 12 | get_caller_address, 13 | get_contract_address, 14 | ) 15 | 16 | @view 17 | func assert_only_self{syscall_ptr: felt*}() { 18 | let (self) = get_contract_address(); 19 | let (caller) = get_caller_address(); 20 | assert self = caller; 21 | return (); 22 | } 23 | 24 | @external 25 | func __validate_declare__(class_hash: felt) { 26 | return (); 27 | } 28 | 29 | @external 30 | func __validate_deploy__(class_hash: felt, contract_address_salt: felt) { 31 | return (); 32 | } 33 | 34 | @external 35 | func __validate__(contract_address, selector: felt, calldata_len: felt, calldata: felt*) { 36 | return (); 37 | } 38 | 39 | @external 40 | @raw_output 41 | func __execute__{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( 42 | contract_address, selector: felt, calldata_len: felt, calldata: felt* 43 | ) -> (retdata_size: felt, retdata: felt*) { 44 | let (retdata_size: felt, retdata: felt*) = call_contract( 45 | contract_address=contract_address, 46 | function_selector=selector, 47 | calldata_size=calldata_len, 48 | calldata=calldata, 49 | ); 50 | return (retdata_size=retdata_size, retdata=retdata); 51 | } 52 | 53 | @external 54 | func deploy_contract{syscall_ptr: felt*}( 55 | class_hash: felt, 56 | contract_address_salt: felt, 57 | constructor_calldata_len: felt, 58 | constructor_calldata: felt*, 59 | ) -> (contract_address: felt) { 60 | assert_only_self(); 61 | let (contract_address) = deploy( 62 | class_hash=class_hash, 63 | contract_address_salt=contract_address_salt, 64 | constructor_calldata_size=constructor_calldata_len, 65 | constructor_calldata=constructor_calldata, 66 | deploy_from_zero=FALSE, 67 | ); 68 | return (contract_address=contract_address); 69 | } 70 | -------------------------------------------------------------------------------- /starknet_programs/account_without_validation_and_expensive_constructor.cairo: -------------------------------------------------------------------------------- 1 | // @compile-flags += --account_contract 2 | 3 | // A dummy account contract without any validations. 4 | 5 | %lang starknet 6 | 7 | from starkware.cairo.common.bool import FALSE 8 | from starkware.cairo.common.cairo_builtins import HashBuiltin 9 | from starkware.starknet.common.syscalls import ( 10 | call_contract, 11 | deploy, 12 | get_caller_address, 13 | get_contract_address, 14 | ) 15 | 16 | @constructor 17 | func constructor{ 18 | syscall_ptr: felt*, 19 | pedersen_ptr: HashBuiltin*, 20 | range_check_ptr, 21 | }() { 22 | // Call some syscalls so we get a non-trivial fee increase 23 | get_caller_address(); 24 | get_caller_address(); 25 | get_caller_address(); 26 | get_caller_address(); 27 | get_caller_address(); 28 | get_caller_address(); 29 | get_caller_address(); 30 | return (); 31 | } 32 | 33 | @view 34 | func assert_only_self{syscall_ptr: felt*}() { 35 | let (self) = get_contract_address(); 36 | let (caller) = get_caller_address(); 37 | assert self = caller; 38 | return (); 39 | } 40 | 41 | @external 42 | func __validate_declare__(class_hash: felt) { 43 | return (); 44 | } 45 | 46 | @external 47 | func __validate_deploy__(class_hash: felt, contract_address_salt: felt) { 48 | return (); 49 | } 50 | 51 | @external 52 | func __validate__(contract_address, selector: felt, calldata_len: felt, calldata: felt*) { 53 | return (); 54 | } 55 | 56 | @external 57 | @raw_output 58 | func __execute__{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( 59 | contract_address, selector: felt, calldata_len: felt, calldata: felt* 60 | ) -> (retdata_size: felt, retdata: felt*) { 61 | let (retdata_size: felt, retdata: felt*) = call_contract( 62 | contract_address=contract_address, 63 | function_selector=selector, 64 | calldata_size=calldata_len, 65 | calldata=calldata, 66 | ); 67 | return (retdata_size=retdata_size, retdata=retdata); 68 | } 69 | 70 | @external 71 | func deploy_contract{syscall_ptr: felt*}( 72 | class_hash: felt, 73 | contract_address_salt: felt, 74 | constructor_calldata_len: felt, 75 | constructor_calldata: felt*, 76 | ) -> (contract_address: felt) { 77 | assert_only_self(); 78 | let (contract_address) = deploy( 79 | class_hash=class_hash, 80 | contract_address_salt=contract_address_salt, 81 | constructor_calldata_size=constructor_calldata_len, 82 | constructor_calldata=constructor_calldata, 83 | deploy_from_zero=FALSE, 84 | ); 85 | return (contract_address=contract_address); 86 | } 87 | -------------------------------------------------------------------------------- /starknet_programs/amm_proxy.cairo: -------------------------------------------------------------------------------- 1 | %lang starknet 2 | 3 | @contract_interface 4 | namespace IAMMContract { 5 | func get_account_token_balance(account_id: felt, token_type: felt) -> (balance: felt) { 6 | } 7 | 8 | func get_pool_token_balance(token_type: felt) -> (balance: felt) { 9 | } 10 | 11 | func swap(token_from: felt, amount_from: felt) -> (amount_to: felt) { 12 | } 13 | 14 | func add_demo_token(token_a_amount: felt, token_b_amount: felt) { 15 | } 16 | 17 | func init_pool(token_a: felt, token_b: felt) { 18 | } 19 | } 20 | 21 | @view 22 | func proxy_get_account_token_balance{syscall_ptr: felt*, range_check_ptr}( 23 | contract_address: felt, account_id: felt, token_type: felt 24 | ) -> (balance: felt) { 25 | return IAMMContract.get_account_token_balance(contract_address, account_id, token_type); 26 | } 27 | 28 | @view 29 | func proxy_get_pool_token_balance{syscall_ptr: felt*, range_check_ptr}( 30 | contract_address: felt, token_type: felt 31 | ) -> (balance: felt) { 32 | return IAMMContract.get_pool_token_balance(contract_address, token_type); 33 | } 34 | 35 | 36 | @external 37 | func proxy_swap{syscall_ptr: felt*, range_check_ptr}( 38 | contract_address: felt, token_from: felt, amount_from: felt 39 | ) -> (amount_to: felt) { 40 | return IAMMContract.swap(contract_address, token_from, amount_from); 41 | } 42 | 43 | @external 44 | func proxy_add_demo_token{syscall_ptr: felt*, range_check_ptr}( 45 | contract_address: felt, token_a_amount: felt, token_b_amount: felt 46 | ) { 47 | return IAMMContract.add_demo_token(contract_address, token_a_amount, token_b_amount); 48 | } 49 | 50 | @external 51 | func proxy_init_pool{syscall_ptr: felt*, range_check_ptr}( 52 | contract_address: felt, token_a: felt, token_b: felt 53 | ) { 54 | return IAMMContract.init_pool(contract_address, token_a, token_b); 55 | } 56 | -------------------------------------------------------------------------------- /starknet_programs/blockifier/ERC20_without_some_syscalls/ERC20/permitted.cairo: -------------------------------------------------------------------------------- 1 | %lang starknet 2 | 3 | from starkware.cairo.common.cairo_builtins import HashBuiltin 4 | from starkware.cairo.common.math import assert_not_zero 5 | from starkware.starknet.common.syscalls import get_caller_address 6 | 7 | @storage_var 8 | func permitted_minter() -> (res: felt) { 9 | } 10 | 11 | // Constructor. 12 | 13 | func permitted_initializer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( 14 | minter_address: felt 15 | ) { 16 | assert_not_zero(minter_address); 17 | permitted_minter.write(minter_address); 18 | return (); 19 | } 20 | 21 | // Getters. 22 | 23 | @view 24 | func permittedMinter{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> ( 25 | minter: felt 26 | ) { 27 | let (minter) = permitted_minter.read(); 28 | return (minter=minter); 29 | } 30 | 31 | // Internals. 32 | 33 | func permitted_minter_only{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { 34 | let (caller_address) = get_caller_address(); 35 | let (permitted_address) = permittedMinter(); 36 | assert_not_zero(permitted_address); 37 | assert caller_address = permitted_address; 38 | return (); 39 | } 40 | -------------------------------------------------------------------------------- /starknet_programs/blockifier/ERC20_without_some_syscalls/upgradability_proxy/initializable.cairo: -------------------------------------------------------------------------------- 1 | %lang starknet 2 | 3 | from starkware.cairo.common.bool import FALSE, TRUE 4 | from starkware.cairo.common.cairo_builtins import HashBuiltin 5 | 6 | @storage_var 7 | func _initialized() -> (res: felt) { 8 | } 9 | 10 | @view 11 | func initialized{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (res: felt) { 12 | let (res) = _initialized.read(); 13 | return (res=res); 14 | } 15 | 16 | func only_uninitialized{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { 17 | let (initialized_: felt) = initialized(); 18 | with_attr error_message("ALREADY_INITIALIZED") { 19 | assert initialized_ = FALSE; 20 | } 21 | return (); 22 | } 23 | 24 | func set_initialized{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { 25 | only_uninitialized(); 26 | _initialized.write(TRUE); 27 | return (); 28 | } 29 | -------------------------------------------------------------------------------- /starknet_programs/blockifier/rabbitx/contracts/protocol/libraries/helpers/bool_cmp.cairo: -------------------------------------------------------------------------------- 1 | namespace BoolCmp { 2 | func is_valid(a: felt) { 3 | with_attr error_message("Value should be either 0 or 1. Current value: {a}") { 4 | assert a * a = a; 5 | } 6 | return (); 7 | } 8 | 9 | func eq(a: felt, b: felt) -> (res: felt) { 10 | if (a == b) { 11 | return (res=1); 12 | } else { 13 | return (res=0); 14 | } 15 | } 16 | 17 | func either(x: felt, y: felt) -> (res: felt) { 18 | assert x * x = x; 19 | assert y * y = y; 20 | let (res) = eq((x - 1) * (y - 1), 0); 21 | return (res=res); 22 | } 23 | 24 | func both(x: felt, y: felt) -> (res: felt) { 25 | assert x * x = x; 26 | assert y * y = y; 27 | let (res) = eq((x + y), 2); 28 | return (res=res); 29 | } 30 | 31 | func neither(x: felt, y: felt) -> (res: felt) { 32 | assert x * x = x; 33 | assert y * y = y; 34 | let (res) = eq((x + y), 0); 35 | return (res=res); 36 | } 37 | 38 | func not(x: felt) -> (res: felt) { 39 | assert x * x = x; 40 | let res = (1 - x); 41 | return (res=res); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /starknet_programs/blockifier/rabbitx/contracts/protocol/libraries/helpers/constants.cairo: -------------------------------------------------------------------------------- 1 | from starkware.cairo.common.uint256 import Uint256 2 | from blockifier.rabbitx.contracts.protocol.libraries.types.data_types import DataTypes 3 | 4 | const UINT128_MAX = 2 ** 128 - 1; 5 | const INITIALIZE_SELECTOR = 215307247182100370520050591091822763712463273430149262739280891880522753123; 6 | 7 | // P - the prime number defined in Cairo documentation. Every artithmetic operation is done with mod P. 8 | // NOTE: This number shouldn't change for StartkNet, but if you are using Cairo with other P, please adjust this number to your needs. 9 | const CAIRO_FIELD_ORDER = 2 ** 251 + 17 * 2 ** 192 + 1; // 3618502788666131213697322783095070105623107215331596699973092056135872020481 == 0 10 | 11 | // MAX_UNSIGNED_FELT 12 | const MAX_UNSIGNED_FELT = CAIRO_FIELD_ORDER - 1; 13 | 14 | // MAX_SIGNED_FELT 15 | const MAX_SIGNED_FELT = (CAIRO_FIELD_ORDER - 1) / 2; 16 | 17 | // MIN_SIGNED_FELT - the lowest number possible in Cairo if felts are interpreted as signed integers. 18 | // (Recall : floor(P/2) = (P-1)/2) 19 | // (P-1/2) is done to be able to express floor(P/2) (no floor function in Cairo) 20 | // +1 is added, because (P-1/2): highest signed integer and (P-1/2)+1: lowest signed integer 21 | const MIN_SIGNED_FELT = MAX_SIGNED_FELT + 1; // as signed: -1809251394333065606848661391547535052811553607665798349986546028067936010240 or as unsigned: 1809251394333065606848661391547535052811553607665798349986546028067936010241 22 | 23 | func empty_reserve_configuration() -> (res: DataTypes.ReserveConfiguration) { 24 | return (DataTypes.ReserveConfiguration(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),); 25 | } 26 | 27 | func empty_reserve_data() -> (res: DataTypes.ReserveData) { 28 | let (empty_config) = empty_reserve_configuration(); 29 | return (DataTypes.ReserveData(empty_config, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),); 30 | } 31 | 32 | func uint256_max() -> (max: Uint256) { 33 | return (Uint256(UINT128_MAX, UINT128_MAX),); 34 | } 35 | -------------------------------------------------------------------------------- /starknet_programs/blockifier/rabbitx/contracts/protocol/libraries/types/data_types.cairo: -------------------------------------------------------------------------------- 1 | from starkware.cairo.common.uint256 import Uint256 2 | 3 | namespace DataTypes { 4 | struct ReserveConfiguration { 5 | ltv: felt, 6 | liquidation_threshold: felt, 7 | liquidation_bonus: felt, 8 | decimals: felt, 9 | reserve_active: felt, 10 | reserve_frozen: felt, 11 | borrowing_enabled: felt, 12 | stable_rate_borrowing_enabled: felt, 13 | asset_paused: felt, 14 | borrowable_in_isolation: felt, 15 | siloed_borrowing: felt, 16 | reserve_factor: felt, 17 | borrow_cap: felt, 18 | supply_cap: felt, 19 | liquidation_protocol_fee: felt, 20 | eMode_category: felt, 21 | unbacked_mint_cap: felt, 22 | debt_ceiling: felt, 23 | } 24 | 25 | struct ReserveData { 26 | configuration: ReserveConfiguration, 27 | liquidity_index: felt, 28 | current_liquidity_rate: felt, 29 | variable_borrow_index: felt, 30 | current_variable_borrow_rate: felt, 31 | current_stable_borrow_rate: felt, 32 | last_update_timestamp: felt, 33 | id: felt, 34 | a_token_address: felt, 35 | stable_debt_token_address: felt, 36 | variable_debt_token_address: felt, 37 | interest_rate_strategy_address: felt, 38 | accrued_to_treasury: felt, 39 | unbacked: felt, 40 | isolation_mode_total_debt: felt, 41 | } 42 | 43 | struct ReserveCache { 44 | curr_scaled_variable_debt: felt, 45 | next_scaled_variable_debt: felt, 46 | curr_principal_stable_debt: felt, 47 | curr_avg_stable_borrow_rate: felt, 48 | curr_total_stable_debt: felt, 49 | next_avg_stable_borrow_rate: felt, 50 | next_total_stable_debt: felt, 51 | curr_liquidity_index: felt, 52 | next_liquidity_index: felt, 53 | curr_variable_borrow_index: felt, 54 | next_variable_borrow_index: felt, 55 | curr_liquidity_rate: felt, 56 | curr_variable_borrow_rate: felt, 57 | reserve_factor: felt, 58 | a_token_address: felt, 59 | stable_debt_token_address: felt, 60 | variable_debt_token_address: felt, 61 | reserve_last_update_timestamp: felt, 62 | stable_debt_last_update_timestamp: felt, 63 | configuration: ReserveConfiguration, 64 | } 65 | 66 | struct InitReserveParams { 67 | asset: felt, 68 | a_token_address: felt, 69 | stable_debt_token_address: felt, 70 | variable_debt_token_address: felt, 71 | interest_rate_strategy_address: felt, 72 | reserves_count: felt, 73 | max_number_reserves: felt, 74 | } 75 | 76 | struct UserConfigurationMap { 77 | borrowing: felt, 78 | using_as_collateral: felt, 79 | } 80 | 81 | struct ExecuteSupplyParams { 82 | asset: felt, 83 | amount: Uint256, 84 | on_behalf_of: felt, 85 | referral_code: felt, 86 | } 87 | 88 | struct ExecuteWithdrawParams { 89 | asset: felt, 90 | amount: Uint256, 91 | to: felt, 92 | reserves_count: felt, 93 | // TODO add the rest of the fields 94 | // member oracle : felt 95 | // member user_eMode_category : felt 96 | } 97 | 98 | // @dev UserState - additionalData is a flexible field. 99 | // ATokens and VariableDebtTokens use this field store the index of the user's last supply/withdrawal/borrow/repayment. 100 | // StableDebtTokens use this field to store the user's stable rate. 101 | struct UserState { 102 | balance: felt, 103 | additional_data: felt, 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/callee.cairo: -------------------------------------------------------------------------------- 1 | #[starknet::interface] 2 | trait IContractTrait { 3 | fn return_42(ref self: TContractState) -> felt252; 4 | fn return_44(ref self: TContractState) -> felt252; 5 | } 6 | 7 | #[starknet::contract] 8 | mod Callee { 9 | #[storage] 10 | struct Storage { 11 | balance: felt252, 12 | } 13 | 14 | #[constructor] 15 | fn constructor(ref self: ContractState, initial_balance: felt252) { 16 | self.balance.write(initial_balance); 17 | } 18 | 19 | #[abi(embed_v0)] 20 | impl IContractTrait of super::IContractTrait { 21 | fn return_42(ref self: ContractState) -> felt252 { 22 | 42 23 | } 24 | 25 | fn return_44(ref self: ContractState) -> felt252 { 26 | 44 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/caller.cairo: -------------------------------------------------------------------------------- 1 | #[starknet::interface] 2 | trait IContractTrait { 3 | fn call_callee_contract(ref self: TContractState, function_selector: felt252) -> felt252; 4 | } 5 | 6 | #[starknet::contract] 7 | mod Caller { 8 | use starknet::call_contract_syscall; 9 | use core::array; 10 | use core::result::ResultTrait; 11 | 12 | #[storage] 13 | struct Storage { 14 | balance: felt252, 15 | } 16 | 17 | #[abi(embed_v0)] 18 | impl IContractTrait of super::IContractTrait { 19 | fn call_callee_contract(ref self: ContractState, function_selector: felt252) -> felt252 { 20 | let calldata: Array = ArrayTrait::new(); 21 | let callee_addr = starknet::get_contract_address(); 22 | let return_data = call_contract_syscall(callee_addr, function_selector, calldata.span()) 23 | .unwrap(); 24 | *return_data.get(0_usize).unwrap().unbox() 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/contract_a.cairo: -------------------------------------------------------------------------------- 1 | #[starknet::interface] 2 | trait IContractA { 3 | fn foo(ref self: TContractState, a: u128) -> u128; 4 | } 5 | 6 | #[starknet::contract] 7 | mod ContractA { 8 | use traits::Into; 9 | use starknet::info::get_contract_address; 10 | 11 | #[storage] 12 | struct Storage { 13 | value: u128, 14 | } 15 | 16 | #[constructor] 17 | fn constructor(ref self: ContractState, value_: u128) { 18 | self.value.write(value_); 19 | } 20 | 21 | #[abi(embed_v0)] 22 | impl ContractA of super::IContractA { 23 | fn foo(ref self: ContractState, a: u128) -> u128 { 24 | let value = self.value.read(); 25 | self.value.write(a); 26 | value 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/deploy.cairo: -------------------------------------------------------------------------------- 1 | use starknet::class_hash::ClassHash; 2 | 3 | #[starknet::interface] 4 | trait IDeployTest { 5 | fn deploy_test(self: @TContractState, class_hash: ClassHash, contract_address_salt: felt252) -> starknet::contract_address::ContractAddress; 6 | } 7 | 8 | #[starknet::contract] 9 | mod DeployTest { 10 | use core::result::ResultTrait; 11 | use starknet::syscalls::deploy_syscall; 12 | use starknet::class_hash::ClassHash; 13 | use starknet::contract_address::ContractAddress; 14 | use starknet::class_hash::Felt252TryIntoClassHash; 15 | use option::OptionTrait; 16 | use traits::TryInto; 17 | use array::ArrayTrait; 18 | 19 | 20 | #[storage] 21 | struct Storage { 22 | } 23 | 24 | #[abi(embed_v0)] 25 | impl DeployTest of super::IDeployTest { 26 | fn deploy_test(self: @ContractState, class_hash: ClassHash, contract_address_salt: felt252) -> ContractAddress { 27 | let mut calldata = ArrayTrait::new(); 28 | calldata.append(100); 29 | let (address0, _) = deploy_syscall(class_hash, contract_address_salt, calldata.span(), false).unwrap(); 30 | address0 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/deploy_contract_no_args.cairo: -------------------------------------------------------------------------------- 1 | #[starknet::interface] 2 | trait IDeploy { 3 | fn deploy_no_args(self: @TContractState, class_hash: starknet::class_hash::ClassHash) -> felt252; 4 | } 5 | 6 | #[starknet::contract] 7 | mod Deploy { 8 | use array::{Array, ArrayTrait, Span, SpanTrait}; 9 | use starknet::{syscalls::deploy_syscall, contract_address_to_felt252, class_hash::ClassHash}; 10 | use result::ResultTrait; 11 | 12 | 13 | #[storage] 14 | struct Storage { 15 | } 16 | 17 | #[abi(embed_v0)] 18 | impl Deploy of super::IDeploy { 19 | fn deploy_no_args(self: @ContractState, class_hash: ClassHash) -> felt252 { 20 | let calldata = ArrayTrait::new(); 21 | match deploy_syscall(class_hash, 0, calldata.span(), false) { 22 | Result::Ok((addr, _)) => contract_address_to_felt252(addr), 23 | Result::Err(revert_reason) => *revert_reason.span().at(0), 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/deploy_erc20.cairo: -------------------------------------------------------------------------------- 1 | use starknet::contract_address::ContractAddress; 2 | use starknet::class_hash::ClassHash; 3 | #[starknet::interface] 4 | trait IDeployTest { 5 | fn deploy_test(self: @TContractState, class_hash: ClassHash, contract_address_salt: felt252, recipient: felt252, name: felt252, decimals: felt252, initial_supply: felt252, symbol: felt252) -> (core::starknet::contract_address::ContractAddress, core::array::Span::); 6 | } 7 | 8 | #[starknet::contract] 9 | mod DeployTest { 10 | use core::result::ResultTrait; 11 | use starknet::syscalls::deploy_syscall; 12 | use starknet::class_hash::ClassHash; 13 | use starknet::contract_address::ContractAddress; 14 | use starknet::class_hash::Felt252TryIntoClassHash; 15 | use option::OptionTrait; 16 | use traits::TryInto; 17 | use array::ArrayTrait; 18 | 19 | #[storage] 20 | struct Storage { 21 | } 22 | 23 | #[abi(embed_v0)] 24 | impl DeployTest of super::IDeployTest { 25 | fn deploy_test(self: @ContractState, class_hash: ClassHash, contract_address_salt: felt252, recipient: felt252, name: felt252, decimals: felt252, initial_supply: felt252, symbol: felt252) -> (core::starknet::contract_address::ContractAddress, core::array::Span::) { 26 | let mut calldata = ArrayTrait::new(); 27 | calldata.append(recipient); 28 | calldata.append(name); 29 | calldata.append(decimals); 30 | calldata.append(initial_supply); 31 | calldata.append(symbol); 32 | deploy_syscall(class_hash, contract_address_salt, calldata.span(), false).unwrap() 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/deploy_with_constructor.cairo: -------------------------------------------------------------------------------- 1 | #[starknet::interface] 2 | trait IDeployWithConstructorTest { 3 | fn deploy_test(self: @TContractState, class_hash: felt252, contract_address_salt: felt252, address: felt252, value: felt252) -> starknet::contract_address::ContractAddress; 4 | } 5 | 6 | #[starknet::contract] 7 | mod DeployTest { 8 | use core::result::ResultTrait; 9 | use starknet::syscalls::deploy_syscall; 10 | use starknet::class_hash::ClassHash; 11 | use starknet::contract_address::ContractAddress; 12 | use starknet::class_hash::Felt252TryIntoClassHash; 13 | use option::OptionTrait; 14 | use traits::TryInto; 15 | use array::ArrayTrait; 16 | 17 | 18 | 19 | #[storage] 20 | struct Storage { 21 | } 22 | 23 | #[abi(embed_v0)] 24 | impl DeployWithConstructorTest of super::IDeployWithConstructorTest { 25 | fn deploy_test(self: @ContractState, class_hash: felt252, contract_address_salt: felt252, address: felt252, value: felt252) -> ContractAddress { 26 | let mut calldata = ArrayTrait::new(); 27 | calldata.append(address); 28 | calldata.append(value); 29 | let (address0, _) = deploy_syscall(class_hash.try_into().unwrap(), contract_address_salt, calldata.span(), false).unwrap(); 30 | address0 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/deploy_without_constructor.cairo: -------------------------------------------------------------------------------- 1 | #[starknet::interface] 2 | trait IDeployWithoutConstructorTest { 3 | fn deploy_test(self: @TContractState, class_hash: felt252, contract_address_salt: felt252) -> starknet::contract_address::ContractAddress; 4 | } 5 | 6 | #[starknet::contract] 7 | mod DeployTest { 8 | use core::result::ResultTrait; 9 | use starknet::syscalls::deploy_syscall; 10 | use starknet::class_hash::ClassHash; 11 | use starknet::contract_address::ContractAddress; 12 | use starknet::class_hash::Felt252TryIntoClassHash; 13 | use option::OptionTrait; 14 | use traits::TryInto; 15 | use array::ArrayTrait; 16 | 17 | 18 | #[storage] 19 | struct Storage { 20 | } 21 | 22 | #[abi(embed_v0)] 23 | impl DeployWithoutConstructorTest of super::IDeployWithoutConstructorTest { 24 | fn deploy_test(self: @ContractState, class_hash: felt252, contract_address_salt: felt252) -> ContractAddress { 25 | let mut calldata = ArrayTrait::new(); 26 | let (address0, _) = deploy_syscall(class_hash.try_into().unwrap(), contract_address_salt, calldata.span(), false).unwrap(); 27 | address0 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/echo.cairo: -------------------------------------------------------------------------------- 1 | #[starknet::interface] 2 | trait IEcho { 3 | fn echo(ref self: TContractState, value: felt252) -> felt252; 4 | } 5 | 6 | #[starknet::contract] 7 | mod Echo { 8 | #[storage] 9 | struct Storage { 10 | balance: felt252, 11 | } 12 | 13 | #[constructor] 14 | fn constructor(ref self: ContractState, initial_balance: felt252) { 15 | self.balance.write(initial_balance); 16 | } 17 | 18 | #[abi(embed_v0)] 19 | impl IEcho of super::IEcho { 20 | #[abi(per_item)] 21 | fn echo(ref self: ContractState, value: felt252) -> felt252 { 22 | value 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/echo_caller.cairo: -------------------------------------------------------------------------------- 1 | #[starknet::interface] 2 | trait IContractTrait { 3 | fn call_echo_contract( 4 | ref self: TContractState, function_selector: felt252, value: felt252 5 | ) -> felt252; 6 | } 7 | 8 | #[starknet::contract] 9 | mod EchoCaller { 10 | use starknet::call_contract_syscall; 11 | use core::array; 12 | use core::result::ResultTrait; 13 | 14 | #[storage] 15 | struct Storage { 16 | balance: felt252, 17 | } 18 | 19 | #[abi(embed_v0)] 20 | impl IContractTrait of super::IContractTrait { 21 | fn call_echo_contract( 22 | ref self: ContractState, function_selector: felt252, value: felt252 23 | ) -> felt252 { 24 | let mut calldata: Array = ArrayTrait::new(); 25 | calldata.append(value); 26 | let callee_addr = starknet::get_contract_address(); 27 | let return_data = call_contract_syscall(callee_addr, function_selector, calldata.span()) 28 | .unwrap(); 29 | *return_data.get(0_usize).unwrap().unbox() 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/emit_event.cairo: -------------------------------------------------------------------------------- 1 | #[starknet::interface] 2 | trait IEventTest { 3 | fn trigger_events(ref self: TContractState) -> (); 4 | } 5 | 6 | #[starknet::contract] 7 | mod EventTest { 8 | #[storage] 9 | struct Storage { 10 | } 11 | 12 | #[event] 13 | #[derive(Drop, starknet::Event)] 14 | enum Event { 15 | EmitEvent: EmitEvent 16 | } 17 | 18 | #[derive(Drop, starknet::Event)] 19 | struct EmitEvent { 20 | n: felt252 21 | } 22 | 23 | 24 | #[abi(embed_v0)] 25 | impl EventTest of super::IEventTest { 26 | fn trigger_events(ref self: ContractState) -> () { 27 | self.emit(Event::EmitEvent(EmitEvent { n: 1 })); 28 | self.emit(Event::EmitEvent(EmitEvent { n: 2 })); 29 | self.emit(Event::EmitEvent(EmitEvent { n: 3 })); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/event_emitter.cairo: -------------------------------------------------------------------------------- 1 | #[starknet::interface] 2 | trait IContractTrait { 3 | fn trigger_event(ref self: TContractState) -> felt252; 4 | } 5 | 6 | 7 | #[starknet::contract] 8 | mod EventTest { 9 | use starknet::syscalls::emit_event_syscall; 10 | 11 | #[storage] 12 | struct Storage { 13 | balance: felt252, 14 | } 15 | 16 | #[event] 17 | #[derive(Drop, starknet::Event)] 18 | enum Event { 19 | EmitEvent: EmitEvent 20 | } 21 | 22 | #[derive(Drop, starknet::Event)] 23 | struct EmitEvent { 24 | n: u128, 25 | } 26 | 27 | #[abi(embed_v0)] 28 | impl IContractTrait of super::IContractTrait { 29 | fn trigger_event(ref self: ContractState) -> felt252 { 30 | let mut keys = ArrayTrait::new(); 31 | keys.append('n'); 32 | let mut values = ArrayTrait::new(); 33 | values.append(1); 34 | emit_event_syscall(keys.span(), values.span()).unwrap(); 35 | 1234 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/events.cairo: -------------------------------------------------------------------------------- 1 | use core::debug::PrintTrait; 2 | use core::traits::Into; 3 | use core::result::ResultTrait; 4 | use starknet::syscalls::{deploy_syscall, get_block_hash_syscall}; 5 | use traits::TryInto; 6 | use option::OptionTrait; 7 | use starknet::SyscallResultTrait; 8 | use starknet::class_hash::Felt252TryIntoClassHash; 9 | use array::ArrayTrait; 10 | use array::SpanTrait; 11 | 12 | #[starknet::interface] 13 | trait IContractWithEvent { 14 | fn emit_event(ref self: T, incremental: bool); 15 | } 16 | 17 | #[starknet::contract] 18 | mod ContractWithEvent { 19 | use traits::Into; 20 | use starknet::info::get_contract_address; 21 | #[storage] 22 | struct Storage { 23 | value: u128, 24 | } 25 | 26 | #[derive(Copy, Drop, PartialEq, starknet::Event)] 27 | struct IncrementalEvent { 28 | value: u128, 29 | } 30 | 31 | #[derive(Copy, Drop, PartialEq, starknet::Event)] 32 | struct StaticEvent {} 33 | 34 | #[event] 35 | #[derive(Copy, Drop, PartialEq, starknet::Event)] 36 | enum Event { 37 | IncrementalEvent: IncrementalEvent, 38 | StaticEvent: StaticEvent, 39 | } 40 | 41 | #[constructor] 42 | fn constructor(ref self: ContractState) { 43 | self.value.write(0); 44 | } 45 | 46 | #[abi(embed_v0)] 47 | fn emit_event(ref self: ContractState, incremental: bool) { 48 | if incremental { 49 | self.emit(Event::IncrementalEvent(IncrementalEvent { value: self.value.read() })); 50 | self.value.write(self.value.read() + 1); 51 | } else { 52 | self.emit(Event::StaticEvent(StaticEvent {})); 53 | } 54 | } 55 | } 56 | 57 | use ContractWithEvent::{Event, IncrementalEvent, StaticEvent}; 58 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/example_contract.cairo: -------------------------------------------------------------------------------- 1 | #[starknet::interface] 2 | trait IExampleContract { 3 | fn get_balance(ref self: TContractState) -> u128; 4 | fn increase_balance(ref self: TContractState, amount: u128); 5 | } 6 | 7 | #[starknet::contract] 8 | mod ExampleContract { 9 | use traits::Into; 10 | use starknet::info::get_contract_address; 11 | 12 | #[storage] 13 | struct Storage { 14 | balance: u128, 15 | } 16 | 17 | #[constructor] 18 | fn constructor(ref self: ContractState) { 19 | } 20 | 21 | #[abi(embed_v0)] 22 | impl ExampleContract of super::IExampleContract { 23 | fn get_balance(ref self: ContractState) -> u128 { 24 | self.balance.read() 25 | } 26 | 27 | fn increase_balance(ref self: ContractState, amount: u128) { 28 | let balance = self.balance.read(); 29 | self.balance.write(balance + amount); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/factorial.cairo: -------------------------------------------------------------------------------- 1 | #[starknet::interface] 2 | trait IFactorial { 3 | fn factorial(self: @TContractState, n: felt252) -> felt252; 4 | } 5 | 6 | #[starknet::contract] 7 | mod Factorial { 8 | #[storage] 9 | struct Storage { 10 | } 11 | 12 | #[abi(embed_v0)] 13 | impl Factorial of super::IFactorial { 14 | fn factorial(self: @ContractState, n: felt252) -> felt252 { 15 | match n { 16 | 0 => 1, 17 | _ => n * Factorial::factorial(self, n-1), 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/factorial_tr.cairo: -------------------------------------------------------------------------------- 1 | #[starknet::interface] 2 | trait IFactorial { 3 | fn factorial(self: @TContractState, n: felt252) -> felt252; 4 | } 5 | 6 | #[starknet::contract] 7 | mod Factorial { 8 | #[storage] 9 | struct Storage { 10 | } 11 | 12 | fn factorial_tr(acc: felt252, n: felt252) -> felt252 { 13 | if n == 0 || n == 1 { 14 | acc 15 | } else { 16 | factorial_tr(acc*n, n-1) 17 | } 18 | } 19 | 20 | #[abi(embed_v0)] 21 | impl Factorial of super::IFactorial { 22 | fn factorial(self: @ContractState, n: felt252) -> felt252 { 23 | factorial_tr(1, n) 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/failing_constructor.cairo: -------------------------------------------------------------------------------- 1 | #[starknet::contract] 2 | mod FailingConstructor { 3 | #[storage] 4 | struct Storage { 5 | } 6 | 7 | #[constructor] 8 | fn constructor(ref self: ContractState) { 9 | assert( 1 == 0 , 'Oops'); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/faulty_low_level_storage_read.cairo: -------------------------------------------------------------------------------- 1 | #[starknet::interface] 2 | trait IReadStorage { 3 | fn read_storage(self: @TContractState) -> felt252; 4 | } 5 | 6 | #[starknet::contract] 7 | mod ReadStorage { 8 | use array::{Array, ArrayTrait, Span, SpanTrait}; 9 | use starknet::{syscalls::storage_read_syscall, storage_access::{StorageAddress, storage_address_try_from_felt252}}; 10 | use result::ResultTrait; 11 | use option::OptionTrait; 12 | 13 | #[storage] 14 | struct Storage { 15 | } 16 | 17 | #[abi(embed_v0)] 18 | impl ReadStorage of super::IReadStorage { 19 | fn read_storage(self: @ContractState) -> felt252 { 20 | let address = storage_address_try_from_felt252(1).unwrap(); 21 | match storage_read_syscall(3, address) { 22 | Result::Ok(value) => value, 23 | Result::Err(revert_reason) => *revert_reason.span().at(0), 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/faulty_low_level_storage_write.cairo: -------------------------------------------------------------------------------- 1 | #[starknet::interface] 2 | trait IWriteStorage { 3 | fn write_storage(self: @TContractState) -> felt252; 4 | } 5 | 6 | #[starknet::contract] 7 | mod WriteStorage { 8 | use array::{Array, ArrayTrait, Span, SpanTrait}; 9 | use starknet::{syscalls::storage_write_syscall, storage_access::{StorageAddress, storage_address_try_from_felt252}}; 10 | use result::ResultTrait; 11 | use option::OptionTrait; 12 | 13 | #[storage] 14 | struct Storage { 15 | } 16 | 17 | #[abi(embed_v0)] 18 | impl WriteStorage of super::IWriteStorage { 19 | fn write_storage(self: @ContractState) -> felt252 { 20 | let address = storage_address_try_from_felt252(1).unwrap(); 21 | match storage_write_syscall(3, address, 1) { 22 | Result::Ok(_value) => 1, 23 | Result::Err(revert_reason) => *revert_reason.span().at(0), 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/faulty_math_lib.cairo: -------------------------------------------------------------------------------- 1 | #[starknet::interface] 2 | trait IMath { 3 | fn square_root(self: @TContractState, n: felt252) -> felt252; 4 | } 5 | 6 | #[starknet::contract] 7 | mod Math { 8 | use integer::u128_sqrt; 9 | use core::traits::Into; 10 | use traits::TryInto; 11 | use option::OptionTrait; 12 | 13 | #[storage] 14 | struct Storage { 15 | } 16 | 17 | #[abi(embed_v0)] 18 | impl Math of super::IMath { 19 | fn square_root(self: @ContractState, n: felt252) -> felt252 { 20 | assert( 0 == 1 , 'Unimplemented'); 21 | 0 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/fibonacci.cairo: -------------------------------------------------------------------------------- 1 | #[starknet::interface] 2 | trait IFibonacci { 3 | fn fib(self: @TContractState, a: felt252, b: felt252, n: felt252) -> felt252; 4 | } 5 | 6 | #[starknet::contract] 7 | mod Fibonacci { 8 | #[storage] 9 | struct Storage { 10 | } 11 | 12 | #[abi(embed_v0)] 13 | impl Fibonacci of super::IFibonacci { 14 | fn fib(self: @ContractState, a: felt252, b: felt252, n: felt252) -> felt252 { 15 | match n { 16 | 0 => a, 17 | _ => Fibonacci::fib(self, b, a + b, n - 1), 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/fibonacci_dispatcher.cairo: -------------------------------------------------------------------------------- 1 | use starknet::ContractAddress; 2 | use array::ArrayTrait; 3 | use array::SpanTrait; 4 | use box::BoxTrait; 5 | use result::ResultTrait; 6 | use option::OptionTrait; 7 | 8 | #[starknet::interface] 9 | trait IDispatcher { 10 | fn fib(self: @TContractState, class_hash: felt252, selector: felt252, a: felt252, b: felt252, n: felt252) -> felt252; 11 | } 12 | 13 | trait FibonacciDispatcherTrait { 14 | fn fib(self: T, a: felt252, b: felt252, n: felt252) -> felt252; 15 | } 16 | 17 | #[derive(Copy, Drop, storage_access::StorageAccess, Serde)] 18 | struct FibonacciLibraryDispatcher { 19 | class_hash: starknet::ClassHash, 20 | selector: felt252, 21 | } 22 | 23 | impl FibonacciLibraryDispatcherImpl of FibonacciDispatcherTrait { 24 | fn fib( 25 | self: FibonacciLibraryDispatcher, a: felt252, b: felt252, n: felt252 26 | ) -> felt252 { 27 | 28 | let mut calldata = ArrayTrait::new(); 29 | calldata.append(a); 30 | calldata.append(b); 31 | calldata.append(n); 32 | 33 | let ret = starknet::syscalls::library_call_syscall(self.class_hash, self.selector, calldata.span()).unwrap(); 34 | *ret.get(0_usize).unwrap().unbox() 35 | } 36 | } 37 | 38 | #[starknet::contract] 39 | mod Dispatcher { 40 | use super::FibonacciDispatcherTrait; 41 | use super::FibonacciLibraryDispatcher; 42 | use starknet::ContractAddress; 43 | 44 | #[storage] 45 | struct Storage { 46 | } 47 | 48 | #[abi(embed_v0)] 49 | impl Dispatcher of super::IDispatcher { 50 | fn fib( 51 | self: @ContractState, class_hash: felt252, selector: felt252, a: felt252, b: felt252, n: felt252 52 | ) -> felt252 { 53 | FibonacciLibraryDispatcher { 54 | // THIS VALUE IS THE HASH OF THE FIBONACCI CASM CLASS HASH. 55 | class_hash: starknet::class_hash_const::<2889767417435368609058888822622483550637539736178264636938129582300971548553>(), 56 | selector 57 | }.fib(a, b, n) 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/get_block_hash_basic.cairo: -------------------------------------------------------------------------------- 1 | #[starknet::interface] 2 | trait IGetBlockHashBasic { 3 | fn get_block_hash(self: @TContractState, block_number: u64) -> felt252; 4 | } 5 | 6 | #[starknet::contract] 7 | mod GetBlockHashBasic { 8 | use core::{debug::PrintTrait, result::ResultTrait, starknet::get_block_hash_syscall}; 9 | 10 | #[storage] 11 | struct Storage {} 12 | 13 | #[abi(embed_v0)] 14 | impl GetBlockHashBasic of super::IGetBlockHashBasic { 15 | fn get_block_hash(self: @ContractState, block_number: u64) -> felt252 { 16 | get_block_hash_syscall(block_number).unwrap() 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/get_execution_info.cairo: -------------------------------------------------------------------------------- 1 | use core::starknet::contract_address::ContractAddress; 2 | 3 | #[starknet::interface] 4 | trait IGetExecutionInfo { 5 | fn get_info(self: @TContractState) -> (ContractAddress, ContractAddress, ContractAddress, ContractAddress); 6 | } 7 | 8 | #[starknet::contract] 9 | mod GetExecutionInfo { 10 | use starknet::info::get_execution_info; 11 | use starknet::info::ExecutionInfo; 12 | use core::starknet::contract_address::ContractAddress; 13 | use box::BoxTrait; 14 | use array::SpanTrait; 15 | 16 | #[storage] 17 | struct Storage { 18 | } 19 | 20 | #[abi(embed_v0)] 21 | impl GetExecutionInfo of super::IGetExecutionInfo { 22 | fn get_info(self: @ContractState) -> (ContractAddress, ContractAddress, ContractAddress, ContractAddress) { 23 | let info = get_execution_info().unbox(); 24 | let block_info = info.block_info.unbox(); 25 | let tx_info = info.tx_info.unbox(); 26 | 27 | let block_number = block_info.block_number; 28 | let block_timestamp = block_info.block_timestamp; 29 | let sequencer_address = block_info.sequencer_address; 30 | 31 | let version = tx_info.version; 32 | let account_contract_address = tx_info.account_contract_address; 33 | let max_fee = tx_info.max_fee; 34 | let signature = tx_info.signature; 35 | let transaction_hash = tx_info.transaction_hash; 36 | let chain_id = tx_info.chain_id; 37 | let nonce = tx_info.nonce; 38 | 39 | let caller_address = info.caller_address; 40 | let contract_address = info.contract_address; 41 | let entry_point_selector = info.entry_point_selector; 42 | 43 | assert(block_number == 0, 1); 44 | assert(block_timestamp == 0, 2); 45 | assert(version == 1, 3); 46 | assert(max_fee == 0, 4); 47 | assert(transaction_hash == 0, 5); 48 | assert(chain_id == 1536727068981429685321, 6); 49 | assert(nonce == 10, 7); 50 | assert(entry_point_selector == 1583979555264088613757654119588925070177786702073426169970015447448454297318, 8); 51 | assert(*signature.at(0) == 22, 9); 52 | assert(*signature.at(1) == 33, 10); 53 | assert(signature.len() == 2, 11); 54 | 55 | return ( 56 | sequencer_address, 57 | account_contract_address, 58 | caller_address, 59 | contract_address 60 | ); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/get_execution_info_v2.cairo: -------------------------------------------------------------------------------- 1 | use core::starknet::contract_address::ContractAddress; 2 | 3 | #[starknet::interface] 4 | trait IGetExecutionInfo { 5 | fn get_info(self: @TContractState) -> (ContractAddress, ContractAddress, ContractAddress, ContractAddress); 6 | } 7 | 8 | #[starknet::contract] 9 | mod GetExecutionInfo { 10 | use starknet::info::get_execution_info; 11 | use starknet::info::v2::ExecutionInfo; 12 | use core::starknet::contract_address::ContractAddress; 13 | use box::BoxTrait; 14 | use array::SpanTrait; 15 | 16 | #[storage] 17 | struct Storage { 18 | } 19 | 20 | #[abi(embed_v0)] 21 | impl GetExecutionInfo of super::IGetExecutionInfo { 22 | fn get_info(self: @ContractState) -> (ContractAddress, ContractAddress, ContractAddress, ContractAddress) { 23 | let info = get_execution_info().unbox(); 24 | let block_info = info.block_info.unbox(); 25 | let tx_info = info.tx_info.unbox(); 26 | 27 | let block_number = block_info.block_number; 28 | let block_timestamp = block_info.block_timestamp; 29 | let sequencer_address = block_info.sequencer_address; 30 | 31 | let version = tx_info.version; 32 | let account_contract_address = tx_info.account_contract_address; 33 | let max_fee = tx_info.max_fee; 34 | let signature = tx_info.signature; 35 | let transaction_hash = tx_info.transaction_hash; 36 | let chain_id = tx_info.chain_id; 37 | let nonce = tx_info.nonce; 38 | 39 | let caller_address = info.caller_address; 40 | let contract_address = info.contract_address; 41 | let entry_point_selector = info.entry_point_selector; 42 | 43 | // V2 fields 44 | 45 | let resource_bounds = tx_info.resource_bounds; 46 | let tip = tx_info.tip; 47 | let paymaster_data = tx_info.paymaster_data; 48 | let nonce_da_mode = tx_info.nonce_data_availability_mode; 49 | let fee_da_mode = tx_info.fee_data_availability_mode; 50 | let account_deployment_data = tx_info.account_deployment_data; 51 | 52 | assert(block_number == 0, 'Wrong Block Number'); 53 | assert(block_timestamp == 0, 'Wrong Block Timestamp'); 54 | assert(version == 1, 'Wrong Version'); 55 | assert(max_fee == 0, 'Wrong max fee'); 56 | assert(transaction_hash == 0, 'Wrong Tx Hash'); 57 | assert(chain_id == 1536727068981429685321, 'Wrong Chain Id'); 58 | assert(nonce == 10, 'Wrong Nonce'); 59 | assert(entry_point_selector == 1583979555264088613757654119588925070177786702073426169970015447448454297318, 'Wrong Entrypoint Selector'); 60 | assert(*signature.at(0) == 22, 'Wrong Signature'); 61 | assert(*signature.at(1) == 33, 'Wrong Signature'); 62 | assert(signature.len() == 2, 'Wrong Signature len'); 63 | assert(*resource_bounds.at(0).resource == 83774935613779, 'Wrong L1 gas resource name'); 64 | assert(*resource_bounds.at(0).max_amount == 30, 'Wrong L1 gas max amount'); 65 | assert(*resource_bounds.at(0).max_price_per_unit == 15, 'Wrong L1 gas max price per unit'); 66 | assert(*resource_bounds.at(1).resource== 83779230581075, 'Wrong L1 gas resource name'); 67 | assert(*resource_bounds.at(1).max_amount == 10, 'Wrong L2 gas max amount'); 68 | assert(*resource_bounds.at(1).max_price_per_unit == 5, 'Wrong L2 gas max price per unit'); 69 | assert(tip == 3, 'Wrong Tip'); 70 | assert(*paymaster_data.at(0) == 6, 'Wrong Paymaster Data'); 71 | assert(*paymaster_data.at(1) == 17, 'Wrong Paymaster Data'); 72 | assert(paymaster_data.len() == 2, 'Wrong Paymaster Data len'); 73 | assert(nonce_da_mode == 0, 'Wrong Nonce DA Mode'); 74 | assert(fee_da_mode == 1, 'Wrong Fee DA Mode'); 75 | assert(*account_deployment_data.at(0) == 7, 'Wrong Acc. Deployment Data'); 76 | assert(*account_deployment_data.at(1) == 18, 'Wrong Acc. Deployment Data'); 77 | assert(account_deployment_data.len() == 2, 'Wrong Acc. Deployment Data len'); 78 | 79 | return ( 80 | sequencer_address, 81 | account_contract_address, 82 | caller_address, 83 | contract_address 84 | ); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/get_number_a.cairo: -------------------------------------------------------------------------------- 1 | use core::starknet::class_hash::ClassHash; 2 | 3 | #[starknet::interface] 4 | trait IGetNumber { 5 | fn get_number(self: @TContractState) -> felt252; 6 | fn upgrade(self: @TContractState, new_class_hash: ClassHash); 7 | } 8 | 9 | #[starknet::contract] 10 | mod GetNumber { 11 | use core::starknet::class_hash::ClassHash; 12 | use core::starknet::replace_class_syscall; 13 | 14 | #[storage] 15 | struct Storage { 16 | } 17 | 18 | #[abi(embed_v0)] 19 | impl GetNumber of super::IGetNumber { 20 | fn get_number(self: @ContractState) -> felt252 { 21 | 25 22 | } 23 | 24 | fn upgrade(self: @ContractState, new_class_hash: ClassHash) { 25 | replace_class_syscall(new_class_hash).unwrap(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/get_number_b.cairo: -------------------------------------------------------------------------------- 1 | use core::starknet::class_hash::ClassHash; 2 | 3 | #[starknet::interface] 4 | trait IGetNumber { 5 | fn get_number(self: @TContractState) -> felt252; 6 | fn upgrade(self: @TContractState, new_class_hash: ClassHash); 7 | } 8 | 9 | #[starknet::contract] 10 | mod GetNumber { 11 | use core::starknet::class_hash::ClassHash; 12 | use core::starknet::replace_class_syscall; 13 | 14 | #[storage] 15 | struct Storage { 16 | } 17 | 18 | #[abi(embed_v0)] 19 | impl GetNumber of super::IGetNumber { 20 | fn get_number(self: @ContractState) -> felt252 { 21 | 17 22 | } 23 | 24 | fn upgrade(self: @ContractState, new_class_hash: ClassHash) { 25 | replace_class_syscall(new_class_hash).unwrap(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/get_number_wrapper.cairo: -------------------------------------------------------------------------------- 1 | use starknet::ClassHash; 2 | 3 | #[starknet::interface] 4 | trait GetNumber { 5 | fn get_number(self: @TContractState) -> felt252; 6 | fn upgrade(self: @TContractState, new_class_hash: ClassHash); 7 | } 8 | 9 | #[starknet::interface] 10 | trait IGetNumber { 11 | fn get_number(self: @TContractState) -> felt252; 12 | fn upgrade(self: @TContractState, new_class_hash: ClassHash); 13 | fn get_numbers_old_new(self: @TContractState, new_class_hash: ClassHash) -> (felt252, felt252); 14 | } 15 | 16 | #[starknet::contract] 17 | mod GetNumberWrapper { 18 | use super::GetNumberDispatcherTrait; 19 | use super::GetNumberDispatcher; 20 | use starknet::ClassHash; 21 | use starknet::ContractAddress; 22 | use starknet::contract_address_try_from_felt252; 23 | use option::OptionTrait; 24 | 25 | #[storage] 26 | struct Storage { 27 | } 28 | 29 | // We use a constant for the contract_address to test the replace_class functionality 30 | const get_number_contract_address: felt252 = 1; 31 | 32 | #[abi(embed_v0)] 33 | impl GetNumberWrapper of super::IGetNumber { 34 | fn get_number(self: @ContractState) -> felt252 { 35 | let address = contract_address_try_from_felt252(get_number_contract_address).unwrap(); 36 | GetNumberDispatcher {contract_address: address}.get_number() 37 | } 38 | 39 | fn upgrade(self: @ContractState, new_class_hash: ClassHash) { 40 | let address = contract_address_try_from_felt252(get_number_contract_address).unwrap(); 41 | GetNumberDispatcher {contract_address: address}.upgrade(new_class_hash); 42 | } 43 | 44 | fn get_numbers_old_new(self: @ContractState, new_class_hash: ClassHash) -> (felt252, felt252){ 45 | let address = contract_address_try_from_felt252(get_number_contract_address).unwrap(); 46 | let old_number = GetNumberDispatcher {contract_address: address}.get_number(); 47 | GetNumberDispatcher {contract_address: address}.upgrade(new_class_hash); 48 | let new_number = GetNumberDispatcher {contract_address: address}.get_number(); 49 | (old_number, new_number) 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/hello_world_account.cairo: -------------------------------------------------------------------------------- 1 | // Import necessary modules and traits 2 | use serde::Serde; 3 | use starknet::ContractAddress; 4 | use array::ArrayTrait; 5 | use array::SpanTrait; 6 | use option::OptionTrait; 7 | 8 | // Define the Call struct 9 | #[derive(Drop, Serde)] 10 | struct Call { 11 | to: ContractAddress, 12 | selector: felt252, 13 | calldata: Array 14 | } 15 | 16 | #[starknet::interface] 17 | trait IAccount { 18 | fn __validate_deploy__(self: @TContractState, class_hash: felt252, contract_address_salt: felt252, public_key_: felt252) -> felt252; 19 | fn __validate_declare__(self: @TContractState, class_hash: felt252) -> felt252; 20 | fn __validate__(self: @TContractState, contract_address: ContractAddress, entry_point_selector: felt252, calldata: Array) -> felt252; 21 | fn __execute__(ref self: TContractState, calls: Array) -> Span; 22 | fn deploy(self: @TContractState, class_hash: felt252, contract_address_salt: felt252, name_: felt252, symbol_: felt252, decimals: felt252, initial_supply: felt252, recipient: felt252) -> (ContractAddress, core::array::Span::); 23 | } 24 | 25 | // Define the Account contract 26 | #[starknet::contract(account)] 27 | mod Account { 28 | use array::ArrayTrait; 29 | use array::SpanTrait; 30 | use box::BoxTrait; 31 | use ecdsa::check_ecdsa_signature; 32 | use option::OptionTrait; 33 | use super::Call; 34 | use starknet::ContractAddress; 35 | use zeroable::Zeroable; 36 | use starknet::syscalls::deploy_syscall; 37 | use core::result::ResultTrait; 38 | use starknet::class_hash::ClassHash; 39 | use starknet::class_hash::Felt252TryIntoClassHash; 40 | use traits::TryInto; 41 | 42 | // Define the contract's storage variables 43 | #[storage] 44 | struct Storage { 45 | public_key: felt252 46 | } 47 | 48 | // Constructor function for initializing the contract 49 | #[constructor] 50 | fn constructor(ref self: ContractState, public_key_: felt252) { 51 | self.public_key.write(public_key_); 52 | } 53 | 54 | // Internal function to validate the transaction signature 55 | fn validate_transaction(self: @ContractState) -> felt252 { 56 | let tx_info = starknet::get_tx_info().unbox(); // Unbox transaction info 57 | let signature = tx_info.signature; // Extract signature 58 | assert(signature.len() == 2_u32, 'INVALID_SIGNATURE_LENGTH'); // Check signature length 59 | 60 | // Verify ECDSA signature 61 | 62 | starknet::VALIDATED // Return validation status 63 | } 64 | 65 | #[abi(embed_v0)] 66 | impl Account of super::IAccount { 67 | fn deploy(self: @ContractState, class_hash: felt252, contract_address_salt: felt252, name_: felt252, symbol_: felt252, decimals: felt252, initial_supply: felt252, recipient: felt252) -> (ContractAddress, core::array::Span::) { 68 | let mut calldata = ArrayTrait::new(); 69 | calldata.append(name_); 70 | calldata.append(symbol_); 71 | calldata.append(decimals); 72 | calldata.append(initial_supply); 73 | calldata.append(recipient); 74 | let (address0, something_else) = deploy_syscall(class_hash.try_into().unwrap(), contract_address_salt, calldata.span(), false).unwrap(); 75 | (address0, something_else) 76 | } 77 | // Validate contract deployment 78 | fn __validate_deploy__( 79 | self: @ContractState, class_hash: felt252, contract_address_salt: felt252, public_key_: felt252 80 | ) -> felt252 { 81 | validate_transaction(self) 82 | } 83 | 84 | // Validate contract declaration 85 | fn __validate_declare__(self: @ContractState, class_hash: felt252) -> felt252 { 86 | validate_transaction(self) 87 | } 88 | 89 | // Validate contract execution 90 | fn __validate__( 91 | self: @ContractState, contract_address: ContractAddress, entry_point_selector: felt252, calldata: Array 92 | ) -> felt252 { 93 | validate_transaction(self) 94 | } 95 | 96 | // Execute a contract call 97 | #[raw_output] 98 | fn __execute__(ref self: ContractState, mut calls: Array) -> Span { 99 | // Validate caller 100 | assert(starknet::get_caller_address().is_zero(), 'INVALID_CALLER'); 101 | 102 | let tx_info = starknet::get_tx_info().unbox(); // Unbox transaction info 103 | assert(tx_info.version != 0, 'INVALID_TX_VERSION'); 104 | 105 | assert(calls.len() == 1_u32, 'MULTI_CALL_NOT_SUPPORTED'); // Only single calls are supported 106 | let Call{to, selector, calldata } = calls.pop_front().unwrap(); 107 | 108 | // Call the target contract 109 | starknet::call_contract_syscall( 110 | address: to, entry_point_selector: selector, calldata: calldata.span() 111 | ).unwrap() 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/math_lib.cairo: -------------------------------------------------------------------------------- 1 | #[starknet::interface] 2 | trait IMath { 3 | fn square_root(ref self: TContractState, n: felt252) -> felt252; 4 | } 5 | 6 | 7 | #[starknet::contract] 8 | mod Math { 9 | use integer::u128_sqrt; 10 | use core::traits::Into; 11 | use traits::TryInto; 12 | use option::OptionTrait; 13 | 14 | #[storage] 15 | struct Storage{ 16 | } 17 | 18 | #[abi(embed_v0)] 19 | impl Math of super::IMath { 20 | fn square_root(ref self: ContractState, n: felt252) -> felt252 { 21 | let n_u128: u128 = n.try_into().unwrap(); 22 | let n_u64: u64 = u128_sqrt(n_u128); 23 | n_u64.into() 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/multi_syscall_test.cairo: -------------------------------------------------------------------------------- 1 | use starknet::contract_address::ContractAddress; 2 | use starknet::class_hash::ClassHash; 3 | 4 | #[starknet::interface] 5 | trait IMultiSyscall { 6 | fn caller_address(self: @TContractState) -> ContractAddress; 7 | fn contract_address(self: @TContractState) -> ContractAddress; 8 | fn execution_info_syscall(self: @TContractState) -> (ContractAddress, ContractAddress); 9 | fn test_library_call_syscall(self: @TContractState, class_hash: ClassHash, function_selector: felt252, number: felt252) -> felt252; 10 | fn test_call_contract_syscall(self: @TContractState, function_selector: felt252, number: felt252) -> felt252; 11 | fn test_send_message_to_l1(self: @TContractState, to_address: felt252, payload_0: felt252, payload_1: felt252); 12 | fn read(self: @TContractState)-> felt252; 13 | fn trigger_events(ref self: TContractState); 14 | fn get_number(self: @TContractState, number: felt252) -> felt252; 15 | } 16 | 17 | #[starknet::contract] 18 | mod MultiSyscall { 19 | use core::starknet::{get_caller_address, get_contract_address, get_execution_info_syscall, replace_class_syscall,library_call_syscall, call_contract_syscall, send_message_to_l1_syscall, storage_read_syscall, storage_write_syscall, deploy_syscall}; 20 | use starknet::storage_access::{StorageAddress, storage_address_try_from_felt252}; 21 | use starknet::contract_address::ContractAddress; 22 | use array::{Array, ArrayTrait, Span, SpanTrait}; 23 | use result::ResultTrait; 24 | use starknet::info::ExecutionInfo; 25 | use option::OptionTrait; 26 | use starknet::class_hash::{ClassHash, Felt252TryIntoClassHash}; 27 | use box::{Box, BoxTrait}; 28 | use traits::{Into, TryInto}; 29 | 30 | #[storage] 31 | struct Storage { 32 | value: u128, 33 | } 34 | 35 | #[derive(Copy, Drop, PartialEq, starknet::Event)] 36 | struct StaticEvent { 37 | n: felt252, 38 | } 39 | 40 | #[event] 41 | #[derive(Copy, Drop, PartialEq, starknet::Event)] 42 | enum Event { 43 | StaticEvent: StaticEvent, 44 | } 45 | 46 | 47 | #[abi(embed_v0)] 48 | impl MultiSyscall of super::IMultiSyscall { 49 | fn caller_address(self: @ContractState) -> ContractAddress { 50 | get_caller_address() 51 | } 52 | fn contract_address(self: @ContractState) -> ContractAddress { 53 | get_contract_address() 54 | } 55 | fn execution_info_syscall(self: @ContractState) -> (ContractAddress, ContractAddress) { 56 | let return_data = get_execution_info_syscall().unwrap().unbox(); 57 | (return_data.caller_address, return_data.contract_address) 58 | } 59 | fn test_library_call_syscall(self: @ContractState, class_hash: ClassHash, function_selector: felt252, number: felt252) -> felt252 { 60 | let mut calldata = ArrayTrait::::new(); 61 | calldata.append(number); 62 | let return_data = library_call_syscall(class_hash, function_selector, calldata.span()).unwrap(); 63 | *return_data.get(0_usize).unwrap().unbox() 64 | } 65 | fn test_call_contract_syscall(self: @ContractState, function_selector: felt252, number: felt252) -> felt252 { 66 | let mut calldata = ArrayTrait::::new(); 67 | calldata.append(number); 68 | let return_data = call_contract_syscall(get_contract_address(), function_selector, calldata.span()).unwrap(); 69 | *return_data.get(0_usize).unwrap().unbox() 70 | } 71 | 72 | fn test_send_message_to_l1(self: @ContractState, to_address: felt252, payload_0: felt252, payload_1: felt252) { 73 | let mut calldata = ArrayTrait::::new(); 74 | calldata.append(payload_0); 75 | calldata.append(payload_1); 76 | let return_data = send_message_to_l1_syscall(to_address, calldata.span()).unwrap(); 77 | return_data 78 | } 79 | fn read(self: @ContractState)-> felt252{ 80 | //write to storage 81 | let address = storage_address_try_from_felt252(3534535754756246375475423547453).unwrap(); 82 | storage_write_syscall(0, address, 'Hello').unwrap(); 83 | 84 | //read from storage 85 | match storage_read_syscall(0, address) { 86 | Result::Ok(value) => value, 87 | Result::Err(revert_reason) => *revert_reason.span().at(0), 88 | } 89 | } 90 | fn trigger_events(ref self: ContractState) { 91 | self.emit(Event::StaticEvent(StaticEvent {n: 1})); 92 | self.emit(Event::StaticEvent(StaticEvent {n: 2})); 93 | self.emit(Event::StaticEvent(StaticEvent {n: 3})); 94 | } 95 | fn get_number(self: @ContractState, number: felt252) -> felt252 { 96 | number 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/send_message_to_l1.cairo: -------------------------------------------------------------------------------- 1 | #[starknet::interface] 2 | trait ISendMessageToL1 { 3 | fn send_msg(ref self: TContractState); 4 | } 5 | 6 | #[starknet::contract] 7 | mod SendMessageToL1 { 8 | 9 | use starknet::syscalls::send_message_to_l1_syscall; 10 | use array::{Array, ArrayTrait}; 11 | 12 | #[storage] 13 | struct Storage{ 14 | } 15 | 16 | #[abi(embed_v0)] 17 | impl SendMessageToL1 of super::ISendMessageToL1 { 18 | fn send_msg(ref self: ContractState) { 19 | let mut payload = array::array_new::(); 20 | payload.append(555); 21 | payload.append(666); 22 | send_message_to_l1_syscall(444, payload.span()).unwrap(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/send_messages_contract_call.cairo: -------------------------------------------------------------------------------- 1 | #[starknet::interface] 2 | trait SendMessageToL1 { 3 | fn send_simple_message_to_l1(ref self: TContractState, to_address: felt252, message: felt252); 4 | } 5 | 6 | #[starknet::interface] 7 | trait ISendMessages { 8 | fn send_sequential_messages(ref self: TContractState, to_address: felt252, message1: felt252, message2: felt252); 9 | } 10 | 11 | #[starknet::contract] 12 | mod SendMessages { 13 | use super::SendMessageToL1DispatcherTrait; 14 | use super::SendMessageToL1Dispatcher; 15 | use starknet::ContractAddress; 16 | use starknet::contract_address_try_from_felt252; 17 | use option::OptionTrait; 18 | 19 | const SEND_MESSAGES_CONTRACT_ADDRESS: felt252 = 1; //Hardcoded value in test 20 | 21 | #[storage] 22 | struct Storage{ 23 | } 24 | 25 | #[abi(embed_v0)] 26 | impl SendMessages of super::ISendMessages { 27 | fn send_sequential_messages(ref self: ContractState, to_address: felt252, message1: felt252, message2: felt252) { 28 | let address = contract_address_try_from_felt252(SEND_MESSAGES_CONTRACT_ADDRESS).unwrap(); 29 | SendMessageToL1Dispatcher {contract_address: address}.send_simple_message_to_l1(to_address, message1); 30 | SendMessageToL1Dispatcher {contract_address: address}.send_simple_message_to_l1(to_address, message2); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/send_simple_message_to_l1.cairo: -------------------------------------------------------------------------------- 1 | #[starknet::interface] 2 | trait ISendMessageToL1 { 3 | fn send_simple_message_to_l1(self: @TContractState, to_address: felt252, message: felt252); 4 | } 5 | 6 | #[starknet::contract] 7 | mod SendMessageToL1 { 8 | use starknet::syscalls::send_message_to_l1_syscall; 9 | use array::{Array, ArrayTrait}; 10 | 11 | #[storage] 12 | struct Storage { 13 | } 14 | 15 | #[abi(embed_v0)] 16 | impl SendMessageToL1 of super::ISendMessageToL1 { 17 | fn send_simple_message_to_l1(self: @ContractState, to_address: felt252, message: felt252) { 18 | let mut payload = array::array_new::(); 19 | payload.append(message); 20 | send_message_to_l1_syscall(to_address, payload.span()).unwrap(); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/simple_wallet.cairo: -------------------------------------------------------------------------------- 1 | #[starknet::interface] 2 | trait ISimpleWallet { 3 | fn get_balance(ref self: TContractState) -> felt252; 4 | fn increase_balance(ref self: TContractState, amount: felt252); 5 | } 6 | 7 | #[starknet::contract] 8 | mod SimpleWallet { 9 | 10 | #[storage] 11 | struct Storage { 12 | balance: felt252, 13 | } 14 | 15 | #[constructor] 16 | fn constructor(ref self: ContractState, initial_balance: felt252) { 17 | self.balance.write(initial_balance); 18 | } 19 | 20 | #[abi(embed_v0)] 21 | impl SimpleWallet of super::ISimpleWallet { 22 | fn get_balance(ref self: ContractState) -> felt252 { 23 | self.balance.read() 24 | } 25 | 26 | fn increase_balance(ref self: ContractState, amount: felt252) { 27 | let current_balance = self.balance.read(); 28 | self.balance.write(current_balance + amount) 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/square_root.cairo: -------------------------------------------------------------------------------- 1 | use starknet::ClassHash; 2 | 3 | #[starknet::interface] 4 | trait Math { 5 | fn square_root(self: @TContractState, n: felt252) -> felt252; 6 | } 7 | 8 | #[starknet::interface] 9 | trait ISquareRoot { 10 | fn square_root(self: @TContractState, n: felt252, math_class_hash: ClassHash) -> felt252; 11 | } 12 | 13 | 14 | #[starknet::contract] 15 | mod SquareRoot { 16 | use super::MathDispatcherTrait; 17 | use super::MathLibraryDispatcher; 18 | use starknet::ClassHash; 19 | 20 | #[storage] 21 | struct Storage{ 22 | } 23 | 24 | #[abi(embed_v0)] 25 | impl SquareRoot of super::ISquareRoot { 26 | fn square_root(self: @ContractState, n: felt252, math_class_hash: ClassHash) -> felt252 { 27 | MathLibraryDispatcher {class_hash: math_class_hash}.square_root(n) 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/square_root_recursive.cairo: -------------------------------------------------------------------------------- 1 | use starknet::ClassHash; 2 | 3 | #[starknet::interface] 4 | trait Math { 5 | fn square_root(self: @TContractState, n: felt252) -> felt252; 6 | } 7 | 8 | #[starknet::interface] 9 | trait ISquareRoot { 10 | fn square_root(self: @TContractState, n: felt252, math_class_hash: ClassHash, n_iterations: u32) -> felt252; 11 | } 12 | 13 | 14 | #[starknet::contract] 15 | mod SquareRoot { 16 | use super::MathDispatcherTrait; 17 | use super::MathLibraryDispatcher; 18 | use starknet::ClassHash; 19 | 20 | #[storage] 21 | struct Storage{ 22 | } 23 | 24 | #[abi(embed_v0)] 25 | impl SquareRoot of super::ISquareRoot { 26 | fn square_root(self: @ContractState, n: felt252, math_class_hash: ClassHash, n_iterations: u32) -> felt252 { 27 | square_root_recursive_inner(n, math_class_hash, n_iterations) 28 | } 29 | } 30 | 31 | fn square_root_recursive_inner(n: felt252, math_class_hash: ClassHash, n_iterations: u32) -> felt252 { 32 | if n_iterations == 0 { 33 | return n; 34 | } 35 | square_root_recursive_inner(MathLibraryDispatcher {class_hash: math_class_hash}.square_root(n), math_class_hash, n_iterations - 1) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/test_cairo_keccak.cairo: -------------------------------------------------------------------------------- 1 | // NOTE: needs compiler version 2.1.0-rc0 or higher to compile. 2 | #[starknet::interface] 3 | trait IKeccak { 4 | fn cairo_keccak_test(self: @TContractState) -> felt252; 5 | } 6 | 7 | #[starknet::contract] 8 | mod Keccak { 9 | use core::clone::Clone; 10 | use array::{Array, ArrayTrait}; 11 | use core::traits::Into; 12 | 13 | #[storage] 14 | struct Storage {} 15 | 16 | #[abi(embed_v0)] 17 | impl Keccak of super::IKeccak { 18 | fn cairo_keccak_test(self: @ContractState) -> felt252 { 19 | let mut input = array![ 20 | 0x0000000000000001, 21 | 0x0000000000000002, 22 | 0x0000000000000003, 23 | 0x0000000000000004, 24 | 0x0000000000000005, 25 | 0x0000000000000006, 26 | 0x0000000000000007, 27 | 0x0000000000000008, 28 | 0x0000000000000009, 29 | 0x000000000000000a, 30 | 0x000000000000000b, 31 | 0x000000000000000c, 32 | 0x000000000000000d 33 | ]; 34 | 35 | // We must clone the array to be used in the second part, as it's modified by `cairo_keccak`. 36 | let mut orig_array = input.clone(); 37 | 38 | let res = keccak::cairo_keccak(ref input, 0x11000010, 4); 39 | assert(@res.low == @0x43ccdbe17ae03b02b308ebe4a23c4cc9, 'Wrong hash low 1'); 40 | assert(@res.high == @0xf3cc56e9bd860f83e3e3bc69919b176a, 'Wrong hash high 1'); 41 | 42 | // With "garbage" at the end (note the `aa`s), we should get the same result. 43 | let res = keccak::cairo_keccak(ref orig_array, 0xaaaaaaaa11000010, 4); 44 | assert(@res.low == @0x43ccdbe17ae03b02b308ebe4a23c4cc9, 'Wrong hash low 2'); 45 | assert(@res.high == @0xf3cc56e9bd860f83e3e3bc69919b176a, 'Wrong hash high 2'); 46 | 47 | 1 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /starknet_programs/cairo2/wallet_wrapper.cairo: -------------------------------------------------------------------------------- 1 | #[starknet::interface] 2 | trait SimpleWallet { 3 | fn get_balance(self: @TContractState) -> felt252; 4 | fn increase_balance(ref self: TContractState, amount: felt252); 5 | } 6 | 7 | #[starknet::interface] 8 | trait IWalletWrapper { 9 | fn get_balance(self: @TContractState, simple_wallet_contract_address: starknet::ContractAddress) -> felt252; 10 | fn increase_balance(ref self: TContractState, amount: felt252, simple_wallet_contract_address: starknet::ContractAddress); 11 | fn increase_balance_recursive(ref self: TContractState, amount: felt252, simple_wallet_contract_address: starknet::ContractAddress); 12 | } 13 | 14 | #[starknet::contract] 15 | mod WalletWrapper { 16 | use super::SimpleWalletDispatcherTrait; 17 | use super::SimpleWalletDispatcher; 18 | use starknet::ContractAddress; 19 | 20 | #[storage] 21 | struct Storage{ 22 | } 23 | 24 | #[abi(embed_v0)] 25 | impl WalletWrapper of super::IWalletWrapper { 26 | fn get_balance(self: @ContractState, simple_wallet_contract_address: ContractAddress) -> felt252 { 27 | SimpleWalletDispatcher {contract_address: simple_wallet_contract_address}.get_balance() 28 | } 29 | fn increase_balance(ref self: ContractState, amount: felt252, simple_wallet_contract_address: ContractAddress) { 30 | SimpleWalletDispatcher {contract_address: simple_wallet_contract_address}.increase_balance(amount) 31 | } 32 | fn increase_balance_recursive(ref self: ContractState, amount: felt252, simple_wallet_contract_address: ContractAddress) { 33 | increase_balance_recursive_inner(amount, simple_wallet_contract_address) 34 | } 35 | } 36 | 37 | fn increase_balance_recursive_inner(amount: felt252, simple_wallet_contract_address: ContractAddress) { 38 | if amount == 0 { 39 | return(); 40 | } 41 | SimpleWalletDispatcher {contract_address: simple_wallet_contract_address}.increase_balance(1); 42 | increase_balance_recursive_inner(amount - 1, simple_wallet_contract_address) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /starknet_programs/constructor.cairo: -------------------------------------------------------------------------------- 1 | %lang starknet 2 | 3 | from starkware.cairo.common.cairo_builtins import HashBuiltin 4 | 5 | // Define a storage variable for the owner address. 6 | @storage_var 7 | func owner() -> (owner_address: felt) { 8 | } 9 | 10 | @constructor 11 | func constructor{ 12 | syscall_ptr: felt*, 13 | pedersen_ptr: HashBuiltin*, 14 | range_check_ptr, 15 | }(owner_address: felt) { 16 | owner.write(value=owner_address); 17 | return (); 18 | } 19 | 20 | @view 21 | func get_owner{ 22 | syscall_ptr: felt*, 23 | pedersen_ptr: HashBuiltin*, 24 | range_check_ptr, 25 | }() -> (address: felt) { 26 | let (address) = owner.read(); 27 | return (address=address); 28 | } 29 | -------------------------------------------------------------------------------- /starknet_programs/delegate_call.cairo: -------------------------------------------------------------------------------- 1 | %lang starknet 2 | 3 | from starkware.cairo.common.alloc import alloc 4 | from starkware.cairo.common.cairo_builtins import HashBuiltin 5 | from starkware.starknet.common.syscalls import ( 6 | DELEGATE_CALL_SELECTOR, CallContractRequest, CallContract 7 | ) 8 | 9 | // Address set in test for contract get_number.cairo 10 | const CONTRACT_ADDRESS = 1; 11 | 12 | func delegate_call{syscall_ptr: felt*}( 13 | contract_address: felt, function_selector: felt, calldata_size: felt, calldata: felt* 14 | ) -> (retdata_size: felt, retdata: felt*) { 15 | let syscall = [cast(syscall_ptr, CallContract*)]; 16 | assert syscall.request = CallContractRequest( 17 | selector=DELEGATE_CALL_SELECTOR, 18 | contract_address=contract_address, 19 | function_selector=function_selector, 20 | calldata_size=calldata_size, 21 | calldata=calldata, 22 | ); 23 | %{ syscall_handler.delegate_call(segments=segments, syscall_ptr=ids.syscall_ptr) %} 24 | let response = syscall.response; 25 | 26 | let syscall_ptr = syscall_ptr + CallContract.SIZE; 27 | return (retdata_size=response.retdata_size, retdata=response.retdata); 28 | } 29 | 30 | @external 31 | func test_delegate_call{ 32 | syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr: felt 33 | }() { 34 | let (calldata) = alloc(); 35 | let (retdata_size, retdata) = delegate_call( 36 | contract_address=CONTRACT_ADDRESS, 37 | // function_selector=sn_keccak('get_number'), 38 | function_selector=0x23180acc053dfb2dbc82a0da33515906d37498b42f34ee4ed308f9d5fb51b6c, 39 | calldata_size=0, 40 | calldata=calldata, 41 | ); 42 | assert retdata_size = 1; 43 | assert retdata[0] = 14; 44 | return (); 45 | } 46 | -------------------------------------------------------------------------------- /starknet_programs/delegate_l1_handler.cairo: -------------------------------------------------------------------------------- 1 | %lang starknet 2 | 3 | from starkware.cairo.common.alloc import alloc 4 | from starkware.cairo.common.cairo_builtins import HashBuiltin 5 | from starkware.starknet.common.syscalls import ( 6 | DELEGATE_L1_HANDLER_SELECTOR, CallContractRequest, CallContract 7 | ) 8 | 9 | // Address set in test for contract get_number_l1_handler.cairo 10 | const CONTRACT_ADDRESS = 1; 11 | 12 | func delegate_l1_handler{syscall_ptr: felt*}( 13 | contract_address: felt, function_selector: felt, calldata_size: felt, calldata: felt* 14 | ) -> (retdata_size: felt, retdata: felt*) { 15 | let syscall = [cast(syscall_ptr, CallContract*)]; 16 | assert syscall.request = CallContractRequest( 17 | selector=DELEGATE_L1_HANDLER_SELECTOR, 18 | contract_address=contract_address, 19 | function_selector=function_selector, 20 | calldata_size=calldata_size, 21 | calldata=calldata, 22 | ); 23 | %{ syscall_handler.delegate_l1_handler(segments=segments, syscall_ptr=ids.syscall_ptr) %} 24 | let response = syscall.response; 25 | 26 | let syscall_ptr = syscall_ptr + CallContract.SIZE; 27 | return (retdata_size=response.retdata_size, retdata=response.retdata); 28 | } 29 | 30 | @external 31 | func test_delegate_l1_handler{ 32 | syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr: felt 33 | }() { 34 | let (calldata) = alloc(); 35 | assert calldata[0] = 5; 36 | 37 | let (retdata_size, retdata) = delegate_l1_handler( 38 | contract_address=CONTRACT_ADDRESS, 39 | function_selector=0x23180acc053dfb2dbc82a0da33515906d37498b42f34ee4ed308f9d5fb51b6c, 40 | calldata_size=1, 41 | calldata=calldata, 42 | ); 43 | return (); 44 | } 45 | -------------------------------------------------------------------------------- /starknet_programs/deployer.cairo: -------------------------------------------------------------------------------- 1 | // Code taken from Universal Deployer Proposal in starknet forum https://community.starknet.io/t/universal-deployer-contract-proposal/1864 2 | %lang starknet 3 | 4 | from starkware.starknet.common.syscalls import get_caller_address, deploy 5 | from starkware.cairo.common.cairo_builtins import HashBuiltin 6 | from starkware.cairo.common.hash import hash2 7 | from starkware.cairo.common.bool import FALSE 8 | 9 | @event 10 | func ContractDeployed( 11 | contractAddress: felt, 12 | deployer: felt, 13 | classHash: felt, 14 | salt: felt 15 | ){ 16 | } 17 | 18 | @external 19 | func deploy_contract{ 20 | syscall_ptr: felt*, 21 | pedersen_ptr: HashBuiltin*, 22 | range_check_ptr, 23 | } ( 24 | class_hash: felt, 25 | salt: felt, 26 | constructor_calldata_len: felt, 27 | constructor_calldata: felt*, 28 | ) -> (contract_address: felt){ 29 | 30 | let (deployer) = get_caller_address(); 31 | let (unique_salt) = hash2{hash_ptr=pedersen_ptr}(deployer, salt); 32 | 33 | let (contract_address) = deploy( 34 | class_hash=class_hash, 35 | contract_address_salt=unique_salt, 36 | constructor_calldata_size=constructor_calldata_len, 37 | constructor_calldata=constructor_calldata, 38 | deploy_from_zero=FALSE 39 | ); 40 | 41 | ContractDeployed.emit( 42 | contractAddress=contract_address, 43 | deployer=deployer, 44 | classHash=class_hash, 45 | salt=salt 46 | ); 47 | 48 | return (contract_address=contract_address); 49 | } 50 | -------------------------------------------------------------------------------- /starknet_programs/empty_contract.cairo: -------------------------------------------------------------------------------- 1 | %lang starknet 2 | -------------------------------------------------------------------------------- /starknet_programs/factorial.cairo: -------------------------------------------------------------------------------- 1 | %lang starknet 2 | 3 | // factorial(n) = n! 4 | @external 5 | func factorial(n) -> (result: felt) { 6 | if (n == 1) { 7 | return (n,); 8 | } 9 | let (a) = factorial(n - 1); 10 | return (n * a,); 11 | } 12 | 13 | func main() { 14 | return (); 15 | } 16 | -------------------------------------------------------------------------------- /starknet_programs/fibonacci.cairo: -------------------------------------------------------------------------------- 1 | %lang starknet 2 | 3 | func main{range_check_ptr: felt*}() { 4 | // Call fib(1, 1, 10). 5 | let result: felt = fib(1, 1, 10); 6 | 7 | // Make sure the 10th Fibonacci number is 144. 8 | assert result = 144; 9 | ret; 10 | } 11 | 12 | @external 13 | func fib(first_element, second_element, n) -> (res: felt) { 14 | jmp fib_body if n != 0; 15 | tempvar result = second_element; 16 | return (second_element,); 17 | 18 | fib_body: 19 | tempvar y = first_element + second_element; 20 | return fib(second_element, y, n - 1); 21 | } 22 | -------------------------------------------------------------------------------- /starknet_programs/first_contract.cairo: -------------------------------------------------------------------------------- 1 | %lang starknet 2 | 3 | from starkware.cairo.common.cairo_builtins import HashBuiltin 4 | 5 | // Define a storage variable. 6 | @storage_var 7 | func balance() -> (res: felt) { 8 | } 9 | 10 | // Increases the balance by the given amount. 11 | @external 12 | func increase_balance{ 13 | syscall_ptr: felt*, 14 | pedersen_ptr: HashBuiltin*, 15 | range_check_ptr, 16 | }(amount: felt) { 17 | let (res) = balance.read(); 18 | balance.write(res + amount); 19 | return (); 20 | } 21 | 22 | // Returns the current balance. 23 | @view 24 | func get_balance{ 25 | syscall_ptr: felt*, 26 | pedersen_ptr: HashBuiltin*, 27 | range_check_ptr, 28 | }() -> (res: felt) { 29 | let (res) = balance.read(); 30 | return (res=res); 31 | } 32 | -------------------------------------------------------------------------------- /starknet_programs/get_number.cairo: -------------------------------------------------------------------------------- 1 | %lang starknet 2 | 3 | @view 4 | func get_number() -> (number: felt) { 5 | return (number=14); 6 | } 7 | -------------------------------------------------------------------------------- /starknet_programs/get_number_c.cairo: -------------------------------------------------------------------------------- 1 | %lang starknet 2 | from starkware.starknet.common.syscalls import replace_class 3 | 4 | @view 5 | func get_number() -> (number: felt) { 6 | return (number=33); 7 | } 8 | 9 | @external 10 | func upgrade{syscall_ptr: felt*}(new_class_hash: felt) { 11 | replace_class(class_hash=new_class_hash); 12 | return(); 13 | } 14 | -------------------------------------------------------------------------------- /starknet_programs/get_number_d.cairo: -------------------------------------------------------------------------------- 1 | %lang starknet 2 | from starkware.starknet.common.syscalls import replace_class 3 | 4 | @view 5 | func get_number() -> (number: felt) { 6 | return (number=64); 7 | } 8 | 9 | @external 10 | func upgrade{syscall_ptr: felt*}(new_class_hash: felt) { 11 | replace_class(class_hash=new_class_hash); 12 | return(); 13 | } 14 | -------------------------------------------------------------------------------- /starknet_programs/get_number_l1_handler.cairo: -------------------------------------------------------------------------------- 1 | %lang starknet 2 | 3 | @l1_handler 4 | func get_number(from_address: felt) { 5 | return (); 6 | } 7 | -------------------------------------------------------------------------------- /starknet_programs/increase_balance.cairo: -------------------------------------------------------------------------------- 1 | // Declare this file as a StarkNet contract. 2 | %lang starknet 3 | 4 | from starkware.cairo.common.cairo_builtins import HashBuiltin 5 | 6 | // Define a storage variable. 7 | @storage_var 8 | func balance() -> (res: felt) { 9 | } 10 | 11 | // Increases the balance by the given amount. 12 | @external 13 | func increase_balance{ 14 | syscall_ptr: felt*, 15 | pedersen_ptr: HashBuiltin*, 16 | range_check_ptr, 17 | }(amount: felt) { 18 | let (res) = balance.read(); 19 | balance.write(amount); 20 | return (); 21 | } 22 | 23 | // Returns the current balance. 24 | @view 25 | func get_balance{ 26 | syscall_ptr: felt*, 27 | pedersen_ptr: HashBuiltin*, 28 | range_check_ptr, 29 | }() -> (res: felt) { 30 | let (res) = balance.read(); 31 | return (res=res); 32 | } 33 | -------------------------------------------------------------------------------- /starknet_programs/internal_calls.cairo: -------------------------------------------------------------------------------- 1 | %lang starknet 2 | 3 | @contract_interface 4 | namespace ISelf { 5 | func a() { 6 | } 7 | 8 | func b() { 9 | } 10 | 11 | func c() { 12 | } 13 | } 14 | 15 | @external 16 | func a{syscall_ptr: felt*, range_check_ptr}() { 17 | ISelf.library_call_b( 18 | class_hash=0x0101010101010101010101010101010101010101010101010101010101010101 19 | ); 20 | return (); 21 | } 22 | 23 | @external 24 | func b{syscall_ptr: felt*, range_check_ptr}() { 25 | ISelf.library_call_c( 26 | class_hash=0x0101010101010101010101010101010101010101010101010101010101010101 27 | ); 28 | return (); 29 | } 30 | 31 | @external 32 | func c{syscall_ptr: felt*, range_check_ptr}() { 33 | return (); 34 | } 35 | -------------------------------------------------------------------------------- /starknet_programs/l1l2.cairo: -------------------------------------------------------------------------------- 1 | // Contract taken from: 2 | // https://www.cairo-lang.org/docs/_static/l1l2.cairo 3 | 4 | %lang starknet 5 | 6 | from starkware.cairo.common.alloc import alloc 7 | from starkware.cairo.common.cairo_builtins import HashBuiltin 8 | from starkware.cairo.common.math import assert_nn 9 | from starkware.starknet.common.messages import send_message_to_l1 10 | 11 | const L1_CONTRACT_ADDRESS = (0x8359E4B0152ed5A731162D3c7B0D8D56edB165A0); 12 | const MESSAGE_WITHDRAW = 0; 13 | 14 | // A mapping from a user (L1 Ethereum address) to their balance. 15 | @storage_var 16 | func balance(user: felt) -> (res: felt) { 17 | } 18 | 19 | @view 20 | func get_balance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(user: felt) -> ( 21 | balance: felt 22 | ) { 23 | let (res) = balance.read(user=user); 24 | return (balance=res); 25 | } 26 | 27 | @external 28 | func increase_balance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( 29 | user: felt, amount: felt 30 | ) { 31 | let (res) = balance.read(user=user); 32 | balance.write(user, res + amount); 33 | return (); 34 | } 35 | 36 | @external 37 | func withdraw{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( 38 | user: felt, amount: felt 39 | ) { 40 | // Make sure 'amount' is positive. 41 | assert_nn(amount); 42 | 43 | let (res) = balance.read(user=user); 44 | tempvar new_balance = res - amount; 45 | 46 | // Make sure the new balance will be positive. 47 | assert_nn(new_balance); 48 | 49 | // Update the new balance. 50 | balance.write(user, new_balance); 51 | 52 | // Send the withdrawal message. 53 | let (message_payload: felt*) = alloc(); 54 | assert message_payload[0] = MESSAGE_WITHDRAW; 55 | assert message_payload[1] = user; 56 | assert message_payload[2] = amount; 57 | send_message_to_l1(to_address=L1_CONTRACT_ADDRESS, payload_size=3, payload=message_payload); 58 | 59 | return (); 60 | } 61 | 62 | @l1_handler 63 | func deposit{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( 64 | from_address: felt, user: felt, amount: felt 65 | ) { 66 | // Make sure the message was sent by the intended L1 contract. 67 | assert from_address = L1_CONTRACT_ADDRESS; 68 | 69 | // Read the current balance. 70 | let (res) = balance.read(user=user); 71 | 72 | // Compute and update the new balance. 73 | tempvar new_balance = res + amount; 74 | balance.write(user, new_balance); 75 | 76 | return (); 77 | } 78 | -------------------------------------------------------------------------------- /starknet_programs/send_message_to_l1.cairo: -------------------------------------------------------------------------------- 1 | %lang starknet 2 | 3 | from starkware.starknet.common.messages import send_message_to_l1 4 | from starkware.cairo.common.alloc import alloc 5 | 6 | 7 | @external 8 | func send_simple_message_to_l1{ 9 | syscall_ptr: felt*, 10 | }(to_address: felt, message: felt) { 11 | let payload: felt* = alloc(); 12 | assert payload[0] = message; 13 | send_message_to_l1(to_address, 1, payload); 14 | return (); 15 | } 16 | -------------------------------------------------------------------------------- /starknet_programs/send_messages_contract_call.cairo: -------------------------------------------------------------------------------- 1 | %lang starknet 2 | 3 | @contract_interface 4 | namespace ISendMessageToL1 { 5 | func send_simple_message_to_l1(to_address: felt, message: felt) { 6 | } 7 | } 8 | 9 | const SEND_MESSAGES_CONTRACT_ADDRESS = 1; //Hardcoded value in test 10 | 11 | @external 12 | func send_sequential_messages{syscall_ptr: felt*, range_check_ptr: felt}(to_address: felt, message1: felt, message2: felt) { 13 | ISendMessageToL1.send_simple_message_to_l1( 14 | contract_address=SEND_MESSAGES_CONTRACT_ADDRESS, 15 | to_address=to_address, 16 | message=message1, 17 | ); 18 | ISendMessageToL1.send_simple_message_to_l1( 19 | contract_address=SEND_MESSAGES_CONTRACT_ADDRESS, 20 | to_address=to_address, 21 | message=message2, 22 | ); 23 | return (); 24 | } 25 | -------------------------------------------------------------------------------- /starknet_programs/starknet_libs_storage.cairo: -------------------------------------------------------------------------------- 1 | %lang starknet 2 | from starkware.starknet.common.storage import normalize_address 3 | 4 | @external 5 | func normalize{range_check_ptr}(address: felt) -> (res: felt) { 6 | return normalize_address(address); 7 | } 8 | -------------------------------------------------------------------------------- /starknet_programs/storage.cairo: -------------------------------------------------------------------------------- 1 | %lang starknet 2 | from starkware.cairo.common.cairo_builtins import HashBuiltin 3 | 4 | @storage_var 5 | func _counter() -> (res: felt) { 6 | } 7 | 8 | @external 9 | func write_and_read{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (res:felt) { 10 | _counter.write(42); 11 | return _counter.read(); 12 | } 13 | -------------------------------------------------------------------------------- /starknet_programs/storage_var_and_constructor.cairo: -------------------------------------------------------------------------------- 1 | %lang starknet 2 | from starkware.cairo.common.cairo_builtins import HashBuiltin 3 | 4 | @storage_var 5 | func constant() -> (res: felt) { 6 | } 7 | 8 | @constructor 9 | func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( 10 | _constant: felt 11 | ) { 12 | constant.write(_constant); 13 | return (); 14 | } 15 | 16 | @external 17 | func get_constant{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr} () -> (res: felt) { 18 | return constant.read(); 19 | } 20 | 21 | @external 22 | func set_constant{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr} ( _constant: felt) -> () { 23 | constant.write(_constant); 24 | return (); 25 | } 26 | 27 | @external 28 | func sum_constant{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr} (n) -> (res: felt) { 29 | let (c) = constant.read(); 30 | return (c + n,); 31 | } 32 | 33 | @external 34 | func mult_constant{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr} (n) -> (res: felt) { 35 | let (c) = constant.read(); 36 | return (c * n,); 37 | } 38 | -------------------------------------------------------------------------------- /starknet_programs/syscalls-lib.cairo: -------------------------------------------------------------------------------- 1 | %lang starknet 2 | 3 | from starkware.cairo.common.cairo_builtins import HashBuiltin 4 | from starkware.starknet.common.syscalls import get_contract_address 5 | 6 | @storage_var 7 | func lib_state() -> (res: felt) { 8 | } 9 | 10 | @l1_handler 11 | func on_event{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr: felt}( 12 | from_address: felt 13 | ) { 14 | lib_state.write(from_address); 15 | 16 | return (); 17 | } 18 | 19 | @external 20 | func stateless_func{syscall_ptr: felt*}(a: felt, b: felt) -> (answer: felt) { 21 | let answer = a * b; 22 | return (answer=answer); 23 | } 24 | 25 | @external 26 | func stateful_func{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr: felt}() { 27 | let (value) = lib_state.read(); 28 | lib_state.write(value + 1); 29 | 30 | return (); 31 | } 32 | 33 | @external 34 | func stateful_get_contract_address{syscall_ptr: felt*}() -> (contract_address: felt) { 35 | let contract_address = get_contract_address(); 36 | 37 | return (contract_address); 38 | } 39 | -------------------------------------------------------------------------------- /tests/integration_tests/account_panic.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use cairo_vm::Felt252; 4 | use starknet_in_rust::{ 5 | core::contract_address::compute_casm_class_hash, 6 | definitions::{block_context::BlockContext, constants::TRANSACTION_VERSION}, 7 | services::api::contract_classes::compiled_class::CompiledClass, 8 | state::{ 9 | cached_state::CachedState, 10 | contract_class_cache::{ContractClassCache, PermanentContractClassCache}, 11 | in_memory_state_reader::InMemoryStateReader, 12 | }, 13 | transaction::{Address, ClassHash, InvokeFunction, Transaction}, 14 | utils::calculate_sn_keccak, 15 | CasmContractClass, 16 | }; 17 | 18 | #[test] 19 | fn account_panic() { 20 | let account_data = include_bytes!("../../starknet_programs/cairo2/account_panic.casm"); 21 | let contract_data = include_bytes!("../../starknet_programs/cairo2/contract_a.casm"); 22 | 23 | let account_contract_class: CasmContractClass = serde_json::from_slice(account_data).unwrap(); 24 | let account_class_hash = ClassHash( 25 | compute_casm_class_hash(&account_contract_class) 26 | .unwrap() 27 | .to_bytes_be(), 28 | ); 29 | 30 | let contract_class: CasmContractClass = serde_json::from_slice(contract_data).unwrap(); 31 | let contract_class_hash_felt = compute_casm_class_hash(&contract_class).unwrap(); 32 | let contract_class_hash = ClassHash::from(contract_class_hash_felt); 33 | 34 | let account_address = Address(1111.into()); 35 | let contract_address = Address(0000.into()); 36 | let nonce = 0.into(); 37 | 38 | let block_context = BlockContext::default(); 39 | 40 | let contract_class_cache = PermanentContractClassCache::default(); 41 | 42 | contract_class_cache.set_contract_class( 43 | account_class_hash, 44 | CompiledClass::Casm { 45 | casm: Arc::new(account_contract_class), 46 | sierra: None, 47 | }, 48 | ); 49 | contract_class_cache.set_contract_class( 50 | contract_class_hash, 51 | CompiledClass::Casm { 52 | casm: Arc::new(contract_class.clone()), 53 | sierra: None, 54 | }, 55 | ); 56 | 57 | let mut state_reader = InMemoryStateReader::default(); 58 | state_reader 59 | .address_to_class_hash_mut() 60 | .insert(account_address.clone(), account_class_hash); 61 | state_reader 62 | .address_to_nonce_mut() 63 | .insert(account_address.clone(), nonce); 64 | state_reader 65 | .address_to_class_hash_mut() 66 | .insert(contract_address.clone(), contract_class_hash); 67 | state_reader 68 | .address_to_nonce_mut() 69 | .insert(contract_address, 1.into()); 70 | let mut state = CachedState::new(Arc::new(state_reader), Arc::new(contract_class_cache)); 71 | 72 | let selector = Felt252::from_bytes_be(&calculate_sn_keccak(b"__execute__")); 73 | 74 | // arguments of contract_a contract 75 | // calldata is a Vec of Call, which is 76 | /* 77 | #[derive(Drop, Serde)] 78 | struct Call { 79 | to: ContractAddress, 80 | selector: felt252, 81 | calldata: Array 82 | } 83 | */ 84 | let selector_contract = &contract_class 85 | .entry_points_by_type 86 | .external 87 | .get(0) 88 | .unwrap() 89 | .selector; 90 | // calldata of contract_a is 1 value. 91 | let calldata: Vec<_> = [ 92 | 1.into(), 93 | contract_class_hash_felt, 94 | Felt252::from(selector_contract), 95 | 1.into(), 96 | 2.into(), 97 | ] 98 | .to_vec(); 99 | 100 | // set up remaining structures 101 | 102 | let invoke = InvokeFunction::new( 103 | account_address, 104 | selector, 105 | Default::default(), 106 | *TRANSACTION_VERSION, 107 | calldata, 108 | vec![], 109 | *block_context.starknet_os_config().chain_id(), 110 | Some(0.into()), 111 | ) 112 | .unwrap(); 113 | 114 | let tx = Transaction::InvokeFunction(invoke); 115 | let exec_info = tx 116 | .execute( 117 | &mut state, 118 | &block_context, 119 | u128::MAX, 120 | #[cfg(feature = "cairo-native")] 121 | None, 122 | ) 123 | .expect("failed to invoke"); 124 | let call_info = exec_info.call_info.as_ref().unwrap(); 125 | 126 | assert_eq!(exec_info.revert_error, None); 127 | 128 | // 482670963043u128 == 'panic' 129 | assert_eq!(call_info.retdata[0], 482670963043u128.into()); 130 | assert!(call_info.failure_flag); 131 | } 132 | -------------------------------------------------------------------------------- /tests/integration_tests/complex_contracts/amm_contracts/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod amm; 2 | pub mod amm_proxy; 3 | -------------------------------------------------------------------------------- /tests/integration_tests/complex_contracts/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod amm_contracts; 2 | pub mod erc20; 3 | pub mod nft; 4 | pub mod utils; 5 | -------------------------------------------------------------------------------- /tests/integration_tests/complex_contracts/nft/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod erc721; 2 | -------------------------------------------------------------------------------- /tests/integration_tests/delegate_call.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings)] 2 | 3 | use cairo_vm::Felt252; 4 | use starknet_in_rust::services::api::contract_classes::compiled_class::CompiledClass; 5 | use starknet_in_rust::transaction::ClassHash; 6 | use starknet_in_rust::EntryPointType; 7 | use starknet_in_rust::{ 8 | definitions::{block_context::BlockContext, constants::TRANSACTION_VERSION}, 9 | execution::{ 10 | execution_entry_point::ExecutionEntryPoint, CallType, TransactionExecutionContext, 11 | }, 12 | services::api::contract_classes::deprecated_contract_class::ContractClass, 13 | state::{ 14 | cached_state::CachedState, 15 | contract_class_cache::{ContractClassCache, PermanentContractClassCache}, 16 | in_memory_state_reader::InMemoryStateReader, 17 | ExecutionResourcesManager, 18 | }, 19 | transaction::Address, 20 | }; 21 | use std::{path::PathBuf, sync::Arc}; 22 | 23 | #[test] 24 | fn delegate_call() { 25 | //* -------------------------------------------- 26 | //* Create state reader with class hash data 27 | //* -------------------------------------------- 28 | 29 | let contract_class_cache = PermanentContractClassCache::default(); 30 | let nonce = Felt252::ZERO; 31 | 32 | // Add get_number.cairo contract to the state 33 | 34 | let path = PathBuf::from("starknet_programs/get_number.json"); 35 | let contract_class = ContractClass::from_path(path).unwrap(); 36 | 37 | let address = Address(Felt252::ONE); // const CONTRACT_ADDRESS = 1; 38 | let class_hash = ClassHash([2; 32]); 39 | 40 | contract_class_cache.set_contract_class( 41 | class_hash, 42 | CompiledClass::Deprecated(Arc::new(contract_class)), 43 | ); 44 | let mut state_reader = InMemoryStateReader::default(); 45 | state_reader 46 | .address_to_class_hash_mut() 47 | .insert(address.clone(), class_hash); 48 | state_reader.address_to_nonce_mut().insert(address, nonce); 49 | 50 | // --------------------------------------------------------- 51 | // Create program and entry point types for contract class 52 | // --------------------------------------------------------- 53 | 54 | let path = PathBuf::from("starknet_programs/delegate_call.json"); 55 | let contract_class = ContractClass::from_path(path).unwrap(); 56 | let entry_points_by_type = contract_class.entry_points_by_type().clone(); 57 | 58 | // External entry point, delegate_call function delegate.cairo:L13 59 | let test_delegate_call_selector = *entry_points_by_type 60 | .get(&EntryPointType::External) 61 | .unwrap() 62 | .get(0) 63 | .unwrap() 64 | .selector(); 65 | 66 | // ------------ contract data -------------------- 67 | 68 | let address = Address(1111.into()); 69 | let class_hash = ClassHash([1; 32]); 70 | 71 | contract_class_cache.set_contract_class( 72 | class_hash, 73 | CompiledClass::Deprecated(Arc::new(contract_class)), 74 | ); 75 | state_reader 76 | .address_to_class_hash_mut() 77 | .insert(address.clone(), class_hash); 78 | state_reader 79 | .address_to_nonce_mut() 80 | .insert(address.clone(), nonce); 81 | 82 | //* --------------------------------------- 83 | //* Create state with previous data 84 | //* --------------------------------------- 85 | 86 | let mut state = CachedState::new(Arc::new(state_reader), Arc::new(contract_class_cache)); 87 | 88 | //* ------------------------------------ 89 | //* Create execution entry point 90 | //* ------------------------------------ 91 | 92 | let calldata = [].to_vec(); 93 | let caller_address = Address(0000.into()); 94 | let entry_point_type = EntryPointType::External; 95 | 96 | let exec_entry_point = ExecutionEntryPoint::new( 97 | address, 98 | calldata, 99 | test_delegate_call_selector, 100 | caller_address, 101 | entry_point_type, 102 | Some(CallType::Delegate), 103 | Some(class_hash), 104 | 0, 105 | ); 106 | 107 | //* -------------------- 108 | //* Execute contract 109 | //* --------------------- 110 | let block_context = BlockContext::default(); 111 | let mut tx_execution_context = TransactionExecutionContext::new( 112 | Address(0.into()), 113 | Felt252::ZERO, 114 | Vec::new(), 115 | Default::default(), 116 | 10.into(), 117 | block_context.invoke_tx_max_n_steps(), 118 | *TRANSACTION_VERSION, 119 | ); 120 | let mut resources_manager = ExecutionResourcesManager::default(); 121 | 122 | assert!(exec_entry_point 123 | .execute( 124 | &mut state, 125 | &block_context, 126 | &mut resources_manager, 127 | &mut tx_execution_context, 128 | false, 129 | block_context.invoke_tx_max_n_steps(), 130 | #[cfg(feature = "cairo-native")] 131 | None, 132 | ) 133 | .is_ok()); 134 | } 135 | -------------------------------------------------------------------------------- /tests/integration_tests/delegate_l1_handler.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings)] 2 | 3 | use cairo_vm::Felt252; 4 | use starknet_in_rust::services::api::contract_classes::compiled_class::CompiledClass; 5 | use starknet_in_rust::{ 6 | definitions::{block_context::BlockContext, constants::TRANSACTION_VERSION}, 7 | execution::{ 8 | execution_entry_point::ExecutionEntryPoint, CallType, TransactionExecutionContext, 9 | }, 10 | services::api::contract_classes::deprecated_contract_class::ContractClass, 11 | state::{ 12 | cached_state::CachedState, 13 | contract_class_cache::{ContractClassCache, PermanentContractClassCache}, 14 | in_memory_state_reader::InMemoryStateReader, 15 | ExecutionResourcesManager, 16 | }, 17 | transaction::Address, 18 | }; 19 | use starknet_in_rust::{transaction::ClassHash, EntryPointType}; 20 | use std::{path::PathBuf, sync::Arc}; 21 | 22 | #[test] 23 | fn delegate_l1_handler() { 24 | //* -------------------------------------------- 25 | //* Create state reader with class hash data 26 | //* -------------------------------------------- 27 | let contract_class_cache = PermanentContractClassCache::default(); 28 | let nonce = Felt252::ZERO; 29 | 30 | // Add get_number.cairo contract to the state 31 | 32 | let path = PathBuf::from("starknet_programs/get_number_l1_handler.json"); 33 | let contract_class = ContractClass::from_path(path).unwrap(); 34 | 35 | let address = Address(Felt252::ONE); // const CONTRACT_ADDRESS = 1; 36 | let class_hash: ClassHash = ClassHash([2; 32]); 37 | 38 | contract_class_cache.set_contract_class( 39 | class_hash, 40 | CompiledClass::Deprecated(Arc::new(contract_class)), 41 | ); 42 | let mut state_reader = InMemoryStateReader::default(); 43 | state_reader 44 | .address_to_class_hash_mut() 45 | .insert(address.clone(), class_hash); 46 | state_reader.address_to_nonce_mut().insert(address, nonce); 47 | 48 | // --------------------------------------------------------- 49 | // Create program and entry point types for contract class 50 | // --------------------------------------------------------- 51 | 52 | let path = PathBuf::from("starknet_programs/delegate_l1_handler.json"); 53 | let contract_class = ContractClass::from_path(path).unwrap(); 54 | 55 | // External entry point, delegate_call function delegate.cairo:L13 56 | let test_delegate_l1_handler_selector = Felt252::from_dec_str( 57 | "517623934924705024901038305335656287487647971342355715053765242809192309107", 58 | ) 59 | .unwrap(); 60 | 61 | // ------------ contract data -------------------- 62 | 63 | let address = Address(1111.into()); 64 | let class_hash = ClassHash([1; 32]); 65 | 66 | contract_class_cache.set_contract_class( 67 | class_hash, 68 | CompiledClass::Deprecated(Arc::new(contract_class)), 69 | ); 70 | state_reader 71 | .address_to_class_hash_mut() 72 | .insert(address.clone(), class_hash); 73 | state_reader 74 | .address_to_nonce_mut() 75 | .insert(address.clone(), nonce); 76 | 77 | //* --------------------------------------- 78 | //* Create state with previous data 79 | //* --------------------------------------- 80 | 81 | let mut state = CachedState::new(Arc::new(state_reader), Arc::new(contract_class_cache)); 82 | 83 | //* ------------------------------------ 84 | //* Create execution entry point 85 | //* ------------------------------------ 86 | 87 | let calldata = [].to_vec(); 88 | let caller_address = Address(0000.into()); 89 | let entry_point_type = EntryPointType::External; 90 | 91 | let exec_entry_point = ExecutionEntryPoint::new( 92 | address, 93 | calldata, 94 | test_delegate_l1_handler_selector, 95 | caller_address, 96 | entry_point_type, 97 | Some(CallType::Delegate), 98 | Some(class_hash), 99 | 0, 100 | ); 101 | 102 | //* -------------------- 103 | //* Execute contract 104 | //* --------------------- 105 | let block_context = BlockContext::default(); 106 | let mut tx_execution_context = TransactionExecutionContext::new( 107 | Address(0.into()), 108 | Felt252::ZERO, 109 | Vec::new(), 110 | Default::default(), 111 | 10.into(), 112 | block_context.invoke_tx_max_n_steps(), 113 | *TRANSACTION_VERSION, 114 | ); 115 | let mut resources_manager = ExecutionResourcesManager::default(); 116 | assert!(exec_entry_point 117 | .execute( 118 | &mut state, 119 | &block_context, 120 | &mut resources_manager, 121 | &mut tx_execution_context, 122 | false, 123 | block_context.invoke_tx_max_n_steps(), 124 | #[cfg(feature = "cairo-native")] 125 | None, 126 | ) 127 | .is_ok()); 128 | } 129 | -------------------------------------------------------------------------------- /tests/integration_tests/internal_calls.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings)] 2 | 3 | use cairo_vm::Felt252; 4 | use starknet_in_rust::{ 5 | definitions::{block_context::BlockContext, constants::TRANSACTION_VERSION}, 6 | execution::{ 7 | execution_entry_point::ExecutionEntryPoint, CallType, TransactionExecutionContext, 8 | }, 9 | services::api::contract_classes::{ 10 | compiled_class::CompiledClass, deprecated_contract_class::ContractClass, 11 | }, 12 | state::{ 13 | cached_state::CachedState, 14 | contract_class_cache::{ContractClassCache, PermanentContractClassCache}, 15 | in_memory_state_reader::InMemoryStateReader, 16 | state_cache::StorageEntry, 17 | ExecutionResourcesManager, 18 | }, 19 | transaction::{Address, ClassHash}, 20 | utils::calculate_sn_keccak, 21 | EntryPointType, 22 | }; 23 | use std::sync::Arc; 24 | 25 | #[test] 26 | fn test_internal_calls() { 27 | let contract_class = ContractClass::from_path("starknet_programs/internal_calls.json") 28 | .expect("Could not load contract from JSON"); 29 | 30 | let block_context = BlockContext::default(); 31 | let mut tx_execution_context = TransactionExecutionContext::create_for_testing( 32 | Address(0.into()), 33 | 0.into(), 34 | block_context.invoke_tx_max_n_steps(), 35 | *TRANSACTION_VERSION, 36 | ); 37 | 38 | let address = Address(1111.into()); 39 | let class_hash: ClassHash = ClassHash([1; 32]); 40 | let nonce = Felt252::ZERO; 41 | let storage_entry: StorageEntry = (address.clone(), [1; 32]); 42 | let storage = Felt252::ZERO; 43 | 44 | let mut state_reader = InMemoryStateReader::default(); 45 | state_reader 46 | .address_to_class_hash_mut() 47 | .insert(address.clone(), class_hash); 48 | state_reader.address_to_nonce_mut().insert(address, nonce); 49 | state_reader 50 | .address_to_storage_mut() 51 | .insert(storage_entry, storage); 52 | 53 | let mut state = CachedState::new( 54 | Arc::new(state_reader), 55 | Arc::new({ 56 | let cache = PermanentContractClassCache::default(); 57 | cache.set_contract_class( 58 | ClassHash([0x01; 32]), 59 | CompiledClass::Deprecated(Arc::new(contract_class)), 60 | ); 61 | cache 62 | }), 63 | ); 64 | 65 | let entry_point_selector = Felt252::from_bytes_be(&calculate_sn_keccak(b"a")); 66 | let entry_point = ExecutionEntryPoint::new( 67 | Address(1111.into()), 68 | vec![], 69 | entry_point_selector, 70 | Address(1111.into()), 71 | EntryPointType::External, 72 | CallType::Delegate.into(), 73 | Some(ClassHash([1; 32])), 74 | 0, 75 | ); 76 | 77 | let mut resources_manager = ExecutionResourcesManager::default(); 78 | 79 | let call_info = entry_point 80 | .execute( 81 | &mut state, 82 | &block_context, 83 | &mut resources_manager, 84 | &mut tx_execution_context, 85 | false, 86 | block_context.invoke_tx_max_n_steps(), 87 | #[cfg(feature = "cairo-native")] 88 | None, 89 | ) 90 | .expect("Could not execute contract"); 91 | 92 | let call_info = call_info.call_info.unwrap(); 93 | 94 | assert_eq!(call_info.internal_calls.len(), 1); 95 | assert_eq!(call_info.internal_calls[0].internal_calls.len(), 1); 96 | assert!(call_info.internal_calls[0].internal_calls[0] 97 | .internal_calls 98 | .is_empty()); 99 | } 100 | -------------------------------------------------------------------------------- /tests/integration_tests/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod account_panic; 2 | pub mod cairo_1_syscalls; 3 | pub mod cairo_native; 4 | pub mod complex_contracts; 5 | pub mod delegate_call; 6 | pub mod delegate_l1_handler; 7 | pub mod deploy_account; 8 | pub mod fibonacci; 9 | pub mod increase_balance; 10 | pub mod internal_calls; 11 | pub mod internals; 12 | pub mod multi_syscall_test; 13 | pub mod storage; 14 | pub mod syscalls; 15 | pub mod syscalls_errors; 16 | pub mod yas_bench_test; 17 | -------------------------------------------------------------------------------- /tests/tests.rs: -------------------------------------------------------------------------------- 1 | //! To avoid generating lot of test executables, this is the single entry point of all tests. 2 | 3 | pub mod integration_tests; 4 | --------------------------------------------------------------------------------