diff --git a/.github/workflows/basic_ethereum.yml b/.github/workflows/basic_ethereum.yml new file mode 100644 index 0000000000..8382913431 --- /dev/null +++ b/.github/workflows/basic_ethereum.yml @@ -0,0 +1,28 @@ +name: basic_ethereum + +on: + push: + branches: [master] + pull_request: + paths: + - rust/basic_ethereum/** + - .github/workflows/basic_ethereum.yml + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + rust-basic_ethereum: + runs-on: ubuntu-24.04 + container: ghcr.io/dfinity/icp-dev-env-rust:1.0.1 + env: + ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + - name: Deploy and test + working-directory: rust/basic_ethereum + run: | + icp network start -d + icp deploy + bash test.sh diff --git a/rust/basic_ethereum/.devcontainer/devcontainer.json b/rust/basic_ethereum/.devcontainer/devcontainer.json deleted file mode 100644 index ebb0b8bcc6..0000000000 --- a/rust/basic_ethereum/.devcontainer/devcontainer.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "ICP Dev Environment", - "image": "ghcr.io/dfinity/icp-dev-env-slim:22", - "forwardPorts": [4943, 5173], - "portsAttributes": { - "4943": { - "label": "dfx", - "onAutoForward": "ignore" - }, - "5173": { - "label": "vite", - "onAutoForward": "openBrowser" - } - }, - "customizations": { - "vscode": { - "extensions": ["dfinity-foundation.vscode-motoko"] - } - } -} diff --git a/rust/basic_ethereum/BUILD.md b/rust/basic_ethereum/BUILD.md deleted file mode 100644 index 24cfcb7547..0000000000 --- a/rust/basic_ethereum/BUILD.md +++ /dev/null @@ -1,113 +0,0 @@ -# Continue building locally - -Projects deployed through ICP Ninja are temporary; they will only be live for 20 minutes before they are removed. The command-line tool `dfx` can be used to continue building your ICP Ninja project locally and deploy it to the mainnet. - -To migrate your ICP Ninja project off of the web browser and develop it locally, follow these steps. - -### 1. Install developer tools. - -You can install the developer tools natively or use Dev Containers. - -#### Option 1: Natively install developer tools - -> Installing `dfx` natively is currently only supported on macOS and Linux systems. On Windows, it is recommended to use the Dev Containers option. - -1. Install `dfx` with the following command: - -``` - -sh -ci "$(curl -fsSL https://internetcomputer.org/install.sh)" - -``` - -> On Apple Silicon (e.g., Apple M1 chip), make sure you have Rosetta installed (`softwareupdate --install-rosetta`). - -2. [Install NodeJS](https://nodejs.org/en/download/package-manager). - -3. For Rust projects, you will also need to: - -- Install [Rust](https://doc.rust-lang.org/cargo/getting-started/installation.html#install-rust-and-cargo): `curl https://sh.rustup.rs -sSf | sh` - -- Install [candid-extractor](https://crates.io/crates/candid-extractor): `cargo install candid-extractor` - -4. For Motoko projects, you will also need to: - -- Install the Motoko package manager [Mops](https://docs.mops.one/quick-start#2-install-mops-cli): `npm i -g ic-mops` - -Lastly, navigate into your project's directory that you downloaded from ICP Ninja. - -#### Option 2: Dev Containers - -Continue building your projects locally by installing the [Dev Container extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) for VS Code and [Docker](https://docs.docker.com/engine/install/). - -Make sure Docker is running, then navigate into your project's directory that you downloaded from ICP Ninja and start the Dev Container by selecting `Dev-Containers: Reopen in Container` in VS Code's command palette (F1 or Ctrl/Cmd+Shift+P). - -> Note that local development ports (e.g. the ports used by `dfx` or `vite`) are forwarded from the Dev Container to your local machine. In the VS code terminal, use Ctrl/Cmd+Click on the displayed local URLs to open them in your browser. To view the current port mappings, click the "Ports" tab in the VS Code terminal window. - -### 2. Start the local development environment. - -``` -dfx start --background -``` - -### 3. Create a local developer identity. - -To manage your project's canisters, it is recommended that you create a local [developer identity](https://internetcomputer.org/docs/building-apps/getting-started/identities) rather than use the `dfx` default identity that is not stored securely. - -To create a new identity, run the commands: - -``` - -dfx identity new IDENTITY_NAME - -dfx identity use IDENTITY_NAME - -``` - -Replace `IDENTITY_NAME` with your preferred identity name. The first command `dfx start --background` starts the local `dfx` processes, then `dfx identity new` will create a new identity and return your identity's seed phase. Be sure to save this in a safe, secure location. - -The third command `dfx identity use` will tell `dfx` to use your new identity as the active identity. Any canister smart contracts created after running `dfx identity use` will be owned and controlled by the active identity. - -Your identity will have a principal ID associated with it. Principal IDs are used to identify different entities on ICP, such as users and canisters. - -[Learn more about ICP developer identities](https://internetcomputer.org/docs/building-apps/getting-started/identities). - -### 4. Deploy the project locally. - -Deploy your project to your local developer environment with: - -``` -npm install -dfx deploy - -``` - -Your project will be hosted on your local machine. The local canister URLs for your project will be shown in the terminal window as output of the `dfx deploy` command. You can open these URLs in your web browser to view the local instance of your project. - -### 5. Obtain cycles. - -To deploy your project to the mainnet for long-term public accessibility, first you will need [cycles](https://internetcomputer.org/docs/building-apps/getting-started/tokens-and-cycles). Cycles are used to pay for the resources your project uses on the mainnet, such as storage and compute. - -> This cost model is known as ICP's [reverse gas model](https://internetcomputer.org/docs/building-apps/essentials/gas-cost), where developers pay for their project's gas fees rather than users pay for their own gas fees. This model provides an enhanced end user experience since they do not need to hold tokens or sign transactions when using a dapp deployed on ICP. - -> Learn how much a project may cost by using the [pricing calculator](https://internetcomputer.org/docs/building-apps/essentials/cost-estimations-and-examples). - -Cycles can be obtained through [converting ICP tokens into cycles using `dfx`](https://internetcomputer.org/docs/building-apps/developer-tools/dfx/dfx-cycles#dfx-cycles-convert). - -### 6. Deploy to the mainnet. - -Once you have cycles, run the command: - -``` - -dfx deploy --network ic - -``` - -After your project has been deployed to the mainnet, it will continuously require cycles to pay for the resources it uses. You will need to [top up](https://internetcomputer.org/docs/building-apps/canister-management/topping-up) your project's canisters or set up automatic cycles management through a service such as [CycleOps](https://cycleops.dev/). - -> If your project's canisters run out of cycles, they will be removed from the network. - -## Additional examples - -Additional code examples and sample applications can be found in the [DFINITY examples repo](https://github.com/dfinity/examples). diff --git a/rust/basic_ethereum/Cargo.lock b/rust/basic_ethereum/Cargo.lock index f33f3b585e..09bd96c5b3 100644 --- a/rust/basic_ethereum/Cargo.lock +++ b/rust/basic_ethereum/Cargo.lock @@ -2,21 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - [[package]] name = "aho-corasick" version = "1.1.3" @@ -102,12 +87,6 @@ version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" -[[package]] -name = "arbitrary" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" - [[package]] name = "ark-ff" version = "0.3.0" @@ -138,7 +117,7 @@ dependencies = [ "ark-std 0.4.0", "derivative", "digest 0.10.7", - "itertools 0.10.5", + "itertools", "num-bigint", "num-traits", "paste", @@ -245,20 +224,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] -name = "ascii-canvas" -version = "3.0.0" +name = "async-trait" +version = "0.1.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ - "term", + "proc-macro2", + "quote", + "syn 2.0.104", ] -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - [[package]] name = "auto_impl" version = "1.3.0" @@ -277,18 +252,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] -name = "backtrace" -version = "0.3.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +name = "backend" +version = "0.1.0" dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets 0.52.6", + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "candid", + "evm_rpc_client", + "evm_rpc_types", + "getrandom 0.2.16", + "ic-canister-runtime", + "ic-cdk", + "ic-cdk-management-canister", + "ic-ethereum-types", + "ic-secp256k1", + "ic-sha3 1.0.0 (git+https://github.com/dfinity/ic?tag=release-2025-07-03_03-27-base)", + "num", + "num-traits", + "serde", + "serde_bytes", + "serde_json", ] [[package]] @@ -303,45 +287,12 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - [[package]] name = "base64ct" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" -[[package]] -name = "basic_ethereum" -version = "0.1.0" -dependencies = [ - "alloy-consensus", - "alloy-eips", - "alloy-primitives", - "candid", - "evm-rpc-canister-types", - "getrandom 0.2.16", - "ic-cdk 0.15.2", - "ic-ethereum-types", - "ic-secp256k1", - "ic-sha3 1.0.0 (git+https://github.com/dfinity/ic?tag=release-2025-07-03_03-27-base)", - "num", - "num-traits", - "serde", - "serde_bytes", - "serde_json", -] - -[[package]] -name = "beef" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" - [[package]] name = "binread" version = "2.2.0" @@ -365,30 +316,15 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "bit-set" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" -dependencies = [ - "bit-vec 0.6.3", -] - [[package]] name = "bit-set" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" dependencies = [ - "bit-vec 0.8.0", + "bit-vec", ] -[[package]] -name = "bit-vec" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" - [[package]] name = "bit-vec" version = "0.8.0" @@ -434,12 +370,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "bumpalo" -version = "3.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" - [[package]] name = "byte-slice-cast" version = "1.2.3" @@ -475,9 +405,9 @@ dependencies = [ [[package]] name = "candid" -version = "0.10.14" +version = "0.10.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d90f5a1426d0489283a0bd5da9ed406fb3e69597e0d823dcb88a1965bb58d2" +checksum = "f8f781afa4a1303e3eab4ada0720a874942bcfa936ce01b816ac6378945c43a9" dependencies = [ "anyhow", "binread", @@ -498,9 +428,9 @@ dependencies = [ [[package]] name = "candid_derive" -version = "0.6.6" +version = "0.10.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3de398570c386726e7a59d9887b68763c481477f9a043fb998a2e09d428df1a9" +checksum = "ad6ae8e7944dd0035651bc0e7b3a3e4cb16f5fc43f8ae4fd76b36ff2cd52759f" dependencies = [ "lazy_static", "proc-macro2", @@ -509,22 +439,30 @@ dependencies = [ ] [[package]] -name = "candid_parser" -version = "0.1.4" +name = "canlog" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48a3da76f989cd350b7342c64c6c6008341bb6186f6832ef04e56dc50ba0fd76" +checksum = "bd21b4c7140d033fe006495a65ec5ae24d79219eca550a74e0ba140ff9aa71dc" dependencies = [ - "anyhow", "candid", - "codespan-reporting", - "convert_case 0.6.0", - "hex", - "lalrpop", - "lalrpop-util", - "logos", - "num-bigint", - "pretty", - "thiserror 1.0.69", + "canlog_derive", + "ic-canister-log", + "ic0", + "regex", + "serde", + "serde_json", +] + +[[package]] +name = "canlog_derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6620814f83b784938b29ca6ca8867967a93a4f7f08c1b7ec6256d12c1b53abe8" +dependencies = [ + "darling 0.20.11", + "proc-macro2", + "quote", + "syn 2.0.104", ] [[package]] @@ -542,16 +480,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" -[[package]] -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] - [[package]] name = "const-hex" version = "1.14.1" @@ -597,31 +525,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" -[[package]] -name = "convert_case" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - [[package]] name = "cpufeatures" version = "0.2.17" @@ -668,6 +571,75 @@ dependencies = [ "typenum", ] +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core 0.20.11", + "darling_macro 0.20.11", +] + +[[package]] +name = "darling" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +dependencies = [ + "darling_core 0.23.0", + "darling_macro 0.23.0", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.104", +] + +[[package]] +name = "darling_core" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.104", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core 0.20.11", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "darling_macro" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +dependencies = [ + "darling_core 0.23.0", + "quote", + "syn 2.0.104", +] + [[package]] name = "data-encoding" version = "2.9.0" @@ -711,7 +683,7 @@ version = "0.99.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" dependencies = [ - "convert_case 0.4.0", + "convert_case", "proc-macro2", "quote", "rustc_version 0.4.1", @@ -739,27 +711,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if", - "dirs-sys-next", -] - -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - [[package]] name = "displaydoc" version = "0.2.5" @@ -811,24 +762,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "ena" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5" -dependencies = [ - "log", -] - -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - [[package]] name = "equivalent" version = "1.0.2" @@ -846,18 +779,36 @@ dependencies = [ ] [[package]] -name = "evm-rpc-canister-types" -version = "0.1.3" +name = "evm_rpc_client" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43365151c7779a57aacf1e4370519c9c1250fd09ca6c02c77e6b6f7a9335052c" +checksum = "023af59e299f1591daf2ac441129ba338fc9c6759c884bd05e222a99ffc19c9c" dependencies = [ + "async-trait", "candid", - "candid_parser", - "ic-cdk 0.14.2", - "reqwest", + "evm_rpc_types", + "ic-canister-runtime", "serde", - "serde_bytes", "serde_json", + "strum 0.27.2", +] + +[[package]] +name = "evm_rpc_types" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c348e834a97e2ca221259d6ec813009346904860be95cf756123630c44b79d5c" +dependencies = [ + "candid", + "canlog", + "hex", + "ic-error-types", + "ic-management-canister-types 0.5.0", + "num-bigint", + "serde", + "strum 0.27.2", + "thiserror 2.0.18", + "url", ] [[package]] @@ -910,33 +861,12 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "form_urlencoded" version = "1.2.1" @@ -952,56 +882,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" -[[package]] -name = "futures-channel" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-io" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" - -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - -[[package]] -name = "futures-task" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" - -[[package]] -name = "futures-util" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" -dependencies = [ - "futures-core", - "futures-io", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - [[package]] name = "generic-array" version = "0.14.7" @@ -1036,12 +916,6 @@ dependencies = [ "wasi 0.14.2+wasi-0.2.4", ] -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - [[package]] name = "glob" version = "0.3.2" @@ -1059,31 +933,18 @@ dependencies = [ "subtle", ] -[[package]] -name = "h2" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17da50a276f1e01e0ba6c029e47b7100754904ee8a278f886546e98575380785" -dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - [[package]] name = "hashbrown" version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" version = "0.5.2" @@ -1115,195 +976,126 @@ dependencies = [ ] [[package]] -name = "http" -version = "1.3.1" +name = "ic-canister-log" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +checksum = "cb82c4f617ecff6e452fe65af0489626ec7330ffe3eedd9ea14e6178eea48d1a" dependencies = [ - "bytes", - "fnv", - "itoa", + "serde", ] [[package]] -name = "http-body" -version = "1.0.1" +name = "ic-canister-runtime" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +checksum = "da5bf7cb1426e5485da0e2b0b8da4f11b7b24a2a56cb127b53720ecf8495c2e0" dependencies = [ - "bytes", - "http", + "async-trait", + "candid", + "ic-cdk", + "ic-cdk-management-canister", + "ic-error-types", + "serde", + "thiserror 2.0.18", ] [[package]] -name = "http-body-util" -version = "0.1.3" +name = "ic-cdk" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +checksum = "6a7971f4983db147afbbc4e7f87f60b09fcd60ac707af37ff3d2468dcddbf551" dependencies = [ - "bytes", - "futures-core", - "http", - "http-body", + "candid", + "ic-cdk-executor", + "ic-cdk-macros", + "ic-error-types", + "ic0", "pin-project-lite", + "serde", + "thiserror 2.0.18", ] [[package]] -name = "httparse" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" - -[[package]] -name = "hyper" -version = "1.6.0" +name = "ic-cdk-executor" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +checksum = "33716b730ded33690b8a704bff3533fda87d229e58046823647d28816e9bcee7" dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "itoa", - "pin-project-lite", + "ic0", + "slotmap", "smallvec", - "tokio", - "want", -] - -[[package]] -name = "hyper-rustls" -version = "0.27.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" -dependencies = [ - "http", - "hyper", - "hyper-util", - "rustls", - "rustls-pki-types", - "tokio", - "tokio-rustls", - "tower-service", -] - -[[package]] -name = "hyper-tls" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" -dependencies = [ - "bytes", - "http-body-util", - "hyper", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", ] [[package]] -name = "hyper-util" -version = "0.1.15" +name = "ic-cdk-macros" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f66d5bd4c6f02bf0542fad85d626775bab9258cf795a4256dcaf3161114d1df" +checksum = "a7c20c002200c720958f321bb78b4d4987fc2c380bf9ef69ed4404730810f45f" dependencies = [ - "base64 0.22.1", - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "http", - "http-body", - "hyper", - "ipnet", - "libc", - "percent-encoding", - "pin-project-lite", - "socket2", - "system-configuration", - "tokio", - "tower-service", - "tracing", - "windows-registry", + "candid", + "darling 0.23.0", + "proc-macro2", + "quote", + "syn 2.0.104", ] [[package]] -name = "ic-cdk" -version = "0.14.2" +name = "ic-cdk-management-canister" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae86da27ed9cebcfc7889a9f5cec5bdf52b4dcb9e2e6f1baf823f291eeb36279" +checksum = "92c1319a274caebf0ab70ab826b8905c29e8563498289356b9a59464f2a85c56" dependencies = [ "candid", - "ic-cdk-executor", - "ic-cdk-macros 0.14.0", - "ic0", + "ic-cdk", + "ic-management-canister-types 0.7.1", "serde", "serde_bytes", + "thiserror 2.0.18", ] [[package]] -name = "ic-cdk" -version = "0.15.2" +name = "ic-error-types" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3234b25809a51792d33a8ac3859cc72881db7478055cdcb25fc0faf5741b0413" +checksum = "bbeeb3d91aa179d6496d7293becdacedfc413c825cac79fd54ea1906f003ee55" dependencies = [ - "candid", - "ic-cdk-executor", - "ic-cdk-macros 0.15.0", - "ic0", "serde", - "serde_bytes", + "strum 0.26.3", + "strum_macros 0.26.4", ] [[package]] -name = "ic-cdk-executor" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "903057edd3d4ff4b3fe44a64eaee1ceb73f579ba29e3ded372b63d291d7c16c2" - -[[package]] -name = "ic-cdk-macros" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01dc6bc425ec048d6ac4137c7c0f2cfbd6f8b0be8efc568feae2b265f566117c" +name = "ic-ethereum-types" +version = "1.0.0" +source = "git+https://github.com/dfinity/ic?tag=release-2025-07-03_03-27-base#e915efecc8af90993ccfc499721ebe826aadba60" dependencies = [ - "candid", - "proc-macro2", - "quote", + "hex", + "ic-sha3 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "minicbor", + "minicbor-derive", "serde", - "serde_tokenstream", - "syn 2.0.104", ] [[package]] -name = "ic-cdk-macros" -version = "0.15.0" +name = "ic-management-canister-types" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3af44fb4ec3a4b18831c9d3303ca8fa2ace846c4022d50cb8df4122635d3782e" +checksum = "3149217e24186df3f13dc45eee14cdb3e5cad07d0b2b67bd53555c1c55462957" dependencies = [ "candid", - "proc-macro2", - "quote", "serde", - "serde_tokenstream", - "syn 2.0.104", + "serde_bytes", ] [[package]] -name = "ic-ethereum-types" -version = "1.0.0" -source = "git+https://github.com/dfinity/ic?tag=release-2025-07-03_03-27-base#e915efecc8af90993ccfc499721ebe826aadba60" +name = "ic-management-canister-types" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51705516ed4d23f24e8d714a70fe9d7ec17106cfd830d5434a1b29f583ef70ee" dependencies = [ - "hex", - "ic-sha3 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "minicbor", - "minicbor-derive", + "candid", "serde", + "serde_bytes", ] [[package]] @@ -1342,9 +1134,9 @@ dependencies = [ [[package]] name = "ic0" -version = "0.23.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de254dd67bbd58073e23dc1c8553ba12fa1dc610a19de94ad2bbcd0460c067f" +checksum = "c77c8932bff1f09502d0d8c079d5a206a06afe523e35e816162cf4d30b5bf80d" [[package]] name = "ic_principal" @@ -1352,7 +1144,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1762deb6f7c8d8c2bdee4b6c5a47b60195b74e9b5280faa5ba29692f8e17429c" dependencies = [ - "arbitrary", "crc32fast", "data-encoding", "serde", @@ -1446,6 +1237,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "1.0.3" @@ -1497,33 +1294,6 @@ dependencies = [ "hashbrown", ] -[[package]] -name = "io-uring" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013" -dependencies = [ - "bitflags", - "cfg-if", - "libc", -] - -[[package]] -name = "ipnet" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" - -[[package]] -name = "iri-string" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" -dependencies = [ - "memchr", - "serde", -] - [[package]] name = "itertools" version = "0.10.5" @@ -1533,31 +1303,12 @@ dependencies = [ "either", ] -[[package]] -name = "itertools" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" -dependencies = [ - "either", -] - [[package]] name = "itoa" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" -[[package]] -name = "js-sys" -version = "0.3.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" -dependencies = [ - "once_cell", - "wasm-bindgen", -] - [[package]] name = "k256" version = "0.13.4" @@ -1591,37 +1342,6 @@ dependencies = [ "sha3-asm", ] -[[package]] -name = "lalrpop" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cb077ad656299f160924eb2912aa147d7339ea7d69e1b5517326fdcec3c1ca" -dependencies = [ - "ascii-canvas", - "bit-set 0.5.3", - "ena", - "itertools 0.11.0", - "lalrpop-util", - "petgraph", - "pico-args", - "regex", - "regex-syntax 0.8.5", - "string_cache", - "term", - "tiny-keccak", - "unicode-xid", - "walkdir", -] - -[[package]] -name = "lalrpop-util" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" -dependencies = [ - "regex-automata", -] - [[package]] name = "lazy_static" version = "1.5.0" @@ -1646,16 +1366,6 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" -[[package]] -name = "libredox" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1580801010e535496706ba011c15f8532df6b42297d2e471fec38ceadd8c0638" -dependencies = [ - "bitflags", - "libc", -] - [[package]] name = "linux-raw-sys" version = "0.9.4" @@ -1668,66 +1378,12 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" -[[package]] -name = "lock_api" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" - -[[package]] -name = "logos" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c000ca4d908ff18ac99b93a062cb8958d331c3220719c52e77cb19cc6ac5d2c1" -dependencies = [ - "logos-derive", -] - -[[package]] -name = "logos-codegen" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc487311295e0002e452025d6b580b77bb17286de87b57138f3b5db711cded68" -dependencies = [ - "beef", - "fnv", - "proc-macro2", - "quote", - "regex-syntax 0.6.29", - "syn 2.0.104", -] - -[[package]] -name = "logos-derive" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbfc0d229f1f42d790440136d941afd806bc9e949e2bcb8faa813b0f00d1267e" -dependencies = [ - "logos-codegen", -] - [[package]] name = "memchr" version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - [[package]] name = "minicbor" version = "0.19.1" @@ -1748,49 +1404,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", -] - -[[package]] -name = "mio" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" -dependencies = [ - "libc", - "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys 0.59.0", -] - -[[package]] -name = "native-tls" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "new_debug_unreachable" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" - [[package]] name = "num" version = "0.4.3" @@ -1882,65 +1495,12 @@ dependencies = [ "libc", ] -[[package]] -name = "object" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell" version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" -[[package]] -name = "openssl" -version = "0.10.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" -dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - -[[package]] -name = "openssl-probe" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" - -[[package]] -name = "openssl-sys" -version = "0.9.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "parity-scale-codec" version = "3.7.5" @@ -1970,41 +1530,18 @@ dependencies = [ ] [[package]] -name = "parking_lot" -version = "0.12.4" +name = "paste" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" -dependencies = [ - "lock_api", - "parking_lot_core", -] +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] -name = "parking_lot_core" -version = "0.9.11" +name = "pem" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.52.6", -] - -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - -[[package]] -name = "pem" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" -dependencies = [ - "base64 0.13.1", + "base64", ] [[package]] @@ -2029,46 +1566,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323" dependencies = [ "memchr", - "thiserror 2.0.12", + "thiserror 2.0.18", "ucd-trie", ] -[[package]] -name = "petgraph" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" -dependencies = [ - "fixedbitset", - "indexmap", -] - -[[package]] -name = "phf_shared" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pico-args" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" - [[package]] name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pkcs8" @@ -2080,12 +1586,6 @@ dependencies = [ "spki", ] -[[package]] -name = "pkg-config" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" - [[package]] name = "potential_utf" version = "0.1.2" @@ -2110,12 +1610,6 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - [[package]] name = "pretty" version = "0.12.4" @@ -2149,9 +1643,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] @@ -2162,15 +1656,15 @@ version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fcdab19deb5195a31cf7726a210015ff1496ba1464fd42cb4f537b8b01b471f" dependencies = [ - "bit-set 0.8.0", - "bit-vec 0.8.0", + "bit-set", + "bit-vec", "bitflags", "lazy_static", "num-traits", "rand 0.9.1", "rand_chacha 0.9.0", "rand_xorshift", - "regex-syntax 0.8.5", + "regex-syntax", "rusty-fork", "tempfile", "unarray", @@ -2280,26 +1774,6 @@ dependencies = [ "rand_core 0.9.3", ] -[[package]] -name = "redox_syscall" -version = "0.5.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" -dependencies = [ - "bitflags", -] - -[[package]] -name = "redox_users" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" -dependencies = [ - "getrandom 0.2.16", - "libredox", - "thiserror 1.0.69", -] - [[package]] name = "regex" version = "1.11.1" @@ -2309,7 +1783,7 @@ dependencies = [ "aho-corasick", "memchr", "regex-automata", - "regex-syntax 0.8.5", + "regex-syntax", ] [[package]] @@ -2320,63 +1794,15 @@ checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.5", + "regex-syntax", ] -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - [[package]] name = "regex-syntax" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" -[[package]] -name = "reqwest" -version = "0.12.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbc931937e6ca3a06e3b6c0aa7841849b160a90351d6ab467a8b9b9959767531" -dependencies = [ - "base64 0.22.1", - "bytes", - "encoding_rs", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-rustls", - "hyper-tls", - "hyper-util", - "js-sys", - "log", - "mime", - "native-tls", - "percent-encoding", - "pin-project-lite", - "rustls-pki-types", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "tokio", - "tokio-native-tls", - "tower", - "tower-http", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - [[package]] name = "rfc6979" version = "0.4.0" @@ -2387,20 +1813,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "ring" -version = "0.17.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" -dependencies = [ - "cc", - "cfg-if", - "getrandom 0.2.16", - "libc", - "untrusted", - "windows-sys 0.52.0", -] - [[package]] name = "rlp" version = "0.5.2" @@ -2444,12 +1856,6 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" -[[package]] -name = "rustc-demangle" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" - [[package]] name = "rustc-hex" version = "2.1.0" @@ -2487,39 +1893,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "rustls" -version = "0.23.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7160e3e10bf4535308537f3c4e1641468cd0e485175d6163087c0393c7d46643" -dependencies = [ - "once_cell", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-pki-types" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" -dependencies = [ - "zeroize", -] - -[[package]] -name = "rustls-webpki" -version = "0.103.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" -dependencies = [ - "ring", - "rustls-pki-types", - "untrusted", -] - [[package]] name = "rustversion" version = "1.0.21" @@ -2544,30 +1917,6 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "schannel" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - [[package]] name = "sec1" version = "0.7.3" @@ -2582,29 +1931,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "security-framework" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" -dependencies = [ - "bitflags", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "semver" version = "0.11.0" @@ -2670,30 +1996,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_tokenstream" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64060d864397305347a78851c51588fd283767e7e7589829e8121d65512340f1" -dependencies = [ - "proc-macro2", - "quote", - "serde", - "syn 2.0.104", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - [[package]] name = "sha2" version = "0.10.9" @@ -2749,21 +2051,18 @@ checksum = "297f631f50729c8c99b84667867963997ec0b50f32b2a7dbcab828ef0541e8bb" dependencies = [ "num-bigint", "num-traits", - "thiserror 2.0.12", + "thiserror 2.0.18", "time", ] [[package]] -name = "siphasher" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" - -[[package]] -name = "slab" -version = "0.4.10" +name = "slotmap" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" +checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038" +dependencies = [ + "version_check", +] [[package]] name = "smallvec" @@ -2771,16 +2070,6 @@ version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" -[[package]] -name = "socket2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - [[package]] name = "spki" version = "0.7.3" @@ -2817,15 +2106,52 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] -name = "string_cache" -version = "0.8.9" +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros 0.26.4", +] + +[[package]] +name = "strum" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" +dependencies = [ + "strum_macros 0.27.2", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ - "new_debug_unreachable", - "parking_lot", - "phf_shared", - "precomputed-hash", + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.104", +] + +[[package]] +name = "strum_macros" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.104", ] [[package]] @@ -2856,15 +2182,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "sync_wrapper" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" -dependencies = [ - "futures-core", -] - [[package]] name = "synstructure" version = "0.13.2" @@ -2876,27 +2193,6 @@ dependencies = [ "syn 2.0.104", ] -[[package]] -name = "system-configuration" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" -dependencies = [ - "bitflags", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "tap" version = "1.0.1" @@ -2916,26 +2212,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "term" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" -dependencies = [ - "dirs-next", - "rustversion", - "winapi", -] - -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - [[package]] name = "thiserror" version = "1.0.69" @@ -2947,11 +2223,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.12" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ - "thiserror-impl 2.0.12", + "thiserror-impl 2.0.18", ] [[package]] @@ -2967,9 +2243,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.12" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", @@ -3035,56 +2311,6 @@ dependencies = [ "zerovec", ] -[[package]] -name = "tokio" -version = "1.46.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc3a2344dafbe23a245241fe8b09735b521110d30fcefbbd5feb1797ca35d17" -dependencies = [ - "backtrace", - "bytes", - "io-uring", - "libc", - "mio", - "pin-project-lite", - "slab", - "socket2", - "windows-sys 0.52.0", -] - -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - -[[package]] -name = "tokio-rustls" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" -dependencies = [ - "rustls", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - [[package]] name = "toml_datetime" version = "0.6.11" @@ -3102,76 +2328,6 @@ dependencies = [ "winnow", ] -[[package]] -name = "tower" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" -dependencies = [ - "futures-core", - "futures-util", - "pin-project-lite", - "sync_wrapper", - "tokio", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-http" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" -dependencies = [ - "bitflags", - "bytes", - "futures-util", - "http", - "http-body", - "iri-string", - "pin-project-lite", - "tower", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-layer" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" - -[[package]] -name = "tower-service" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" - -[[package]] -name = "tracing" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" -dependencies = [ - "pin-project-lite", - "tracing-core", -] - -[[package]] -name = "tracing-core" -version = "0.1.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" -dependencies = [ - "once_cell", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - [[package]] name = "typed-arena" version = "2.0.2" @@ -3214,12 +2370,6 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" -[[package]] -name = "unicode-segmentation" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" - [[package]] name = "unicode-width" version = "0.1.14" @@ -3232,12 +2382,6 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - [[package]] name = "url" version = "2.5.4" @@ -3261,12 +2405,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - [[package]] name = "version_check" version = "0.9.5" @@ -3282,25 +2420,6 @@ dependencies = [ "libc", ] -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" @@ -3316,162 +2435,6 @@ dependencies = [ "wit-bindgen-rt", ] -[[package]] -name = "wasm-bindgen" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.104", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" -dependencies = [ - "cfg-if", - "js-sys", - "once_cell", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "web-sys" -version = "0.3.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-link" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" - -[[package]] -name = "windows-registry" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" -dependencies = [ - "windows-link", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-result" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-strings" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-sys" version = "0.59.0" diff --git a/rust/basic_ethereum/Cargo.toml b/rust/basic_ethereum/Cargo.toml index ad2551f2da..d1e49e317a 100644 --- a/rust/basic_ethereum/Cargo.toml +++ b/rust/basic_ethereum/Cargo.toml @@ -1,26 +1,3 @@ -[package] -name = "basic_ethereum" -version = "0.1.0" -edition = "2021" - -[lib] -crate-type = ["cdylib"] - -[dependencies] -alloy-consensus = "0.1.3" -alloy-eips = "0.1.3" -alloy-primitives = "0.7.6" -candid = "0.10" -evm-rpc-canister-types = "0.1.2" -# transitive dependency: ic-crypto-ecdsa-secp256k1 -> k256 -> ecdsa -> elliptic-curve -> crypto-bigint -> rand_core -> getrandom -# See https://forum.dfinity.org/t/module-imports-function-wbindgen-describe-from-wbindgen-placeholder-that-is-not-exported-by-the-runtime/11545/8 -getrandom = { version = "*", default-features = false, features = ["custom"] } -ic-cdk = "0.15" -ic-secp256k1 = { git = "https://github.com/dfinity/ic", tag = "release-2025-07-03_03-27-base", package = "ic-secp256k1" } -ic-sha3 = { git = "https://github.com/dfinity/ic", tag = "release-2025-07-03_03-27-base", package = "ic-sha3" } -ic-ethereum-types = { git = "https://github.com/dfinity/ic", tag = "release-2025-07-03_03-27-base", package = "ic-ethereum-types" } -serde = "1.0" -serde_json = "1.0" -serde_bytes = "0.11.15" -num-traits = "0.2.19" -num = "0.4.3" +[workspace] +members = ["backend"] +resolver = "2" diff --git a/rust/basic_ethereum/README.md b/rust/basic_ethereum/README.md index 1733e2d771..25c4436b33 100644 --- a/rust/basic_ethereum/README.md +++ b/rust/basic_ethereum/README.md @@ -1,173 +1,126 @@ # Basic Ethereum -This tutorial will walk you through how to deploy a -sample [canister smart contract](https://internetcomputer.org/docs/current/developer-docs/multi-chain/ethereum/overview) -**that can send and receive Ether (ETH)** on the Internet Computer. +This example demonstrates how to deploy a canister smart contract on the Internet Computer that can **send and receive Ether (ETH)** on the Ethereum network. The canister uses threshold ECDSA to sign Ethereum transactions and HTTPS outcalls to communicate with the Ethereum network via the EVM RPC canister. ## Architecture -This example internally leverages -the [threshold ECDSA](https://internetcomputer.org/docs/current/developer-docs/smart-contracts/encryption/t-ecdsa) -and [HTTPs outcalls](https://internetcomputer.org/docs/current/developer-docs/smart-contracts/advanced-features/https-outcalls/https-outcalls-overview) -features of the Internet Computer. +This example internally leverages: +- [Threshold ECDSA](https://docs.internetcomputer.org/concepts/chain-key-cryptography/#chain-key-signatures-threshold-ecdsa-and-schnorr): Each user's Ethereum address is derived deterministically from the canister's master ECDSA key using a derivation path based on the user's IC principal. This means each user has a unique, stable Ethereum address controlled by the canister. +- [HTTPS outcalls](https://docs.internetcomputer.org/concepts/https-outcalls): The canister communicates with the Ethereum network via the [EVM RPC canister](https://github.com/dfinity/evm-rpc-canister) (canister ID `7hfb6-caaaa-aaaar-qadga-cai` on ICP mainnet), which forwards requests to public Ethereum RPC providers such as `https://ethereum-sepolia-rpc.publicnode.com`. -For a deeper understanding of the ICP < > ETH integration, see -the [Ethereum integration overview](https://internetcomputer.org/docs/current/developer-docs/multi-chain/ethereum/overview). +For a deeper understanding of the ICP ↔ ETH integration, see the [Ethereum integration](https://docs.internetcomputer.org/concepts/chain-fusion/ethereum). -## Deploying from ICP Ninja +## Build and deploy from the command line -When viewing this project in ICP Ninja, you can deploy it directly to the mainnet for free by clicking "Run" in the upper right corner. Open this project in ICP Ninja: +### Prerequisites -[![](https://icp.ninja/assets/open.svg)](https://icp.ninja/i?g=https://github.com/dfinity/examples/rust/basic_ethereum) +- Node.js +- icp-cli: `npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm` -## Deploying with `dfx` - -- [x] Install the [IC SDK](https://internetcomputer.org/docs/current/developer-docs/getting-started/install). - -## Step 1: Building and deploying sample code - -### Clone the smart contract - -To clone and build the smart contract in **Rust**: +### Install ```bash git clone https://github.com/dfinity/examples cd examples/rust/basic_ethereum -git submodule update --init --recursive ``` -**If you are using MacOS, you'll need to install Homebrew and run `brew install llvm` to be able to compile the example. -** - -### Acquire cycles to deploy - -Deploying to the Internet Computer requires [cycles](https://internetcomputer.org/docs/current/developer-docs/getting-started/tokens-and-cycles) (the equivalent of "gas" on other blockchains). +### Deploy and test locally -### Deploy the smart contract to the Internet Computer +The local icp-cli network supports real HTTPS outcalls, so `get_balance`, `transaction_count`, and `transaction_count_with_client` work against live Ethereum Sepolia data without deploying to ICP mainnet. To query Ethereum mainnet data instead, pass `--args '(opt record {ethereum_network = opt variant {Mainnet}})'` to `icp deploy`. ```bash -dfx deploy --ic basic_ethereum --argument '(opt record {ethereum_network = opt variant {Sepolia}; ecdsa_key_name = opt variant {TestKey1}})' +icp network start -d +icp deploy +bash test.sh +icp network stop ``` -#### What this does +`bash test.sh` verifies address derivation (threshold ECDSA), queries a known funded Sepolia address's balance via the raw EVM RPC canister interface, and queries its transaction count (nonce) via the high-level `evm_rpc_client` — demonstrating both usage patterns side by side. -- `dfx deploy` tells the command line interface to `deploy` the smart contract -- `--ic` tells the command line to deploy the smart contract to the mainnet ICP blockchain -- `--argument (opt record {ethereum_network = opt variant {Sepolia}; ecdsa_key_name = opt variant {TestKey1}})` - initializes the smart contract with the provided arguments: - - `ethereum_network = opt variant {Sepolia}`: the canister uses - the [Ethereum Testnet Sepolia](https://github.com/ethereum-lists/chains/blob/master/_data/chains/eip155-11155111.json) - network. - - `ecdsa_key_name = opt variant {TestKey1}`: the canister uses a test key for signing via threshold ECDSA that is - available on the ICP mainnet. - See [signing messages](https://internetcomputer.org/docs/current/developer-docs/smart-contracts/encryption/signing-messages#signing-messages-1) - for more details. +`send_eth` requires a funded Ethereum address and is not covered in the automated tests. See [Sending ETH](#sending-eth) below. -If successful, you should see an output that looks like this: +### Deploy to ICP mainnet ```bash -Deploying: basic_ethereum -Building canisters... -... -Deployed canisters. -URLs: -Candid: - basic_ethereum: https://a4gq6-oaaaa-aaaab-qaa4q-cai.raw.icp0.io/?id= +icp deploy -e ic ``` -Your canister is live and ready to use! You can interact with it using either the command line or using the Candid UI, -which is the link you see in the output above. +This deploys only the backend canister and points it to the [shared EVM RPC canister](https://github.com/dfinity/evm-rpc-canister) (`7hfb6-caaaa-aaaar-qadga-cai`) already running on ICP mainnet. The default configuration uses Ethereum Sepolia testnet with `test_key_1` — suitable for testing with free Sepolia ETH from a faucet. -In the output above, to see the Candid Web UI for your ethereum canister, you would use the -URL `https://a4gq6-oaaaa-aaaab-qaa4q-cai.raw.icp0.io/?id=`. You should see the methods specified in the Candid file `basic_ethereum.did`. +To deploy for production use on Ethereum mainnet, update the `init_args` in `icp.yaml` to use `variant {Mainnet}` and `"key_1"` — see the comment in `icp.yaml` for the exact value. -## Step 2: Generating an Ethereum address +## Interacting with the deployed canister + +### Get your Ethereum address + +Each IC principal gets a unique, stable Ethereum address controlled by this canister. The address is derived deterministically from the principal using the canister's threshold ECDSA key — the same principal always maps to the same address. + +Passing `null` returns the address for your own IC principal (the identity you are calling with): + +```bash +icp canister call backend ethereum_address '(null)' +# Returns your Ethereum address, e.g. ("0x378a452B20d1f06008C06c581b1656BdC5313c0C") +``` -An Ethereum address can be derived from an ECDSA public key. To derive a user's specific address, identified on the IC -by a principal, the canister uses its own threshold ECDSA public key to derive a new public key deterministically for -each requested principal. To retrieve your Ethereum address, you can call the `ethereum_address` method on the -previously deployed canister: +You can also look up the address for any other IC principal: -```shell -dfx canister --ic call basic_ethereum ethereum_address +```bash +icp canister call backend ethereum_address '(opt principal "hkroy-sm7vs-yyjs7-ekppe-qqnwx-hm4zf-n7ybs-titsi-k6e3k-ucuiu-uqe")' +# Returns e.g. ("0x8d68f7B3cdb40A2E77071077658b01A9EA4B040F") ``` -This will return an Ethereum address such as `("0x378a452B20d1f06008C06c581b1656BdC5313c0C")` that is tied to your -principal. Your address will be different. You can view such addresses on any Ethereum block explorer such as [Etherscan](https://etherscan.io/). +### Check a balance and transaction count -If you want to send some ETH to someone else, you can also use the above method to enquire about their Ethereum address -given their IC principal: +Query the ETH balance (in Wei) for any Ethereum address: -```shell -dfx canister --ic call basic_ethereum ethereum_address '(opt principal "hkroy-sm7vs-yyjs7-ekppe-qqnwx-hm4zf-n7ybs-titsi-k6e3k-ucuiu-uqe")' +```bash +icp canister call backend get_balance '(opt "0x378a452B20d1f06008C06c581b1656BdC5313c0C")' ``` -This will return a different Ethereum address as the one above, such -as `("0x8d68f7B3cdb40A2E77071077658b01A9EA4B040F")`. +Query the transaction count for any Ethereum address using the high-level `EvmRpcClient`. This calls `eth_getTransactionCount`, which returns the **nonce** — the number of transactions sent *from* the address (outgoing only, not received): -## Step 3: Receiving ETH +```bash +icp canister call backend transaction_count_with_client '(opt "0x378a452B20d1f06008C06c581b1656BdC5313c0C", null)' +``` -Now that you have your Ethereum address, let us send some (Sepolia) ETH to it: +Passing `null` uses the derived Ethereum address of your calling IC principal: -1. Get some Sepolia ETH if you don't have any. You can for example use [this faucet](https://www.alchemy.com/faucets/ethereum-sepolia). -2. Send some Sepolia ETH to the address you obtained in the previous step. You can use any Ethereum wallet (e.g., - Metamask) to do so. +```bash +icp canister call backend transaction_count_with_client '(null, null)' +``` -Once the transaction has at least one confirmation, which can take a few seconds, -you'll be able to see it in your Ethereum address's balance, which should be visible in an Ethereum block explorer, -e.g., https://sepolia.etherscan.io/address/0x378a452b20d1f06008c06c581b1656bdc5313c0c. +### Sending ETH -## Step 4: Sending ETH +To send ETH, your derived Ethereum address must be funded first: -You can send ETH using the `send_eth` endpoint on your canister, specifying an Ethereum destination address and an -amount in the smallest unit (Wei). For example, to send 1 Wei to `0xdd2851Cdd40aE6536831558DD46db62fAc7A844d`, run the following command: +1. Get your Ethereum address (see above) — this is the address managed by the canister for your IC principal. +2. Get some Sepolia ETH from [Alchemy's Sepolia faucet](https://www.alchemy.com/faucets/ethereum-sepolia). +3. Send Sepolia ETH to your address using any Ethereum wallet (e.g. MetaMask). +4. Once the transaction has at least one confirmation, verify the balance: -```shell -dfx canister --ic call basic_ethereum send_eth '("0xdd2851Cdd40aE6536831558DD46db62fAc7A844d", 1)' +```bash +icp canister call backend get_balance '(null)' ``` -The `send_eth` endpoint sends ETH by executing the following steps: +Then send ETH (amount in Wei): -1. Retrieving the transaction count for the sender's address at `Latest` block height. This is necessary because - Ethereum transactions for a given sender's address are ordered by a `nonce`, which is a monotonically incrementally - increasing non-negative counter. -2. Estimating the current transaction fees. For simplicity, the current gas fees are hard-coded with a generous limit. A - real world application would dynamically fetch the latest transaction fees, for example using - the [`eth_feeHistory`](https://github.com/internet-computer-protocol/evm-rpc-canister/blob/3cce151d4c1338d83e6741afa354ccf11dff41e8/candid/evm_rpc.did#L254) - method in the [EVM-RPC canister](https://github.com/internet-computer-protocol/evm-rpc-canister/tree/main). -3. Building an Ethereum transaction ([EIP-1559](https://eips.ethereum.org/EIPS/eip-1559)) to send the specified amount - to the given receiver's address. -4. Signing the Ethereum transaction using - the [sign_with_ecdsa API](https://internetcomputer.org/docs/current/developer-docs/smart-contracts/encryption/signing-messages). -5. Sending the signed transaction to the Ethereum network using - the [`eth_sendRawTransaction`](https://github.com/internet-computer-protocol/evm-rpc-canister/blob/3cce151d4c1338d83e6741afa354ccf11dff41e8/candid/evm_rpc.did#L261) - method in the [EVM-RPC canister](https://github.com/internet-computer-protocol/evm-rpc-canister/tree/main). +```bash +icp canister call backend send_eth '("0xdd2851Cdd40aE6536831558DD46db62fAc7A844d", 1)' +``` -The `send_eth` endpoint returns the hash of the transaction sent to the Ethereum network, which can for example be used -to track the transaction on an Ethereum blockchain explorer. +Returns the transaction hash. Track it on [Sepolia Etherscan](https://sepolia.etherscan.io/). -## Conclusion +> **Note:** Due to the replicated nature of HTTPS outcalls, errors such as "transaction already known" or "nonce too low" may be reported even if the transaction was successfully broadcast. Verify by checking Etherscan or confirming that the transaction count for the address increased. -In this tutorial, you were able to: +## RPC providers and API keys -* Deploy a canister smart contract on the ICP blockchain that can receive and send ETH. -* Acquire cycles to deploy the canister to the ICP mainnet. -* Connect the canister to the Ethereum Sepolia testnet. -* Send the canister some Sepolia ETH. -* Use the canister to send ETH to another Ethereum address. +The example uses [PublicNode](https://ethereum-sepolia-rpc.publicnode.com) by default — a free, no-registration provider that works out of the box locally and on mainnet. This is sufficient for getting started and automated testing. -Additional examples regarding the ICP < > ETH integration can be -found [here](https://internetcomputer.org/docs/current/developer-docs/multi-chain/examples#ethereum--evm-examples). +For production deployments requiring premium providers (Alchemy, Ankr, BlockPi), refer to the [EVM RPC canister documentation](https://github.com/dfinity/evm-rpc-canister) for how to configure API keys. Once configured, change `evm_rpc_services()` in `backend/state.rs` to pass `None` instead of an explicit provider list to use all configured providers for better consensus. ## Security considerations and best practices -If you base your application on this example, we recommend you familiarize yourself with and adhere to -the [security best practices](https://internetcomputer.org/docs/current/references/security/) for developing on the -Internet Computer. This example may not implement all the best practices. - -For example, the following aspects are particularly relevant for this app: +Refer to the [security best practices](https://docs.internetcomputer.org/guides/security/overview) for information on security and best practices for your ICP app. For this example the following aspects are particularly relevant: -* [Certify query responses if they are relevant for security](https://internetcomputer.org/docs/current/references/security/general-security-best-practices#certify-query-responses-if-they-are-relevant-for-security), - since the app offers a method to read balances, for example. -* [Use a decentralized governance system like SNS to make a canister have a decentralized controller](https://internetcomputer.org/docs/current/references/security/rust-canister-development-security-best-practices#use-a-decentralized-governance-system-like-sns-to-make-a-canister-have-a-decentralized-controller), - since decentralized control may be essential for canisters holding ETH on behalf of users. +- [Certify query responses if they are relevant for security](https://docs.internetcomputer.org/guides/security/data-integrity-and-authenticity/#certified-variables): since the app offers a method to read balances. +- [Use a governance framework like SNS to make a canister have a decentralized controller](https://docs.internetcomputer.org/guides/security/canister-control/#use-a-governance-framework-such-as-the-sns-to-control-your-canisters): decentralized control may be essential for canisters holding ETH on behalf of users. diff --git a/rust/basic_ethereum/backend/Cargo.toml b/rust/basic_ethereum/backend/Cargo.toml new file mode 100644 index 0000000000..b120a1a537 --- /dev/null +++ b/rust/basic_ethereum/backend/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "backend" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] +path = "lib.rs" + +[dependencies] +alloy-consensus = "0.1.3" +alloy-eips = "0.1.3" +alloy-primitives = "0.7.6" +candid = "0.10" +evm_rpc_types = "3.1.1" +evm_rpc_client = "0.4.0" +ic-canister-runtime = "0.2" +# transitive dependency: ic-crypto-ecdsa-secp256k1 -> k256 -> ecdsa -> elliptic-curve -> crypto-bigint -> rand_core -> getrandom +# See https://forum.dfinity.org/t/module-imports-function-wbindgen-describe-from-wbindgen-placeholder-that-is-not-exported-by-the-runtime/11545/8 +getrandom = { version = "0.2", default-features = false, features = ["custom"] } +ic-cdk = "0.20" +ic-cdk-management-canister = "0.1.1" +ic-secp256k1 = "0.3.0" +ic-sha3 = "1.0.0" +ic-ethereum-types = "1.0.0" +serde = "1.0" +serde_json = "1.0" +serde_bytes = "0.11.15" +num-traits = "0.2.19" +num = "0.4.3" diff --git a/rust/basic_ethereum/src/ecdsa.rs b/rust/basic_ethereum/backend/ecdsa.rs similarity index 94% rename from rust/basic_ethereum/src/ecdsa.rs rename to rust/basic_ethereum/backend/ecdsa.rs index f6685b2e14..f9e403b4ec 100644 --- a/rust/basic_ethereum/src/ecdsa.rs +++ b/rust/basic_ethereum/backend/ecdsa.rs @@ -1,4 +1,4 @@ -use ic_cdk::api::management_canister::ecdsa::EcdsaPublicKeyResponse; +use ic_cdk_management_canister::EcdsaPublicKeyResult as EcdsaPublicKeyResponse; use ic_secp256k1::{PublicKey, DerivationPath}; use ic_ethereum_types::Address; diff --git a/rust/basic_ethereum/src/ethereum_wallet.rs b/rust/basic_ethereum/backend/ethereum_wallet.rs similarity index 95% rename from rust/basic_ethereum/src/ethereum_wallet.rs rename to rust/basic_ethereum/backend/ethereum_wallet.rs index 6fe940af1b..42c9726a86 100644 --- a/rust/basic_ethereum/src/ethereum_wallet.rs +++ b/rust/basic_ethereum/backend/ethereum_wallet.rs @@ -37,12 +37,12 @@ impl EthereumWallet { } pub async fn sign_with_ecdsa(&self, message_hash: [u8; 32]) -> ([u8; 64], RecoveryId) { - use ic_cdk::api::management_canister::ecdsa::SignWithEcdsaArgument; + use ic_cdk_management_canister::{sign_with_ecdsa, SignWithEcdsaArgs}; let derivation_path = derivation_path(&self.owner); let key_id = read_state(|s| s.ecdsa_key_id()); - let (result,) = - ic_cdk::api::management_canister::ecdsa::sign_with_ecdsa(SignWithEcdsaArgument { + let result = + sign_with_ecdsa(&SignWithEcdsaArgs { message_hash: message_hash.to_vec(), derivation_path, key_id, diff --git a/rust/basic_ethereum/src/lib.rs b/rust/basic_ethereum/backend/lib.rs similarity index 60% rename from rust/basic_ethereum/src/lib.rs rename to rust/basic_ethereum/backend/lib.rs index 82473c33e9..6d8d0fdadb 100644 --- a/rust/basic_ethereum/src/lib.rs +++ b/rust/basic_ethereum/backend/lib.rs @@ -7,19 +7,24 @@ use crate::state::{init_state, read_state}; use alloy_consensus::{SignableTransaction, TxEip1559, TxEnvelope}; use alloy_primitives::{hex, Signature, TxKind, U256}; use candid::{CandidType, Deserialize, Nat, Principal}; -use evm_rpc_canister_types::{ - BlockTag, EthMainnetService, EthSepoliaService, EvmRpcCanister, GetTransactionCountArgs, - GetTransactionCountResult, MultiGetTransactionCountResult, RequestResult, RpcService, +use evm_rpc_types::{ + BlockTag, EthMainnetService, EthSepoliaService, GetTransactionCountArgs, Hex20, + MultiRpcResult, Nat256, RpcService, }; -use ic_cdk::api::management_canister::ecdsa::{EcdsaCurve, EcdsaKeyId}; use ic_cdk::{init, update}; use ic_ethereum_types::Address; use num::{BigUint, Num}; use std::str::FromStr; -pub const EVM_RPC_CANISTER_ID: Principal = - Principal::from_slice(b"\x00\x00\x00\x00\x02\x30\x00\xCC\x01\x01"); // 7hfb6-caaaa-aaaar-qadga-cai -pub const EVM_RPC: EvmRpcCanister = EvmRpcCanister(EVM_RPC_CANISTER_ID); +// The EVM RPC canister ID is injected as PUBLIC_CANISTER_ID:evm_rpc at deploy time: +// local: auto-injected by icp-cli after deploying the pre-built evm_rpc canister +// staging/production: set explicitly in icp.yaml to 7hfb6-caaaa-aaaar-qadga-cai (shared mainnet EVM RPC) +// +// See icp.yaml for the environment configuration. +fn evm_rpc_id() -> Principal { + let id = ic_cdk::api::env_var_value("PUBLIC_CANISTER_ID:evm_rpc"); + Principal::from_text(&id).expect("invalid PUBLIC_CANISTER_ID:evm_rpc") +} #[init] pub fn init(maybe_init: Option) { @@ -55,13 +60,17 @@ pub async fn get_balance(address: Option) -> Nat { EthereumNetwork::Sepolia => RpcService::EthSepolia(EthSepoliaService::PublicNode), }; - let (response,) = EVM_RPC - .request(rpc_service, json, max_response_size_bytes, num_cycles) + use evm_rpc_types::RpcResult; + let (response,): (RpcResult,) = ic_cdk::call::Call::bounded_wait(evm_rpc_id(), "request") + .with_args(&(rpc_service, json, max_response_size_bytes)) + .with_cycles(num_cycles) .await - .expect("RPC call failed"); + .expect("RPC call failed") + .candid_tuple() + .expect("failed to decode response"); let hex_balance = match response { - RequestResult::Ok(balance_result) => { + Ok(balance_result) => { // The response to a successful `eth_getBalance` call has the following format: // { "id": "[ID]", "jsonrpc": "2.0", "result": "[BALANCE IN HEX]" } let response: serde_json::Value = serde_json::from_str(&balance_result).unwrap(); @@ -71,7 +80,7 @@ pub async fn get_balance(address: Option) -> Nat { .unwrap() .to_string() } - RequestResult::Err(e) => panic!("Received an error response: {:?}", e), + Err(e) => panic!("Received an error response: {:?}", e), }; // Remove the "0x" prefix before converting to a decimal number. @@ -84,32 +93,81 @@ pub async fn transaction_count(owner: Option, block: Option let owner = owner.unwrap_or(caller); let wallet = EthereumWallet::new(owner).await; let rpc_services = read_state(|s| s.evm_rpc_services()); + let address: Hex20 = wallet + .ethereum_address() + .to_string() + .parse() + .expect("failed to parse ethereum address"); let args = GetTransactionCountArgs { - address: wallet.ethereum_address().to_string(), + address, block: block.unwrap_or(BlockTag::Finalized), }; - let (result,) = EVM_RPC - .eth_get_transaction_count(rpc_services, None, args.clone(), 2_000_000_000_u128) - .await - .unwrap_or_else(|e| { - panic!( - "failed to get transaction count for {:?}, error: {:?}", - args, e - ) - }); + let (result,): (MultiRpcResult,) = + ic_cdk::call::Call::bounded_wait(evm_rpc_id(), "eth_getTransactionCount") + .with_args(&(rpc_services, Option::::None, args.clone())) + .with_cycles(2_000_000_000_u128) + .await + .unwrap_or_else(|e| { + panic!( + "failed to get transaction count for {:?}, error: {:?}", + args, e + ) + }) + .candid_tuple() + .expect("failed to decode response"); + match result { - MultiGetTransactionCountResult::Consistent(consistent_result) => match consistent_result { - GetTransactionCountResult::Ok(count) => count, - GetTransactionCountResult::Err(error) => { - ic_cdk::trap(&format!("failed to get transaction count for {:?}, error: {:?}",args, error)) + MultiRpcResult::Consistent(consistent_result) => match consistent_result { + Ok(count) => Nat(count.as_ref().0.clone()), + Err(error) => { + ic_cdk::trap(&format!("failed to get transaction count for {:?}, error: {:?}", args, error)) } }, - MultiGetTransactionCountResult::Inconsistent(inconsistent_results) => { + MultiRpcResult::Inconsistent(inconsistent_results) => { ic_cdk::trap(&format!("inconsistent results when retrieving transaction count for {:?}. Received results: {:?}", args, inconsistent_results)) } } } +/// Demonstrates the high-level `EvmRpcClient` pattern: no manual cycle amounts, automatic +/// consensus across providers, and a cleaner API surface compared to the raw inter-canister +/// call used in `transaction_count`. Accepts any Ethereum address directly (like `get_balance`), +/// rather than deriving an address from an IC principal. +#[update] +pub async fn transaction_count_with_client(address: Option, block: Option) -> Nat { + let address = address.unwrap_or(ethereum_address(None).await); + let rpc_services = read_state(|s| s.evm_rpc_services()); + + let address: Hex20 = address.parse().expect("failed to parse ethereum address"); + let block_tag = block.unwrap_or(BlockTag::Finalized); + + let canister_id = evm_rpc_id(); + let client = evm_rpc_client::EvmRpcClient::builder( + ic_canister_runtime::IcRuntime::new(), + canister_id, + ) + .with_rpc_sources(rpc_services) + .build(); + + let result: MultiRpcResult = client + .get_transaction_count((address, block_tag)) + .send() + .await; + + match result { + MultiRpcResult::Consistent(Ok(count)) => Nat(count.as_ref().0.clone()), + MultiRpcResult::Consistent(Err(error)) => { + ic_cdk::trap(&format!("failed to get transaction count, error: {:?}", error)) + } + MultiRpcResult::Inconsistent(inconsistent_results) => { + ic_cdk::trap(&format!( + "inconsistent results when retrieving transaction count. Received results: {:?}", + inconsistent_results + )) + } + } +} + #[update] pub async fn send_eth(to: String, amount: Nat) -> String { use alloy_eips::eip2718::Encodable2718; @@ -154,20 +212,22 @@ pub async fn send_eth(to: String, amount: Nat) -> String { // For demonstration purposes, the canister uses a single provider to send the signed transaction, // but in production multiple providers (e.g., using a round-robin strategy) should be used to avoid a single point of failure. let single_rpc_service = read_state(|s| s.single_evm_rpc_service()); - let (result,) = EVM_RPC - .eth_send_raw_transaction( - single_rpc_service, - None, - raw_transaction_hex.clone(), - 2_000_000_000_u128, - ) - .await - .unwrap_or_else(|e| { - panic!( - "failed to send raw transaction {}, error: {:?}", - raw_transaction_hex, e - ) - }); + + use evm_rpc_types::{MultiRpcResult as SendResult, SendRawTransactionStatus}; + let (result,): (SendResult,) = + ic_cdk::call::Call::bounded_wait(evm_rpc_id(), "eth_sendRawTransaction") + .with_args(&(single_rpc_service, Option::::None, raw_transaction_hex.clone())) + .with_cycles(2_000_000_000_u128) + .await + .unwrap_or_else(|e| { + panic!( + "failed to send raw transaction {}, error: {:?}", + raw_transaction_hex, e + ) + }) + .candid_tuple() + .expect("failed to decode response"); + ic_cdk::println!( "Result of sending raw transaction {}: {:?}. \ Due to the replicated nature of HTTPs outcalls, an error such as transaction already known or nonce too low could be reported, \ @@ -196,7 +256,10 @@ fn estimate_transaction_fees() -> (u128, u128, u128) { #[derive(CandidType, Deserialize, Debug, Default, PartialEq, Eq)] pub struct InitArg { pub ethereum_network: Option, - pub ecdsa_key_name: Option, + /// ECDSA key name as used by the IC management canister: "dfx_test_key" (local dfx), + /// "test_key_1" (ICP mainnet testing), or "key_1" (ICP mainnet production). + /// Defaults to "test_key_1". + pub ecdsa_key_name: Option, } #[derive(CandidType, Deserialize, Debug, Default, PartialEq, Eq, Clone, Copy)] @@ -215,30 +278,8 @@ impl EthereumNetwork { } } -#[derive(CandidType, Deserialize, Debug, Default, PartialEq, Eq, Clone)] -pub enum EcdsaKeyName { - #[default] - TestKeyLocalDevelopment, - TestKey1, - ProductionKey1, -} - -impl From<&EcdsaKeyName> for EcdsaKeyId { - fn from(value: &EcdsaKeyName) -> Self { - EcdsaKeyId { - curve: EcdsaCurve::Secp256k1, - name: match value { - EcdsaKeyName::TestKeyLocalDevelopment => "dfx_test_key", - EcdsaKeyName::TestKey1 => "test_key_1", - EcdsaKeyName::ProductionKey1 => "key_1", - } - .to_string(), - } - } -} - pub fn validate_caller_not_anonymous() -> Principal { - let principal = ic_cdk::caller(); + let principal = ic_cdk::api::msg_caller(); if principal == Principal::anonymous() { panic!("anonymous principal is not allowed"); } @@ -263,3 +304,5 @@ fn nat_to_u256(value: Nat) -> U256 { value_u256[32 - value_bytes.len()..].copy_from_slice(&value_bytes); U256::from_be_bytes(value_u256) } + +ic_cdk::export_candid!(); diff --git a/rust/basic_ethereum/src/state.rs b/rust/basic_ethereum/backend/state.rs similarity index 51% rename from rust/basic_ethereum/src/state.rs rename to rust/basic_ethereum/backend/state.rs index 73efb8e35f..b490da50a0 100644 --- a/rust/basic_ethereum/src/state.rs +++ b/rust/basic_ethereum/backend/state.rs @@ -1,7 +1,7 @@ use crate::ecdsa::EcdsaPublicKey; -use crate::{EcdsaKeyName, EthereumNetwork, InitArg}; -use evm_rpc_canister_types::{EthMainnetService, EthSepoliaService, RpcServices}; -use ic_cdk::api::management_canister::ecdsa::EcdsaKeyId; +use crate::{EthereumNetwork, InitArg}; +use evm_rpc_types::{EthMainnetService, EthSepoliaService, RpcServices}; +use ic_cdk_management_canister::{EcdsaCurve, EcdsaKeyId}; use std::cell::RefCell; use std::ops::{Deref, DerefMut}; @@ -24,26 +24,51 @@ where STATE.with(|s| f(s.borrow_mut().deref_mut())) } -#[derive(Debug, Default, PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct State { ethereum_network: EthereumNetwork, - ecdsa_key_name: EcdsaKeyName, + ecdsa_key_name: String, ecdsa_public_key: Option, } +impl Default for State { + fn default() -> Self { + Self { + ethereum_network: EthereumNetwork::default(), + ecdsa_key_name: "test_key_1".to_string(), + ecdsa_public_key: None, + } + } +} + impl State { pub fn ecdsa_key_id(&self) -> EcdsaKeyId { - EcdsaKeyId::from(&self.ecdsa_key_name) + EcdsaKeyId { + curve: EcdsaCurve::Secp256k1, + name: self.ecdsa_key_name.clone(), + } } pub fn ethereum_network(&self) -> EthereumNetwork { self.ethereum_network } + // Returns the RPC services to use for multi-provider calls. + // Uses PublicNode by default (no API key required) so the example works + // out of the box locally and without credentials. + // + // For production, pass `None` to use all configured providers (including + // API-key-based ones like Alchemy/Ankr), or add multiple providers for + // better consensus. API keys are configured via the EVM RPC canister's + // `authorize` and `updateProvider` endpoints — see README for details. pub fn evm_rpc_services(&self) -> RpcServices { match self.ethereum_network { - EthereumNetwork::Mainnet => RpcServices::EthMainnet(None), - EthereumNetwork::Sepolia => RpcServices::EthSepolia(None), + EthereumNetwork::Mainnet => { + RpcServices::EthMainnet(Some(vec![EthMainnetService::PublicNode])) + } + EthereumNetwork::Sepolia => { + RpcServices::EthSepolia(Some(vec![EthSepoliaService::PublicNode])) + } } } @@ -63,29 +88,30 @@ impl From for State { fn from(init_arg: InitArg) -> Self { State { ethereum_network: init_arg.ethereum_network.unwrap_or_default(), - ecdsa_key_name: init_arg.ecdsa_key_name.unwrap_or_default(), - ..Default::default() + ecdsa_key_name: init_arg.ecdsa_key_name.unwrap_or_else(|| "test_key_1".to_string()), + ecdsa_public_key: None, } } } pub async fn lazy_call_ecdsa_public_key() -> EcdsaPublicKey { - use ic_cdk::api::management_canister::ecdsa::{ecdsa_public_key, EcdsaPublicKeyArgument}; + use ic_cdk_management_canister::{ecdsa_public_key, EcdsaPublicKeyArgs as EcdsaPublicKeyArgument}; if let Some(ecdsa_pk) = read_state(|s| s.ecdsa_public_key.clone()) { return ecdsa_pk; } let key_id = read_state(|s| s.ecdsa_key_id()); - let (response,) = ecdsa_public_key(EcdsaPublicKeyArgument { + let key_name = key_id.name.clone(); + let response = ecdsa_public_key(&EcdsaPublicKeyArgument { canister_id: None, derivation_path: vec![], key_id, }) .await - .unwrap_or_else(|(error_code, message)| { + .unwrap_or_else(|e| { ic_cdk::trap(&format!( - "failed to get canister's public key: {} (error code = {:?})", - message, error_code, + "failed to get ECDSA public key for key '{}': {:?}", + key_name, e, )) }); let pk = EcdsaPublicKey::from(response); diff --git a/rust/basic_ethereum/basic_ethereum.did b/rust/basic_ethereum/basic_ethereum.did deleted file mode 100644 index 36ff95e4e5..0000000000 --- a/rust/basic_ethereum/basic_ethereum.did +++ /dev/null @@ -1,57 +0,0 @@ -type InitArg = record { - // The canister will interact with this Ethereum network. - ethereum_network : opt EthereumNetwork; - - // The name of the ECDSA key to use. - ecdsa_key_name : opt EcdsaKeyName; -}; - -type EthereumNetwork = variant { - // The public Ethereum mainnet. - Mainnet; - // The public Ethereum Sepolia testnet. - Sepolia; -}; - -type EcdsaKeyName = variant { - // For local development with `dfx` - TestKeyLocalDevelopment; - // For testing with the Internet Computer's test key. - TestKey1; - // For running the canister in a production environment using the Internet Computer's production key. - ProductionKey1; -}; - -type BlockTag = variant { - Earliest; - Safe; - Finalized; - Latest; - Number : nat; - Pending; -}; - -// Base unit of ETH, i.e., 1 ETH = 10^18 Wei. -type Wei = nat; - -service : (opt InitArg) -> { - // Returns the Ethereum address to which the owner should send ETH - // before sending the amount to another address via the canister using the [send_eth] - // endpoint. - // - // If the owner is not set, it defaults to the caller's principal. - ethereum_address : (owner: opt principal) -> (text); - - // Returns the balance of the given Ethereum address. - // If no address is provided, the address derived from the caller's principal is used. - get_balance : (address: opt text) -> (Wei); - - // Returns the transaction count for the Ethereum address derived for the given principal. - // - // If the owner is not set, it defaults to the caller's principal. - transaction_count : (owner: opt principal, block_height: opt BlockTag) -> (nat); - - // Sends the given amount of ETH in base unit (Wei) to the given Ethereum address. - // Returns the transaction hash - send_eth : (to: text, amount: Wei) -> (text); -} diff --git a/rust/basic_ethereum/dfx.json b/rust/basic_ethereum/dfx.json deleted file mode 100644 index 75f38573a6..0000000000 --- a/rust/basic_ethereum/dfx.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "canisters": { - "basic_ethereum": { - "candid": "basic_ethereum.did", - "package": "basic_ethereum", - "type": "custom", - "build": [ - "cargo build --no-default-features --target wasm32-unknown-unknown --release -p basic_ethereum" - ], - "wasm": "target/wasm32-unknown-unknown/release/basic_ethereum.wasm", - "metadata": [ - { - "name": "candid:service" - } - ] - }, - "evm_rpc": { - "type": "custom", - "candid": "https://github.com/internet-computer-protocol/evm-rpc-canister/releases/download/release-2024-05-23/evm_rpc.did", - "wasm": "https://github.com/internet-computer-protocol/evm-rpc-canister/releases/download/release-2024-05-23/evm_rpc.wasm.gz", - "remote": { - "id": { - "ic": "7hfb6-caaaa-aaaar-qadga-cai" - } - }, - "specified_id": "7hfb6-caaaa-aaaar-qadga-cai", - "init_arg": "(record { nodesInSubnet = 28 })" - } - }, - "defaults": { - "build": { - "args": "", - "packtool": "" - } - }, - "version": 1 -} diff --git a/rust/basic_ethereum/icp.yaml b/rust/basic_ethereum/icp.yaml new file mode 100644 index 0000000000..231dbd70f0 --- /dev/null +++ b/rust/basic_ethereum/icp.yaml @@ -0,0 +1,42 @@ +canisters: + - name: backend + recipe: + type: "@dfinity/rust@v3.3.0" + + # evm_rpc is only deployed locally. On ICP mainnet the shared EVM RPC canister + # (7hfb6-caaaa-aaaar-qadga-cai) is used instead — the ic environment below + # restricts deployment to [backend] only and injects its principal via env vars. + - name: evm_rpc + build: + steps: + - type: pre-built + url: https://github.com/dfinity/evm-rpc-canister/releases/download/evm_rpc-v2.8.0/evm_rpc.wasm.gz + # nodesInSubnet controls how many cycles the EVM RPC canister charges per request + # (each node in a subnet independently makes the HTTPS outcall, so cost scales with N). + # Using the production value (28) locally validates that the cycle amounts in the + # backend are sufficient for a real subnet, even though PocketIC only runs 1 node. + init_args: "(record { nodesInSubnet = 28 })" + +environments: + # Local: deploys both backend and evm_rpc (pre-built). + # icp-cli auto-injects PUBLIC_CANISTER_ID:evm_rpc into the backend after deploying evm_rpc. + - name: local + network: local + + # IC mainnet: deploys only the backend; the shared EVM RPC canister is already running + # on ICP mainnet at 7hfb6-caaaa-aaaar-qadga-cai. + # + # Default configuration uses Sepolia testnet with test_key_1, suitable for development + # and testing on ICP mainnet with free Sepolia ETH from a faucet. + # + # For a production deployment on Ethereum mainnet, change init_args to: + # "(opt record {ethereum_network = opt variant {Mainnet}; ecdsa_key_name = opt \"key_1\"})" + - name: ic + network: ic + canisters: [backend] + init_args: + backend: "(opt record {ethereum_network = opt variant {Sepolia}; ecdsa_key_name = opt \"test_key_1\"})" + settings: + backend: + environment_variables: + "PUBLIC_CANISTER_ID:evm_rpc": "7hfb6-caaaa-aaaar-qadga-cai" diff --git a/rust/basic_ethereum/rust-toolchain.toml b/rust/basic_ethereum/rust-toolchain.toml index d4f7c253a4..990104f055 100644 --- a/rust/basic_ethereum/rust-toolchain.toml +++ b/rust/basic_ethereum/rust-toolchain.toml @@ -1,4 +1,2 @@ [toolchain] -channel = "1.85" targets = ["wasm32-unknown-unknown"] -components = ["rustfmt", "clippy"] diff --git a/rust/basic_ethereum/test.sh b/rust/basic_ethereum/test.sh new file mode 100755 index 0000000000..df0849ca68 --- /dev/null +++ b/rust/basic_ethereum/test.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +set -e + +# The local icp-cli network supports real HTTPS outcalls, so all read operations +# (get_balance, transaction_count) can be tested locally against Ethereum Sepolia. +# send_eth requires a funded canister wallet and is not covered here — see README. + +# Create a non-anonymous identity for canister calls that reject the anonymous principal. +# --storage plaintext is required in CI environments without a keyring daemon. +icp identity new test --storage plaintext 2>/dev/null || true +icp identity default test + +echo "=== Test 1: ethereum_address returns a valid 0x-prefixed Ethereum address ===" +result=$(icp canister call backend ethereum_address '(null)') +echo "$result" +echo "$result" | grep -qE '"0x[0-9a-fA-F]{40}"' && echo "PASS" || (echo "FAIL" && exit 1) +my_address=$(echo "$result" | grep -oE '0x[0-9a-fA-F]{40}') + +echo "=== Test 2: ethereum_address for a specific principal returns a valid address ===" +result=$(icp canister call backend ethereum_address '(opt principal "hkroy-sm7vs-yyjs7-ekppe-qqnwx-hm4zf-n7ybs-titsi-k6e3k-ucuiu-uqe")') +echo "$result" +echo "$result" | grep -qE '"0x[0-9a-fA-F]{40}"' && echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 3: different principals derive different Ethereum addresses ===" +addr2=$(icp canister call backend ethereum_address '(opt principal "hkroy-sm7vs-yyjs7-ekppe-qqnwx-hm4zf-n7ybs-titsi-k6e3k-ucuiu-uqe")' | grep -oE '0x[0-9a-fA-F]{40}') +echo " my address: $my_address" +echo " principal address: $addr2" +[ "$my_address" != "$addr2" ] && echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 4: get_balance returns non-zero balance for a known funded Sepolia address ===" +# 0x378a452B20d1f06008C06c581b1656BdC5313c0C is an address with known Sepolia ETH. +# Asserting > 0 proves the HTTPS outcall to the Ethereum RPC provider works and +# returns real on-chain data. +KNOWN_ADDRESS="0x378a452B20d1f06008C06c581b1656BdC5313c0C" +result=$(icp canister call backend get_balance "(opt \"$KNOWN_ADDRESS\")") +echo "$result" +balance=$(echo "$result" | grep -oE '[0-9][0-9_]*' | head -1 | tr -d '_') +[ "$balance" -gt 0 ] && echo "PASS" || (echo "FAIL: expected non-zero Sepolia ETH balance for $KNOWN_ADDRESS" && exit 1) + +echo "=== Test 5: transaction_count_with_client returns the nonce (outgoing tx count) via EvmRpcClient ===" +# Demonstrates the high-level evm_rpc_client API — same Sepolia HTTPS outcall as Test 4 +# but with automatic cycle management and accepting an Ethereum address directly. +# eth_getTransactionCount returns the nonce: only outgoing transactions are counted. +# The known address has 2 outgoing transactions on Sepolia (nonce = 2). +result=$(icp canister call backend transaction_count_with_client "(opt \"$KNOWN_ADDRESS\", null)") +echo "$result" +count=$(echo "$result" | grep -oE '[0-9][0-9_]*' | head -1 | tr -d '_') +[ "$count" -ge 2 ] && echo "PASS" || (echo "FAIL: expected nonce >= 2 for $KNOWN_ADDRESS, got $count" && exit 1)