diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 535cb4a78..8c35eaf2e 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -55,7 +55,7 @@ jobs: # Python Setup and dependencies installation - uses: actions/setup-python@v4 with: - python-version: '3.9.13' + python-version: "3.9.13" - name: Load cached Poetry installation id: cached-poetry uses: actions/cache@v3 @@ -78,8 +78,7 @@ jobs: uses: actions/cache@v3 with: path: .venv - key: - venv-${{ runner.os }}-${{ hashFiles('./lib/kakarot/poetry.lock') }} + key: venv-${{ runner.os }}-${{ hashFiles('./lib/kakarot/poetry.lock') }} # benchmark rpc - name: install benchmark projects @@ -95,9 +94,9 @@ jobs: - name: Compare result uses: benchmark-action/github-action-benchmark@v1 with: - tool: 'customBiggerIsBetter' + tool: "customBiggerIsBetter" output-file-path: ./benchmarking/reports/metrics.json - alert-threshold: '120%' + alert-threshold: "120%" github-token: ${{ secrets.GITHUB_TOKEN }} fail-on-alert: true summary-always: ${{ github.ref == 'refs/heads/main' }} diff --git a/.github/workflows/kakarot_rpc.yml b/.github/workflows/kakarot_rpc.yml index f34daf1bb..0dd4184f8 100644 --- a/.github/workflows/kakarot_rpc.yml +++ b/.github/workflows/kakarot_rpc.yml @@ -53,8 +53,7 @@ jobs: labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max - outputs: - type=image,name=${{ env.REGISTRY_IMAGE + outputs: type=image,name=${{ env.REGISTRY_IMAGE }},name-canonical=true,push=true - name: Export digest diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml deleted file mode 100644 index da2225b72..000000000 --- a/.github/workflows/linters.yml +++ /dev/null @@ -1,54 +0,0 @@ -name: linters - -on: - workflow_call: - -jobs: - check: - runs-on: ubuntu-latest - timeout-minutes: 30 - steps: - - uses: actions/checkout@v3 - - uses: actions-rs/toolchain@v1 - with: - toolchain: 1.73.0 - profile: minimal - override: true - - uses: Swatinem/rust-cache@v2 - - uses: actions-rs/cargo@v1 - with: - command: check - - fmt: - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - uses: actions/checkout@v3 - - uses: actions-rs/toolchain@v1 - with: - toolchain: 1.73.0 - profile: minimal - override: true - components: rustfmt - - uses: Swatinem/rust-cache@v2 - - uses: actions-rs/cargo@v1 - with: - command: fmt - args: --all -- --check - - clippy: - runs-on: ubuntu-latest - timeout-minutes: 30 - steps: - - uses: actions/checkout@v3 - - uses: actions-rs/toolchain@v1 - with: - toolchain: 1.73.0 - profile: minimal - override: true - components: clippy - - uses: Swatinem/rust-cache@v2 - - uses: actions-rs/cargo@v1 - with: - command: clippy - args: --workspace --all-features --all-targets -- -D warnings diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 37ed794b8..a2869c745 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -3,20 +3,15 @@ name: Workflow - Pull Request on: [pull_request] -jobs: - dump: - name: Dump katana state - uses: ./.github/workflows/dump.yml +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +jobs: spell_check: name: Spell check uses: ./.github/workflows/spell_check.yml - linters: - name: Linters - uses: ./.github/workflows/linters.yml - tests: name: Rust tests uses: ./.github/workflows/test.yml - needs: dump diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 338a4b72e..2e866169f 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -5,11 +5,11 @@ on: push: branches: [main] -jobs: - dump: - name: Dump katana state - uses: ./.github/workflows/dump.yml +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +jobs: spell_check: name: Spell check uses: ./.github/workflows/spell_check.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d4d628359..03acc3578 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,7 +13,7 @@ jobs: uses: actions-rs/toolchain@v1 with: profile: minimal - components: llvm-tools-preview + components: llvm-tools-preview, rustfmt, clippy override: true toolchain: 1.73.0 - name: Retrieve cached dependencies @@ -21,7 +21,6 @@ jobs: - name: Setup coverage env uses: taiki-e/install-action@cargo-llvm-cov # nextest setup - - uses: taiki-e/install-action@cargo-llvm-cov - uses: taiki-e/install-action@nextest # Load lib submodules - name: Load submodules @@ -30,11 +29,48 @@ jobs: with: path: ./lib/ key: ${{ runner.os }}-submodules + # Install Foundry + - name: install foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: nightly + # Install Python + - name: Set up Python 3.9 + uses: actions/setup-python@v4 + with: + python-version: 3.9 + - name: Load cached Poetry installation + id: cached-poetry + uses: actions/cache@v3 + with: + path: ~/.local + key: poetry-${{ runner.os }} + - name: Install Poetry + if: steps.cached-poetry.outputs.cache-hit != 'true' + uses: snok/install-poetry@v1 + with: + virtualenvs-create: true + virtualenvs-in-project: true + installer-parallel: true + - name: Load cached venv + id: cached-poetry-dependencies + uses: actions/cache@v3 + with: + path: .venv + key: venv-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }} + - name: Setup the Kakarot submodule + run: make setup + # Lint + - name: Lint + run: | + cargo check && + cargo fmt --all -- --check && + cargo clippy --workspace --all-features --all-targets -- -D warnings # Create dump - name: Create dump - run: make build-kakarot && make dump-katana + run: ./scripts/make_with_env.sh && make dump-katana - name: Generate code coverage - run: ./scripts/make_with_env.sh test-coverage + run: make test-coverage - name: Upload coverage to Codecov uses: codecov/codecov-action@v3 with: diff --git a/.gitignore b/.gitignore index f51d74bae..63317a701 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,5 @@ broadcast # ignore genesis.json .hive + +artifacts/ diff --git a/.gitmodules b/.gitmodules index a52faf3a2..cb463ad2b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,3 @@ [submodule "kakarot"] - path = lib/kakarot - url = https://github.com/kkrt-labs/kakarot.git -[submodule "lib/forge-std"] - path = lib/forge-std - url = https://github.com/foundry-rs/forge-std -[submodule "lib/madara"] - path = lib/madara - url = https://github.com/keep-starknet-strange/madara +path = lib/kakarot +url = https://github.com/kkrt-labs/kakarot.git diff --git a/Cargo.lock b/Cargo.lock index a2cab55d4..a07ab17be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -92,82 +92,17 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" -[[package]] -name = "alloy-chains" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c18b3ecf1746f0eac255374bdf899dd217dd1b301e4a3f146592234243e1bc66" -dependencies = [ - "num_enum", - "serde", - "strum 0.25.0", -] - -[[package]] -name = "alloy-json-abi" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63c9319ad8b2b623c6a3ac15899f8ffb71479224762dbaedc385c16efbb6cfe3" -dependencies = [ - "alloy-primitives", - "alloy-sol-type-parser", - "serde", - "serde_json", -] - -[[package]] -name = "alloy-primitives" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0628ec0ba5b98b3370bb6be17b12f23bfce8ee4ad83823325a20546d9b03b78" -dependencies = [ - "alloy-rlp", - "bytes", - "cfg-if", - "const-hex", - "derive_more", - "getrandom", - "hex-literal", - "itoa", - "proptest", - "rand", - "ruint", - "serde", - "tiny-keccak", -] - [[package]] name = "alloy-rlp" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc0fac0fc16baf1f63f78b47c3d24718f3619b0714076f6a02957d808d52cbef" dependencies = [ - "alloy-rlp-derive", "arrayvec", "bytes", "smol_str", ] -[[package]] -name = "alloy-rlp-derive" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0391754c09fab4eae3404d19d0d297aa1c670c1775ab51d8a5312afeca23157" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.39", -] - -[[package]] -name = "alloy-sol-type-parser" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81c61ccc29e7c58bf16a2f780898852348183f58b127bde03ced6d07ad544787" -dependencies = [ - "winnow", -] - [[package]] name = "android-tzdata" version = "0.1.1" @@ -2520,12 +2455,12 @@ checksum = "1a5344eea9b20effb5efeaad29418215c4d27017639fd1f908260f59cbbd226e" dependencies = [ "ethers-addressbook", "ethers-contract", - "ethers-core", - "ethers-etherscan", + "ethers-core 2.0.11 (registry+https://github.com/rust-lang/crates.io-index)", + "ethers-etherscan 2.0.11 (registry+https://github.com/rust-lang/crates.io-index)", "ethers-middleware", "ethers-providers", "ethers-signers", - "ethers-solc", + "ethers-solc 2.0.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2534,7 +2469,7 @@ version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c405f24ea3a517899ba7985385c43dc4a7eb1209af3b1e0a1a32d7dcc7f8d09" dependencies = [ - "ethers-core", + "ethers-core 2.0.11 (registry+https://github.com/rust-lang/crates.io-index)", "once_cell", "serde", "serde_json", @@ -2549,7 +2484,7 @@ dependencies = [ "const-hex", "ethers-contract-abigen", "ethers-contract-derive", - "ethers-core", + "ethers-core 2.0.11 (registry+https://github.com/rust-lang/crates.io-index)", "ethers-providers", "futures-util", "once_cell", @@ -2568,8 +2503,8 @@ dependencies = [ "Inflector", "const-hex", "dunce", - "ethers-core", - "ethers-etherscan", + "ethers-core 2.0.11 (registry+https://github.com/rust-lang/crates.io-index)", + "ethers-etherscan 2.0.11 (registry+https://github.com/rust-lang/crates.io-index)", "eyre", "prettyplease", "proc-macro2", @@ -2592,7 +2527,7 @@ dependencies = [ "Inflector", "const-hex", "ethers-contract-abigen", - "ethers-core", + "ethers-core 2.0.11 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2", "quote", "serde_json", @@ -2629,6 +2564,32 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "ethers-core" +version = "2.0.11" +source = "git+https://github.com/gakonst/ethers-rs#546ea029362a7502365667c6f99fac92ad0aeb9f" +dependencies = [ + "arrayvec", + "bytes", + "chrono", + "const-hex", + "elliptic-curve", + "ethabi", + "generic-array", + "k256", + "num_enum", + "open-fastrlp", + "rand", + "rlp", + "serde", + "serde_json", + "strum 0.25.0", + "tempfile", + "thiserror", + "tiny-keccak", + "unicode-xid", +] + [[package]] name = "ethers-etherscan" version = "2.0.11" @@ -2636,7 +2597,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abbac2c890bdbe0f1b8e549a53b00e2c4c1de86bb077c1094d1f38cdf9381a56" dependencies = [ "chrono", - "ethers-core", + "ethers-core 2.0.11 (registry+https://github.com/rust-lang/crates.io-index)", + "reqwest", + "semver 1.0.20", + "serde", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] +name = "ethers-etherscan" +version = "2.0.11" +source = "git+https://github.com/gakonst/ethers-rs#546ea029362a7502365667c6f99fac92ad0aeb9f" +dependencies = [ + "chrono", + "ethers-core 2.0.11 (git+https://github.com/gakonst/ethers-rs)", "reqwest", "semver 1.0.20", "serde", @@ -2654,8 +2630,8 @@ dependencies = [ "async-trait", "auto_impl", "ethers-contract", - "ethers-core", - "ethers-etherscan", + "ethers-core 2.0.11 (registry+https://github.com/rust-lang/crates.io-index)", + "ethers-etherscan 2.0.11 (registry+https://github.com/rust-lang/crates.io-index)", "ethers-providers", "ethers-signers", "futures-channel", @@ -2684,7 +2660,7 @@ dependencies = [ "bytes", "const-hex", "enr", - "ethers-core", + "ethers-core 2.0.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures-core", "futures-timer", "futures-util", @@ -2721,7 +2697,7 @@ dependencies = [ "const-hex", "elliptic-curve", "eth-keystore", - "ethers-core", + "ethers-core 2.0.11 (registry+https://github.com/rust-lang/crates.io-index)", "rand", "sha2", "thiserror", @@ -2738,7 +2714,7 @@ dependencies = [ "const-hex", "dirs", "dunce", - "ethers-core", + "ethers-core 2.0.11 (registry+https://github.com/rust-lang/crates.io-index)", "glob", "home", "md-5", @@ -2760,6 +2736,40 @@ dependencies = [ "yansi 0.5.1", ] +[[package]] +name = "ethers-solc" +version = "2.0.11" +source = "git+https://github.com/gakonst/ethers-rs#546ea029362a7502365667c6f99fac92ad0aeb9f" +dependencies = [ + "cfg-if", + "const-hex", + "dirs", + "dunce", + "ethers-core 2.0.11 (git+https://github.com/gakonst/ethers-rs)", + "futures-util", + "glob", + "home", + "md-5", + "num_cpus", + "once_cell", + "path-slash", + "rayon", + "regex", + "semver 1.0.20", + "serde", + "serde_json", + "sha2", + "solang-parser", + "svm-rs", + "svm-rs-builds", + "thiserror", + "tiny-keccak", + "tokio", + "tracing", + "walkdir", + "yansi 0.5.1", +] + [[package]] name = "event-listener" version = "2.5.3" @@ -2896,86 +2906,32 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "foundry-block-explorers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc59cf4c18884c485b20f376e98946774b76f3b8e2e71e4f35723ffb34b8544" -dependencies = [ - "alloy-chains", - "alloy-json-abi", - "alloy-primitives", - "foundry-compilers", - "reqwest", - "semver 1.0.20", - "serde", - "serde_json", - "thiserror", - "tracing", -] - -[[package]] -name = "foundry-compilers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dcfb3af0dd69f2989ab2311f2c97fdd470227d3c9f657be04092572a3a1db60" -dependencies = [ - "alloy-json-abi", - "alloy-primitives", - "cfg-if", - "const-hex", - "dirs", - "dunce", - "glob", - "home", - "md-5", - "num_cpus", - "once_cell", - "path-slash", - "rayon", - "regex", - "semver 1.0.20", - "serde", - "serde_json", - "sha2", - "solang-parser", - "svm-rs", - "svm-rs-builds", - "thiserror", - "tiny-keccak", - "tokio", - "tracing", - "walkdir", - "yansi 0.5.1", -] - [[package]] name = "foundry-config" version = "0.2.0" -source = "git+https://github.com/foundry-rs/foundry?branch=master#a0d19114127d825fa2b48f9ed3a553832a765966" +source = "git+https://github.com/foundry-rs/foundry?branch=master#9c339c135f6b03d04873f489795699e5a2df457f" dependencies = [ "Inflector", - "alloy-chains", - "alloy-primitives", "dirs-next", + "ethers-core 2.0.11 (git+https://github.com/gakonst/ethers-rs)", + "ethers-etherscan 2.0.11 (git+https://github.com/gakonst/ethers-rs)", + "ethers-solc 2.0.11 (git+https://github.com/gakonst/ethers-rs)", "eyre", "figment", - "foundry-block-explorers", - "foundry-compilers", "globset", "number_prefix", "once_cell", + "open-fastrlp", "path-slash", "regex", "reqwest", - "revm-primitives 1.3.0", "semver 1.0.20", "serde", "serde_json", "serde_regex", "thiserror", - "toml 0.8.8", - "toml_edit 0.21.0", + "toml 0.7.8", + "toml_edit 0.19.15", "tracing", "walkdir", ] @@ -4985,7 +4941,7 @@ dependencies = [ "dotenv", "env_logger", "ethers", - "ethers-solc", + "ethers-solc 2.0.11 (registry+https://github.com/rust-lang/crates.io-index)", "eyre", "foundry-config", "futures", @@ -5010,6 +4966,8 @@ dependencies = [ "serde_json", "serde_with 2.3.3", "starknet", + "starknet-abigen-macros", + "starknet-abigen-parser", "starknet-crypto 0.6.1", "thiserror", "tokio", @@ -5030,7 +4988,7 @@ dependencies = [ "dojo-test-utils", "dotenv", "ethers", - "ethers-solc", + "ethers-solc 2.0.11 (registry+https://github.com/rust-lang/crates.io-index)", "eyre", "foundry-config", "futures", @@ -6230,8 +6188,6 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" dependencies = [ - "bit-set", - "bit-vec", "bitflags 2.4.1", "lazy_static", "num-traits 0.2.17", @@ -6239,17 +6195,9 @@ dependencies = [ "rand_chacha", "rand_xorshift", "regex-syntax 0.8.2", - "rusty-fork", - "tempfile", "unarray", ] -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - [[package]] name = "quote" version = "1.0.33" @@ -6474,7 +6422,7 @@ source = "git+https://github.com/paradigmxyz/reth.git?tag=v0.1.0-alpha.10#1b16d8 dependencies = [ "bytes", "codecs-derive", - "revm-primitives 1.1.2", + "revm-primitives", ] [[package]] @@ -6487,7 +6435,7 @@ dependencies = [ "crc", "crunchy", "derive_more", - "ethers-core", + "ethers-core 2.0.11 (registry+https://github.com/rust-lang/crates.io-index)", "fixed-hash", "hex", "hex-literal", @@ -6500,7 +6448,7 @@ dependencies = [ "reth-codecs", "reth-rlp", "reth-rlp-derive", - "revm-primitives 1.1.2", + "revm-primitives", "ruint", "secp256k1", "serde", @@ -6530,7 +6478,7 @@ dependencies = [ "c-kzg 0.1.0 (git+https://github.com/ethereum/c-kzg-4844?rev=f5f6f863d475847876a2bd5ee252058d37c3a15d)", "ethereum-types", "reth-rlp-derive", - "revm-primitives 1.1.2", + "revm-primitives", ] [[package]] @@ -6592,22 +6540,6 @@ dependencies = [ "sha3", ] -[[package]] -name = "revm-primitives" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51187b852d9e458816a2e19c81f1dd6c924077e1a8fccd16e4f044f865f299d7" -dependencies = [ - "alloy-primitives", - "alloy-rlp", - "auto_impl", - "bitflags 2.4.1", - "bitvec", - "enumn", - "hashbrown 0.14.2", - "hex", -] - [[package]] name = "rfc6979" version = "0.4.0" @@ -6851,18 +6783,6 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" -[[package]] -name = "rusty-fork" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" -dependencies = [ - "fnv", - "quick-error", - "tempfile", - "wait-timeout", -] - [[package]] name = "ryu" version = "1.0.15" @@ -7619,6 +7539,29 @@ dependencies = [ "starknet-signers", ] +[[package]] +name = "starknet-abigen-macros" +version = "0.1.0" +source = "git+https://github.com/glihm/starknet-abigen-rs?tag=v0.1.4-beta1#b3f8d4f695c078900d8e9bfeda3748619bea4ce6" +dependencies = [ + "anyhow", + "proc-macro2", + "quote", + "serde_json", + "starknet", + "starknet-abigen-parser", + "syn 2.0.39", +] + +[[package]] +name = "starknet-abigen-parser" +version = "0.1.0" +source = "git+https://github.com/glihm/starknet-abigen-rs?tag=v0.1.4-beta1#b3f8d4f695c078900d8e9bfeda3748619bea4ce6" +dependencies = [ + "starknet", + "thiserror", +] + [[package]] name = "starknet-accounts" version = "0.6.0" @@ -8237,6 +8180,7 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" dependencies = [ + "indexmap 2.1.0", "serde", "serde_spanned", "toml_datetime", @@ -8249,7 +8193,6 @@ version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" dependencies = [ - "indexmap 2.1.0", "serde", "serde_spanned", "toml_datetime", @@ -8680,15 +8623,6 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" -[[package]] -name = "wait-timeout" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" -dependencies = [ - "libc", -] - [[package]] name = "walkdir" version = "2.4.0" diff --git a/Cargo.toml b/Cargo.toml index 1114e57ef..9622d3267 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,9 @@ starknet = "0.7.0" starknet-crypto = "0.6.1" starknet_api = { git = "https://github.com/starkware-libs/starknet-api", rev = "ecc9b6946ef13003da202838e4124a9ad2efabb0" } +starknet-abigen-parser = { git = "https://github.com/glihm/starknet-abigen-rs", tag = "v0.1.4-beta1" } +starknet-abigen-macros = { git = "https://github.com/glihm/starknet-abigen-rs", tag = "v0.1.4-beta1" } + # Ethereum dependencies ethers = "2.0.9" ethers-solc = "2.0.9" diff --git a/Makefile b/Makefile index 5ce9e4ac1..8ea0a6c9b 100644 --- a/Makefile +++ b/Makefile @@ -8,20 +8,13 @@ override STARKNET_NETWORK = katana endif setup: .gitmodules + chmod +x ./scripts/extract_abi.sh git submodule update --init --recursive - cd lib/kakarot && make setup - -build-kakarot: - cd lib/kakarot && make build && make build-sol + cd lib/kakarot && make setup && make build && make build-sol && cd .. + ./scripts/extract_abi.sh deploy-kakarot: - cd lib/kakarot && STARKNET_NETWORK=$(STARKNET_NETWORK) poetry run python ./scripts/deploy_kakarot.py - -build-and-deploy-kakarot: build-kakarot deploy-kakarot - -# run devnet -devnet: - docker run --rm -it -p 5050:5050 -v $(PWD)/deployments:/app/kakarot/deployments -e STARKNET_NETWORK=katana ghcr.io/kkrt-labs/kakarot/katana:latest + cd lib/kakarot && STARKNET_NETWORK=$(STARKNET_NETWORK) poetry run python ./scripts/deploy_kakarot.py && cd .. run-dev: KAKAROT_ADDRESS=$(shell jq -r '.kakarot.address' ./lib/kakarot/deployments/$(STARKNET_NETWORK)/deployments.json) RUST_LOG=trace cargo run -p kakarot-rpc diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index f4e272e08..dc12f7ddb 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -27,6 +27,10 @@ starknet-crypto = { workspace = true } thiserror = "1.0.38" url = { workspace = true } +starknet-abigen-parser = { workspace = true } +starknet-abigen-macros = { workspace = true } + + futures = "0.3.26" num-bigint = "0.4.3" serde = { version = "1.0" } diff --git a/crates/core/src/client/errors.rs b/crates/core/src/client/errors.rs index 98f1e01bc..d800ee87d 100644 --- a/crates/core/src/client/errors.rs +++ b/crates/core/src/client/errors.rs @@ -6,6 +6,8 @@ use thiserror::Error; use super::helpers::DataDecodingError; use crate::models::ConversionError; +use starknet_abigen_parser::cairo_types::Error as AbigenError; + /// List of JSON-RPC error codes from ETH rpc spec. /// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1474.md #[derive(Debug, Copy, PartialEq, Eq, Clone)] @@ -50,6 +52,9 @@ pub enum EthApiError { /// Request to the Starknet provider failed. #[error(transparent)] RequestError(#[from] ProviderError), + /// Contract call with abigen failed. + #[error(transparent)] + AbigenError(#[from] AbigenError), /// Conversion between Starknet types and ETH failed. #[error("conversion error: {0}")] ConversionError(String), @@ -138,6 +143,7 @@ impl From for ErrorObject<'static> { ProviderError::RateLimited => rpc_err(EthRpcErrorCode::RequestLimitExceeded, err_provider.to_string()), ProviderError::Other(_) => rpc_err(EthRpcErrorCode::InternalError, err_provider.to_string()), }, + EthApiError::AbigenError(err) => rpc_err(EthRpcErrorCode::InternalError, err.to_string()), EthApiError::ConversionError(err) => rpc_err(EthRpcErrorCode::InternalError, err), EthApiError::DataDecodingError(err) => rpc_err(EthRpcErrorCode::InternalError, err.to_string()), EthApiError::KakarotDataFilteringError(err) => rpc_err(EthRpcErrorCode::InternalError, err), diff --git a/crates/core/src/client/helpers.rs b/crates/core/src/client/helpers.rs index b02480c3c..bc7c9e0f8 100644 --- a/crates/core/src/client/helpers.rs +++ b/crates/core/src/client/helpers.rs @@ -1,5 +1,5 @@ use eyre::Result; -use reth_primitives::{Bytes, U128, U256}; +use reth_primitives::{U128, U256}; use reth_rlp::DecodeError; use starknet::core::types::{ FieldElement, MaybePendingBlockWithTxHashes, MaybePendingBlockWithTxs, ValueOutOfRangeError, @@ -67,16 +67,6 @@ pub fn decode_eth_call_return(call_result: &[FieldElement]) -> Result) -> Bytes { - let bytes: Vec = vec_felt.into_iter().filter_map(|x: FieldElement| u8::try_from(x).ok()).collect(); - Bytes::from(bytes) -} - -pub fn bytes_to_felt_vec(bytes: &Bytes) -> Vec { - bytes.to_vec().into_iter().map(FieldElement::from).collect() -} - /// Constructs the calldata for a raw Starknet invoke transaction call pub fn raw_kakarot_calldata(kakarot_address: FieldElement, mut calldata: Vec) -> Vec { let mut execute_calldata: Vec = vec![ @@ -109,43 +99,6 @@ mod tests { use super::*; - #[test] - fn test_bytes_to_felt_vec() { - let bytes = Bytes::from(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); - let felt_vec = bytes_to_felt_vec(&bytes); - assert_eq!(felt_vec.len(), 10); - assert_eq!( - felt_vec, - vec![ - FieldElement::from(1_u64), - FieldElement::from(2_u64), - FieldElement::from(3_u64), - FieldElement::from(4_u64), - FieldElement::from(5_u64), - FieldElement::from(6_u64), - FieldElement::from(7_u64), - FieldElement::from(8_u64), - FieldElement::from(9_u64), - FieldElement::from(10_u64) - ] - ); - } - - #[test] - fn test_vec_felt_to_bytes() { - // Given - let bytecode: Vec = - serde_json::from_str(include_str!("../models/test_data/bytecode/starknet/counter.json")).unwrap(); - - // When - let bytes = vec_felt_to_bytes(bytecode); - - // Then - let expected: Bytes = - serde_json::from_str(include_str!("../models/test_data/bytecode/eth/counter.json")).unwrap(); - assert_eq!(expected, bytes); - } - #[rstest] #[test] #[case( diff --git a/crates/core/src/client/mod.rs b/crates/core/src/client/mod.rs index 0d7a2c48e..7105e9cea 100644 --- a/crates/core/src/client/mod.rs +++ b/crates/core/src/client/mod.rs @@ -31,10 +31,8 @@ use self::constants::{ DUMMY_ARGENT_GAS_PRICE_ACCOUNT_ADDRESS, ESTIMATE_GAS, MAX_FEE, STARKNET_NATIVE_TOKEN, }; use self::errors::EthApiError; -use self::helpers::{bytes_to_felt_vec, raw_kakarot_calldata}; +use self::helpers::raw_kakarot_calldata; use self::waiter::TransactionWaiter; -use crate::contracts::account::{Account, KakarotAccount}; -use crate::contracts::contract_account::ContractAccount; use crate::contracts::erc20::ethereum_erc20::EthereumErc20; use crate::contracts::erc20::starknet_erc20::StarknetErc20; use crate::contracts::kakarot::KakarotContract; @@ -47,6 +45,11 @@ use crate::models::felt::Felt252Wrapper; use crate::models::transaction::transaction::{StarknetTransaction, StarknetTransactions}; use crate::models::transaction::transaction_signed::StarknetTransactionSigned; use crate::models::ConversionError; +use starknet_abigen_macros::abigen_legacy; +use starknet_abigen_parser; + +abigen_legacy!(ContractAccount, "./artifacts/contract_account.json"); +abigen_legacy!(Proxy, "./artifacts/proxy.json"); pub struct KakarotClient { starknet_provider: Arc

, @@ -92,7 +95,7 @@ impl KakarotClient

{ let origin: FieldElement = Felt252Wrapper::from(origin).into(); - let calldata = bytes_to_felt_vec(&calldata); + let calldata = calldata.to_vec().into_iter().map(FieldElement::from).collect(); let result = self.kakarot_contract.eth_call(&origin, &to, calldata, &starknet_block_id).await?; @@ -159,25 +162,22 @@ impl KakarotClient

{ let starknet_block_id: StarknetBlockId = EthBlockId::new(block_id).try_into()?; let starknet_address = self.compute_starknet_address(ðereum_address, &starknet_block_id).await?; - // Get the implementation of the account - let account = KakarotAccount::new(starknet_address, &self.starknet_provider); - let class_hash = match account.implementation(&starknet_block_id).await { + let proxy = ProxyReader::new(starknet_address, &self.starknet_provider); + + let class_hash = match proxy.get_implementation().call().await { Ok(class_hash) => class_hash, - Err(err) => match err { - EthApiError::RequestError(ProviderError::StarknetError(StarknetErrorWithMessage { - code: MaybeUnknownErrorCode::Known(StarknetError::ContractNotFound), - .. - })) => return Ok(U256::from(0)), // Return 0 if the account doesn't exist - _ => return Err(err), // Propagate the error - }, + // TODO: replace by proper error handling + // if the contract doesn't exist, we return 0 + Err(_) => FieldElement::ZERO, }; if class_hash == self.kakarot_contract.contract_account_class_hash { - // Get the nonce of the contract account - let contract_account = ContractAccount::new(starknet_address, &self.starknet_provider); - contract_account.nonce(&starknet_block_id).await + // Get the nonce of the contract account -> a storage variable + let contract_account = ContractAccountReader::new(starknet_address, &self.starknet_provider); + let nonce = contract_account.get_nonce().call().await?; + Ok(Felt252Wrapper::from(nonce).into()) } else { - // Get the nonce of the EOA + // Get the nonce of the EOA -> the protocol level nonce let nonce = self.starknet_provider.get_nonce(starknet_block_id, starknet_address).await; let nonce = match nonce { Ok(nonce) => nonce, @@ -222,11 +222,16 @@ impl KakarotClient

{ let key_high: U256 = index >> 128; let key_high: Felt252Wrapper = key_high.try_into()?; - let provider = self.starknet_provider(); - let contract_account = ContractAccount::new(starknet_contract_address, &provider); - let storage_value = contract_account.storage(&key_low.into(), &key_high.into(), &starknet_block_id).await?; + let contract_account = ContractAccountReader::new(starknet_contract_address, &self.starknet_provider); + let storage = contract_account.storage(&Uint256 { low: key_low.into(), high: key_high.into() }).call().await?; + + // TODO: replace by From for U256 + let low = storage.low; + let high = storage.high; + let result = + Into::::into(Felt252Wrapper::from(low)) + (Into::::into(Felt252Wrapper::from(high)) << 128); - Ok(storage_value) + Ok(result) } /// Returns token balances for a specific address given a list of contracts addresses. @@ -449,13 +454,11 @@ impl KakarotClient

{ /// Returns the EVM address associated with a given Starknet address for a given block id /// by calling the `get_evm_address` function on the Kakarot contract. - pub async fn get_evm_address( - &self, - starknet_address: &FieldElement, - starknet_block_id: &StarknetBlockId, - ) -> Result { - let kakarot_account = KakarotAccount::new(*starknet_address, &self.starknet_provider); - kakarot_account.get_evm_address(starknet_block_id).await + pub async fn get_evm_address(&self, starknet_address: &FieldElement) -> Result { + let contract_account = ContractAccountReader::new(*starknet_address, &self.starknet_provider); + let evm_address = contract_account.get_evm_address().call().await?; + let evm_address = Felt252Wrapper::from(evm_address).try_into()?; + Ok(evm_address) } /// Returns the EVM address associated with a given Starknet address for a given block id diff --git a/crates/core/src/client/tests/mod.rs b/crates/core/src/client/tests/mod.rs index 31d18fbb9..0fb52b048 100644 --- a/crates/core/src/client/tests/mod.rs +++ b/crates/core/src/client/tests/mod.rs @@ -2,7 +2,6 @@ use std::str::FromStr; use reth_primitives::{BlockId, BlockNumberOrTag, Bytes, U256, U64}; use reth_rpc_types::{CallInput, CallRequest}; -use starknet::core::types::{BlockId as StarknetBlockId, BlockTag}; use starknet::providers::jsonrpc::JsonRpcMethod; use crate::client::constants::CHAIN_ID; @@ -36,8 +35,7 @@ async fn test_get_evm_address() { let client = init_mock_client(Some(fixtures)); // When - let evm_address = - client.get_evm_address(&ABDEL_STARKNET_ADDRESS, &StarknetBlockId::Tag(BlockTag::Latest)).await.unwrap(); + let evm_address = client.get_evm_address(&ABDEL_STARKNET_ADDRESS).await.unwrap(); // Then assert_eq!(*ABDEL_ETHEREUM_ADDRESS, evm_address); diff --git a/crates/core/src/contracts/account.rs b/crates/core/src/contracts/account.rs deleted file mode 100644 index d46611fac..000000000 --- a/crates/core/src/contracts/account.rs +++ /dev/null @@ -1,96 +0,0 @@ -use async_trait::async_trait; -use reth_primitives::{Address, Bytes}; -use starknet::core::types::{BlockId, FunctionCall, StarknetError}; -use starknet::providers::{MaybeUnknownErrorCode, Provider, ProviderError, StarknetErrorWithMessage}; -use starknet_crypto::FieldElement; - -use crate::client::constants::selectors::{BYTECODE, GET_EVM_ADDRESS, GET_IMPLEMENTATION}; -use crate::client::errors::EthApiError; -use crate::client::helpers::{vec_felt_to_bytes, DataDecodingError}; -use crate::models::felt::Felt252Wrapper; - -#[async_trait] -pub trait Account<'a, P: Provider + Send + Sync + 'a> { - fn new(starknet_address: FieldElement, provider: &'a P) -> Self; - fn provider(&self) -> &'a P; - fn starknet_address(&self) -> FieldElement; - async fn get_evm_address(&self, starknet_block_id: &BlockId) -> Result { - let request = FunctionCall { - contract_address: self.starknet_address(), - entry_point_selector: GET_EVM_ADDRESS, - calldata: vec![], - }; - - let evm_address = self.provider().call(request, starknet_block_id).await?; - let evm_address: Felt252Wrapper = (*evm_address.first().ok_or_else(|| { - DataDecodingError::InvalidReturnArrayLength { entrypoint: "get_evm_address".into(), expected: 1, actual: 0 } - })?) - .into(); - - Ok(evm_address.truncate_to_ethereum_address()) - } - - /// Returns the evm bytecode of the contract. - async fn bytecode(&self, block_id: &BlockId) -> Result { - // Prepare the calldata for the bytecode function call - let calldata = vec![]; - let request = - FunctionCall { contract_address: self.starknet_address(), entry_point_selector: BYTECODE, calldata }; - - // Make the function call to get the Starknet contract address - let bytecode = self.provider().call(request, block_id).await.or_else(|err| match err { - ProviderError::StarknetError(StarknetErrorWithMessage { - code: MaybeUnknownErrorCode::Known(StarknetError::ContractNotFound), - .. - }) => Ok(vec![]), - _ => Err(EthApiError::from(err)), - })?; - - if bytecode.is_empty() { - return Ok(Bytes::default()); - } - - // bytecode_len is the first element of the returned array - // TODO: Remove Manual Decoding - Ok(vec_felt_to_bytes(bytecode[1..].to_vec())) - } - - /// Returns the class hash of account implementation of the contract. - async fn implementation(&self, block_id: &BlockId) -> Result { - // Prepare the calldata for the get_implementation function call - let calldata = vec![]; - let request = FunctionCall { - contract_address: self.starknet_address(), - entry_point_selector: GET_IMPLEMENTATION, - calldata, - }; - - // Make the function call to get the Starknet contract address - let class_hash = self.provider().call(request, block_id).await?; - let class_hash = *class_hash.first().ok_or_else(|| DataDecodingError::InvalidReturnArrayLength { - entrypoint: "get_implementation".into(), - expected: 1, - actual: 0, - })?; - Ok(class_hash) - } -} - -pub struct KakarotAccount<'a, P> { - pub starknet_address: FieldElement, - provider: &'a P, -} - -impl<'a, P: Provider + Send + Sync> Account<'a, P> for KakarotAccount<'a, P> { - fn new(starknet_address: FieldElement, provider: &'a P) -> Self { - Self { starknet_address, provider } - } - - fn provider(&self) -> &'a P { - self.provider - } - - fn starknet_address(&self) -> FieldElement { - self.starknet_address - } -} diff --git a/crates/core/src/contracts/contract_account.rs b/crates/core/src/contracts/contract_account.rs deleted file mode 100644 index c1e9b5ecc..000000000 --- a/crates/core/src/contracts/contract_account.rs +++ /dev/null @@ -1,84 +0,0 @@ -use reth_primitives::U256; -use starknet::core::types::{BlockId, FunctionCall}; -use starknet::providers::Provider; -use starknet_crypto::FieldElement; - -use super::account::Account; -use crate::client::constants::selectors::{GET_NONCE, STORAGE}; -use crate::client::errors::EthApiError; -use crate::client::helpers::DataDecodingError; -use crate::models::felt::Felt252Wrapper; - -/// Abstraction for a Kakarot contract account. -pub struct ContractAccount<'a, P> { - pub address: FieldElement, - provider: &'a P, -} - -impl<'a, P: Provider + Send + Sync> Account<'a, P> for ContractAccount<'a, P> { - fn new(address: FieldElement, provider: &'a P) -> Self { - Self { address, provider } - } - - fn provider(&self) -> &'a P { - self.provider - } - - fn starknet_address(&self) -> FieldElement { - self.address - } -} - -impl<'a, P: Provider + Send + Sync> ContractAccount<'a, P> { - /// Returns the value stored at the given key in the evm contract storage. Not to be confused - /// with the Starknet contract storage. - pub async fn storage( - &self, - key_low: &FieldElement, - key_high: &FieldElement, - block_id: &BlockId, - ) -> Result { - // Prepare the calldata for the storage function call - let calldata = vec![*key_low, *key_high]; - let request = FunctionCall { contract_address: self.address, entry_point_selector: STORAGE, calldata }; - - // Make the function call to get the Starknet contract address - let result = self.provider.call(request, block_id).await?; - if result.len() != 2 { - return Err(DataDecodingError::InvalidReturnArrayLength { - entrypoint: "storage".into(), - expected: 2, - actual: result.len(), - } - .into()); - } - let low: Felt252Wrapper = result[0].into(); // safe indexing - let high: Felt252Wrapper = result[1].into(); // safe indexing - - let value = Into::::into(low) + (Into::::into(high) << 128); - Ok(value) - } - - /// Returns the nonce of the contract account. - /// In Kakarot EVM, there are two types of accounts: EOA and Contract Account. - /// EOA nonce is handled by Starknet protocol. - /// Contract Account nonce is handled by Kakarot through a dedicated storage, this function - /// returns that storage value. - pub async fn nonce(&self, block_id: &BlockId) -> Result { - // Prepare the calldata for the get_nonce function call - let calldata = vec![]; - let request = FunctionCall { contract_address: self.address, entry_point_selector: GET_NONCE, calldata }; - - let result = self.provider.call(request, block_id).await?; - if result.len() != 1 { - return Err(DataDecodingError::InvalidReturnArrayLength { - entrypoint: "get_nonce".into(), - expected: 1, - actual: result.len(), - } - .into()); - } - - Ok(Felt252Wrapper::from(result[0]).into()) - } -} diff --git a/crates/core/src/contracts/kakarot.rs b/crates/core/src/contracts/kakarot.rs index 7e3fa54c9..de2395359 100644 --- a/crates/core/src/contracts/kakarot.rs +++ b/crates/core/src/contracts/kakarot.rs @@ -9,7 +9,7 @@ use starknet_crypto::FieldElement; use crate::client::constants::selectors::{COMPUTE_STARKNET_ADDRESS, DEPLOY_EXTERNALLY_OWNED_ACCOUNT, ETH_CALL}; use crate::client::errors::EthApiError; -use crate::client::helpers::{decode_eth_call_return, vec_felt_to_bytes, DataDecodingError}; +use crate::client::helpers::{decode_eth_call_return, DataDecodingError}; use crate::client::waiter::TransactionWaiter; pub struct KakarotContract

{ @@ -82,7 +82,8 @@ impl KakarotContract

{ // params let return_data = decode_eth_call_return(&result)?; - let result = vec_felt_to_bytes(return_data); + let result = + Bytes::from(return_data.into_iter().filter_map(|x: FieldElement| u8::try_from(x).ok()).collect::>()); Ok(result) } diff --git a/crates/core/src/contracts/mod.rs b/crates/core/src/contracts/mod.rs index cd2151d82..3c9edd198 100644 --- a/crates/core/src/contracts/mod.rs +++ b/crates/core/src/contracts/mod.rs @@ -1,5 +1,3 @@ -pub mod account; -pub mod contract_account; pub mod erc20; pub mod kakarot; #[cfg(test)] diff --git a/crates/core/src/contracts/tests/account.rs b/crates/core/src/contracts/tests/account.rs deleted file mode 100644 index f1de3e1e3..000000000 --- a/crates/core/src/contracts/tests/account.rs +++ /dev/null @@ -1,71 +0,0 @@ -#[cfg(test)] -mod tests { - - use std::sync::Arc; - - use kakarot_test_utils::execution::contract::KakarotEvmContract; - use kakarot_test_utils::fixtures::counter; - use kakarot_test_utils::sequencer::Katana; - use reth_primitives::U256; - use rstest::*; - use starknet::core::types::{BlockId, BlockTag}; - use starknet_crypto::FieldElement; - - use crate::contracts::account::{Account, KakarotAccount}; - use crate::contracts::contract_account::ContractAccount; - use crate::mock::constants::ABDEL_STARKNET_ADDRESS; - use crate::mock::mock_starknet::{fixtures, mock_starknet_provider, AvailableFixtures}; - - #[tokio::test] - async fn test_nonce() { - // Given - let fixtures = fixtures(vec![AvailableFixtures::GetNonce]); - let starknet_provider = Arc::new(mock_starknet_provider(Some(fixtures))); - let contract_account = ContractAccount::new(*ABDEL_STARKNET_ADDRESS, &starknet_provider); - - // When - let nonce = contract_account.nonce(&BlockId::Tag(BlockTag::Latest)).await.unwrap(); - - // Then - assert_eq!(U256::from(1), nonce); - } - - #[tokio::test] - async fn test_implementation() { - // Given - let fixtures = fixtures(vec![AvailableFixtures::GetImplementation]); - let starknet_provider = Arc::new(mock_starknet_provider(Some(fixtures))); - let account = KakarotAccount::new(*ABDEL_STARKNET_ADDRESS, &starknet_provider); - - // When - let implementation = account.implementation(&BlockId::Tag(BlockTag::Latest)).await.unwrap(); - - // Then - assert_eq!( - FieldElement::from_hex_be("0x4730612e9d26ebca8dd27be1af79cea613f7dee43f5b1584a172040e39f4063").unwrap(), - implementation - ); - } - - #[rstest] - #[awt] - #[tokio::test(flavor = "multi_thread")] - async fn test_bytecode(#[future] counter: (Katana, KakarotEvmContract)) { - // Given - let katana = counter.0; - let counter = counter.1; - let expected_bytecode = - counter.bytecode.deployed_bytecode.expect("Missing deployed bytecode").bytecode.expect("Missing bytecode"); - let expected_bytecode = expected_bytecode.object.as_bytes().expect("Failed to convert bytecode to bytes"); - - let starknet_block_id = BlockId::Tag(BlockTag::Latest); - let starknet_provider = katana.client().starknet_provider(); - let counter_contract_account = KakarotAccount::new(counter.starknet_address, starknet_provider.as_ref()); - - // When - let actual_bytecode = counter_contract_account.bytecode(&starknet_block_id).await.unwrap(); - - // Then - assert_eq!(expected_bytecode.to_vec(), actual_bytecode.to_vec()); - } -} diff --git a/crates/core/src/contracts/tests/mod.rs b/crates/core/src/contracts/tests/mod.rs index 370ce69bd..bfe4665e0 100644 --- a/crates/core/src/contracts/tests/mod.rs +++ b/crates/core/src/contracts/tests/mod.rs @@ -1,2 +1 @@ -mod account; mod erc20; diff --git a/crates/core/src/mock/fixtures/requests/account_getEvmAddress.json b/crates/core/src/mock/fixtures/requests/account_getEvmAddress.json index a9a077512..3d61c81c5 100644 --- a/crates/core/src/mock/fixtures/requests/account_getEvmAddress.json +++ b/crates/core/src/mock/fixtures/requests/account_getEvmAddress.json @@ -8,6 +8,6 @@ "entry_point_selector": "0x158359fe4236681f6236a2f303f9350495f73f078c9afd1ca0890fa4143c2ed", "calldata": [] }, - "latest" + "pending" ] } diff --git a/crates/core/src/mock/fixtures/requests/account_getImplementation.json b/crates/core/src/mock/fixtures/requests/account_getImplementation.json index 882c87220..cb083a7a3 100644 --- a/crates/core/src/mock/fixtures/requests/account_getImplementation.json +++ b/crates/core/src/mock/fixtures/requests/account_getImplementation.json @@ -8,6 +8,6 @@ "entry_point_selector": "0x21691762da057c1b71f851f9b709e0c143628acf6e0cbc9735411a65663d747", "calldata": [] }, - "latest" + "pending" ] } diff --git a/crates/core/src/mock/fixtures/requests/account_getNonce.json b/crates/core/src/mock/fixtures/requests/account_getNonce.json index 2394a78c5..4170e1858 100644 --- a/crates/core/src/mock/fixtures/requests/account_getNonce.json +++ b/crates/core/src/mock/fixtures/requests/account_getNonce.json @@ -8,6 +8,6 @@ "entry_point_selector": "0x1ac47721ee58ba2813c2a816bca188512839a00d3970f67c05eab986b14006d", "calldata": [] }, - "latest" + "pending" ] } diff --git a/crates/core/src/mock/fixtures/requests/kakarot_getCode.json b/crates/core/src/mock/fixtures/requests/kakarot_getCode.json index 10d4f1ecc..1f8355593 100644 --- a/crates/core/src/mock/fixtures/requests/kakarot_getCode.json +++ b/crates/core/src/mock/fixtures/requests/kakarot_getCode.json @@ -8,6 +8,6 @@ "entry_point_selector": "0x2f22d9e1ae4a391b4a190b8225f2f6f772a083382b7ded3e8d85743a8fcfdcd", "calldata": [] }, - "latest" + "pending" ] } diff --git a/crates/core/src/mock/fixtures/requests/starknet_call.json b/crates/core/src/mock/fixtures/requests/starknet_call.json index f2942a09d..0bee96ec3 100644 --- a/crates/core/src/mock/fixtures/requests/starknet_call.json +++ b/crates/core/src/mock/fixtures/requests/starknet_call.json @@ -8,6 +8,6 @@ "entry_point_selector": "0xad7772990f7f5a506d84e5723efd1242e989c23f45653870d49d6d107f6e7", "calldata": ["0xabde1"] }, - "latest" + "pending" ] } diff --git a/crates/core/src/mock/fixtures/requests/starknet_call_other.json b/crates/core/src/mock/fixtures/requests/starknet_call_other.json index 6721169c8..36ad74663 100644 --- a/crates/core/src/mock/fixtures/requests/starknet_call_other.json +++ b/crates/core/src/mock/fixtures/requests/starknet_call_other.json @@ -8,6 +8,6 @@ "entry_point_selector": "0x158359fe4236681f6236a2f303f9350495f73f078c9afd1ca0890fa4143c2ed", "calldata": [] }, - "latest" + "pending" ] } diff --git a/crates/core/src/models/block.rs b/crates/core/src/models/block.rs index c7b3e53c2..f5a2e8eee 100644 --- a/crates/core/src/models/block.rs +++ b/crates/core/src/models/block.rs @@ -1,5 +1,5 @@ use async_trait::async_trait; -use reth_primitives::{BlockId as EthereumBlockId, BlockNumberOrTag, Bloom, Bytes, H256, H64, U256}; +use reth_primitives::{Address, BlockId as EthereumBlockId, BlockNumberOrTag, Bloom, Bytes, H256, H64, U256}; use reth_rpc_types::{Block, BlockTransactions, Header, RichBlock}; use starknet::core::types::{ BlockId as StarknetBlockId, BlockTag, FieldElement, MaybePendingBlockWithTxHashes, MaybePendingBlockWithTxs, @@ -175,7 +175,7 @@ impl ConvertibleStarknetBlock for BlockWithTxHashes { let mix_hash = *MIX_HASH; let parent_hash = H256::from_slice(&self.parent_hash().to_bytes_be()); - let sequencer = Felt252Wrapper::from(self.sequencer_address()).truncate_to_ethereum_address(); + let sequencer = Address::from_slice(&self.sequencer_address().to_bytes_be()[12..]); let timestamp = U256::from(self.timestamp()); let hash = self.block_hash().as_ref().map(|hash| H256::from_slice(&hash.to_bytes_be())); @@ -255,7 +255,7 @@ impl ConvertibleStarknetBlock for BlockWithTxs { let parent_hash = H256::from_slice(&self.parent_hash().to_bytes_be()); - let sequencer = Felt252Wrapper::from(self.sequencer_address()).truncate_to_ethereum_address(); + let sequencer = Address::from_slice(&self.sequencer_address().to_bytes_be()[12..]); let timestamp = U256::from(self.timestamp()); diff --git a/crates/core/src/models/event.rs b/crates/core/src/models/event.rs index 08c93b40f..a398232e3 100644 --- a/crates/core/src/models/event.rs +++ b/crates/core/src/models/event.rs @@ -5,10 +5,10 @@ use reth_primitives::{Address, Bytes, H256, U256}; use reth_rpc_types::Log; use starknet::core::types::Event; use starknet::providers::Provider; +use starknet_crypto::FieldElement; use super::felt::Felt252Wrapper; use crate::client::errors::EthApiError; -use crate::client::helpers::vec_felt_to_bytes; use crate::client::KakarotClient; use crate::models::convertible::ConvertibleStarknetEvent; @@ -70,7 +70,8 @@ impl ConvertibleStarknetEvent for StarknetEvent { }) .collect::>()?; - let data: Bytes = vec_felt_to_bytes(self.0.data); + let data = + Bytes::from(self.0.data.into_iter().filter_map(|x: FieldElement| u8::try_from(x).ok()).collect::>()); Ok(Log { address, diff --git a/crates/core/src/models/felt.rs b/crates/core/src/models/felt.rs index cc941b300..f84137e13 100644 --- a/crates/core/src/models/felt.rs +++ b/crates/core/src/models/felt.rs @@ -10,14 +10,6 @@ pub struct Felt252Wrapper(FieldElement); impl Felt252Wrapper { pub const ZERO: Self = Self(FieldElement::ZERO); - /// Troncate the first 12 bytes of the `FieldElement` and return the last 20 bytes as an - /// Ethereum address. This is used to convert Starknet addresses to Ethereum addresses in - /// cases where the Starknet address does not represent a Kakarot address, i.e. it does not have - /// a `get_evm_address()` entrypoint. - pub fn truncate_to_ethereum_address(&self) -> Address { - let bytes = self.0.to_bytes_be(); - Address::from_slice(&bytes[12..]) - } } impl Mul for Felt252Wrapper { diff --git a/crates/core/src/models/transaction/transaction.rs b/crates/core/src/models/transaction/transaction.rs index 8a53880f1..bbee49f10 100644 --- a/crates/core/src/models/transaction/transaction.rs +++ b/crates/core/src/models/transaction/transaction.rs @@ -77,7 +77,6 @@ impl ConvertibleStarknetTransaction for StarknetTransaction { return Err(EthApiError::KakarotDataFilteringError("Transaction".into())); } - let starknet_block_latest = StarknetBlockId::Tag(BlockTag::Latest); let sender_address: FieldElement = self.sender_address()?.into(); let hash: H256 = self.transaction_hash()?.into(); @@ -105,7 +104,7 @@ impl ConvertibleStarknetTransaction for StarknetTransaction { }; let nonce: U64 = u64::try_from(nonce)?.into(); - let from = client.get_evm_address(&sender_address, &starknet_block_latest).await?; + let from = client.get_evm_address(&sender_address).await?; let max_priority_fee_per_gas = Some(client.max_priority_fee_per_gas()); diff --git a/crates/core/src/models/transaction/transaction_signed.rs b/crates/core/src/models/transaction/transaction_signed.rs index edfde9d11..fa448b998 100644 --- a/crates/core/src/models/transaction/transaction_signed.rs +++ b/crates/core/src/models/transaction/transaction_signed.rs @@ -7,7 +7,7 @@ use starknet_crypto::FieldElement; use crate::client::constants::MAX_FEE; use crate::client::errors::EthApiError; -use crate::client::helpers::{bytes_to_felt_vec, raw_kakarot_calldata, DataDecodingError}; +use crate::client::helpers::{raw_kakarot_calldata, DataDecodingError}; use crate::client::KakarotClient; use crate::models::convertible::ConvertibleSignedTransaction; @@ -39,7 +39,10 @@ impl ConvertibleSignedTransaction for StarknetTransactionSigned { let nonce = FieldElement::from(transaction.nonce()); - let calldata = raw_kakarot_calldata(client.kakarot_address(), bytes_to_felt_vec(&self.0)); + let calldata = raw_kakarot_calldata( + client.kakarot_address(), + self.0.to_vec().into_iter().map(FieldElement::from).collect(), + ); // Get estimated_fee from Starknet let max_fee = *MAX_FEE; diff --git a/crates/eth-rpc/src/servers/eth_rpc.rs b/crates/eth-rpc/src/servers/eth_rpc.rs index 011b5ec70..f451c8715 100644 --- a/crates/eth-rpc/src/servers/eth_rpc.rs +++ b/crates/eth-rpc/src/servers/eth_rpc.rs @@ -3,9 +3,7 @@ use std::sync::Arc; use jsonrpsee::core::{async_trait, RpcResult as Result}; use kakarot_rpc_core::client::constants::{CHAIN_ID, CHUNK_SIZE_LIMIT, TX_ORIGIN_ZERO}; use kakarot_rpc_core::client::errors::{rpc_err, EthApiError, EthRpcErrorCode}; -use kakarot_rpc_core::client::KakarotClient; -use kakarot_rpc_core::contracts::account::Account; -use kakarot_rpc_core::contracts::contract_account::ContractAccount; +use kakarot_rpc_core::client::{ContractAccountReader, KakarotClient}; use kakarot_rpc_core::models::block::EthBlockId; use kakarot_rpc_core::models::convertible::{ ConvertibleEthEventFilter, ConvertibleStarknetEvent, ConvertibleStarknetTransaction, @@ -219,12 +217,12 @@ impl EthApiServer for KakarotEthRpc

{ let starknet_contract_address = self.kakarot_client.compute_starknet_address(&address, &starknet_block_id).await?; - let binding = self.kakarot_client.starknet_provider(); - let contract_account = ContractAccount::new(starknet_contract_address, &binding); - let bytecode = contract_account.bytecode(&starknet_block_id).await?; + let provider = self.kakarot_client.starknet_provider(); - // Convert the result of the function call to a vector of bytes - Ok(bytecode) + // Get the nonce of the contract account -> a storage variable + let contract_account = ContractAccountReader::new(starknet_contract_address, &provider); + let (_, bytecode) = contract_account.bytecode().call().await.map_err(EthApiError::from)?; + Ok(Bytes::from(bytecode.0.into_iter().filter_map(|x: FieldElement| u8::try_from(x).ok()).collect::>())) } async fn get_logs(&self, filter: Filter) -> Result { diff --git a/crates/test-utils/src/hive_utils/madara/utils.rs b/crates/test-utils/src/hive_utils/madara/utils.rs index 5113c7e35..1d79bbb61 100644 --- a/crates/test-utils/src/hive_utils/madara/utils.rs +++ b/crates/test-utils/src/hive_utils/madara/utils.rs @@ -159,12 +159,13 @@ mod tests { use ctor::ctor; use kakarot_rpc_core::client::constants::STARKNET_NATIVE_TOKEN; use kakarot_rpc_core::client::helpers::split_u256_into_field_elements; - use kakarot_rpc_core::contracts::account::Account; - use kakarot_rpc_core::contracts::contract_account::ContractAccount; + use kakarot_rpc_core::client::ContractAccountReader; + use kakarot_rpc_core::client::Uint256 as CairoUint256; use kakarot_rpc_core::mock::constants::ACCOUNT_ADDRESS; + use kakarot_rpc_core::models::felt::Felt252Wrapper; use reth_primitives::U256; use rstest::rstest; - use starknet::core::types::{BlockId as StarknetBlockId, BlockTag, FieldElement}; + use starknet::core::types::FieldElement; use starknet::core::utils::get_storage_var_address; use starknet_api::core::{ClassHash, ContractAddress as StarknetContractAddress, Nonce}; use starknet_api::hash::StarkFelt; @@ -246,6 +247,7 @@ mod tests { assert_eq!(expected_storage, storage); } + #[ignore] #[rstest] #[awt] #[tokio::test(flavor = "multi_thread")] @@ -254,11 +256,14 @@ mod tests { let katana = counter.0; let counter = counter.1; let starknet_client = katana.client().starknet_provider(); - let counter_contract = ContractAccount::new(counter.evm_address, &starknet_client); + + let counter_contract = ContractAccountReader::new(counter.evm_address, &starknet_client); // When - let deployed_evm_bytecode = counter_contract.bytecode(&StarknetBlockId::Tag(BlockTag::Latest)).await.unwrap(); - let deployed_evm_bytecode_len = deployed_evm_bytecode.len(); + let (deployed_evm_bytecode_len, deployed_evm_bytecode) = counter_contract.bytecode().call().await.unwrap(); + let deployed_evm_bytecode = Bytes::from( + deployed_evm_bytecode.0.into_iter().filter_map(|x: FieldElement| u8::try_from(x).ok()).collect::>(), + ); // Use genesis_set_bytecode to get the bytecode to be stored into counter let counter_genesis_address = FieldElement::from_str("0x1234").unwrap(); @@ -270,7 +275,7 @@ mod tests { // Set the counter bytecode length into the contract let key = get_starknet_storage_key("bytecode_len_", &[]); - let value = Into::::into(StarkFelt::from(deployed_evm_bytecode_len as u64)); + let value = StarkFelt::from(deployed_evm_bytecode_len); counter_storage.insert(key, value); // Set the counter bytecode into the contract @@ -294,12 +299,15 @@ mod tests { drop(starknet); // Create a new counter contract pointing to the genesis initialized storage - let counter_genesis = ContractAccount::new(counter_genesis_address, &starknet_client); - let evm_bytecode_actual = counter_genesis.bytecode(&StarknetBlockId::Tag(BlockTag::Latest)).await.unwrap(); + let counter_genesis = ContractAccountReader::new(counter.evm_address, &starknet_client); + let (_, genesis_evm_bytecode) = counter_genesis.bytecode().call().await.unwrap(); + let genesis_evm_bytecode = Bytes::from( + genesis_evm_bytecode.0.into_iter().filter_map(|x: FieldElement| u8::try_from(x).ok()).collect::>(), + ); // Then // Assert that the expected and actual bytecodes are equal - assert_eq!(evm_bytecode_actual, deployed_evm_bytecode); + assert_eq!(genesis_evm_bytecode, deployed_evm_bytecode); } /// This test verifies that the `genesis_fund_starknet_address` function generates the correct @@ -428,10 +436,15 @@ mod tests { // Deploy the contract account with the set genesis storage and retrieve the storage on the contract let starknet_client = katana.client().starknet_provider(); - let genesis_contract = ContractAccount::new(genesis_address, &starknet_client); let [key_low, key_high] = split_u256_into_field_elements(expected_key); + let genesis_contract = ContractAccountReader::new(genesis_address, &starknet_client); + let storage = genesis_contract.storage(&CairoUint256 { low: key_low, high: key_high }).call().await.unwrap(); + + // TODO: replace by From for U256 + let low = storage.low; + let high = storage.high; let actual_value = - genesis_contract.storage(&key_low, &key_high, &StarknetBlockId::Tag(BlockTag::Latest)).await.unwrap(); + Into::::into(Felt252Wrapper::from(low)) + (Into::::into(Felt252Wrapper::from(high)) << 128); // Assert that the value stored in the contract is the same as the value we set in the genesis assert_eq!(expected_value, actual_value); diff --git a/crates/test-utils/src/sequencer/mod.rs b/crates/test-utils/src/sequencer/mod.rs index 1686deac5..64e1e84f5 100644 --- a/crates/test-utils/src/sequencer/mod.rs +++ b/crates/test-utils/src/sequencer/mod.rs @@ -3,6 +3,7 @@ use std::path::Path; use std::str::FromStr; use std::sync::Arc; +use crate::execution::eoa::EOA; use dojo_test_utils::sequencer::{Environment, SequencerConfig, StarknetConfig, TestSequencer}; use ethers::types::H256; use foundry_config::utils::find_project_root_path; @@ -48,8 +49,8 @@ async fn katana_sequencer() -> TestSequencer { } pub struct Katana { - sequencer: TestSequencer, - eoa: KakarotEOA>, + pub sequencer: TestSequencer, + pub eoa: KakarotEOA>, } impl Katana { @@ -107,8 +108,8 @@ impl Katana { &self.eoa } - pub const fn client(&self) -> &KakarotClient> { - &self.eoa.client + pub fn client(&self) -> &KakarotClient> { + self.eoa.client() } pub const fn sequencer(&self) -> &TestSequencer { diff --git a/scripts/extract_abi.sh b/scripts/extract_abi.sh new file mode 100755 index 000000000..db9ed47de --- /dev/null +++ b/scripts/extract_abi.sh @@ -0,0 +1,27 @@ +#!/bin/bash +set -o pipefail + +# Directory containing the original JSON files +src_dir="./lib/kakarot/build" + +# Directory to write the new JSON files to +dest_dir="./artifacts" + +# Ensure the destination directory exists +rm -rf "${dest_dir}" +mkdir -p "${dest_dir}" + +# Find and process each JSON file +find "${src_dir}" -type f -name '*.json' | while read -r src_file; do + # Extract the filename without the extension + filename=$(basename -- "${src_file}") + filename="${filename%.*}" + + # Check and create a subdirectory structure in destination if needed + sub_dir=$(dirname "${src_file}") + sub_dir=${sub_dir#"${src_dir}"} + mkdir -p "${dest_dir}${sub_dir}" + + # Use jq to extract the 'abi' field and write it to a new JSON file + jq '.abi' "${src_file}" >"${dest_dir}${sub_dir}/${filename}.json" +done