chore: migrate rust/basic_ethereum to icp-cli#1395
Conversation
Replaces dfx.json with icp.yaml using @dfinity/rust@v3.3.0 recipe. Moves Rust source from src/ into backend/, adds workspace Cargo.toml, Makefile with local-testable ethereum_address tests, updated README with icp-cli deploy instructions preserving Ethereum integration details, and CI workflow with icp-dev-env-rust:1.0.0. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
….0.1 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2d51380 to
4a9e7a5
Compare
…image 1.0.1
- Cargo.toml: add path = "lib.rs" (files are at backend/*.rs not src/)
- lib.rs: replace hardcoded mainnet EVM RPC principal with
ic_cdk::api::env_var_value("PUBLIC_CANISTER_ID:evm_rpc") — read at
runtime as a canister environment variable
- icp.yaml: add environments block; local uses auto-injected
PUBLIC_CANISTER_ID:evm_rpc, production sets EVM_RPC_CANISTER_ID to
the mainnet canister (7hfb6-caaaa-aaaar-qadga-cai)
- CI: bump image to icp-dev-env-rust:1.0.1
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace evm-rpc-canister-types (ic-cdk 0.14 conflict) with: - evm_rpc_types 3.1.1: Candid types for EVM RPC canister - evm_rpc_client 0.4.0: high-level client with automatic cycle management transaction_count: raw inter-canister call using evm_rpc_types + ic_cdk transaction_count_with_client: uses EvmRpcClient for automatic cycle management, consensus across providers, and cleaner API Also update rust-toolchain.toml to 1.88 (required by ic-cdk 0.20) and fix ic_cdk API changes: caller() -> msg_caller(), tuple error unwrapping -> single error, EcdsaPublicKeyResponse -> EcdsaPublicKeyResult. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ain.toml The dev-env image already pins the toolchain; a per-example pin is redundant and risks drifting out of sync. Matches the pattern used in all other migrated Rust examples. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ic_cdk::export_candid!() was missing, causing candid-extractor to fail with "get_candid_pointer not found" - Bump pre-built EVM RPC canister from v2.2.0 to v2.8.0 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The local icp-cli network supports real HTTPS outcalls, so get_balance and transaction_count work against live Ethereum Sepolia data locally. test.sh: - Test 4: get_balance with canister's own Sepolia address — proves the EVM RPC canister's HTTPS outcall to PublicNode/Ankr works - Test 5: transaction_count_with_client — demonstrates EvmRpcClient high-level API vs raw inter-canister call in Test 4 README: - Remove "mainnet only" notes for get_balance and transaction_count - Explain local HTTPS outcall support and what test.sh covers - Document send_eth flow with Alchemy Sepolia faucet - Fix security links to specific anchors Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… setup evm_rpc_services() defaulted to None (all providers) which includes API-key-required providers like Alchemy (provider 6), breaking local tests. Switch to explicit PublicNode (free, no API key) so the example works out of the box. Add README section explaining how to configure API keys locally and switch to multi-provider mode for production. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ia address Test 4 now uses 0x378a452B20d1f06008C06c581b1656BdC5313c0C (from the original README) which has known Sepolia ETH, and asserts balance > 0. This is a stronger check proving real on-chain data is returned, not just that the call succeeds with 0. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…thereum address directly Change the signature from Option<Principal> to Option<String> to mirror get_balance — any Ethereum address can be queried, not just ones derived from IC principals. Passing null still falls back to the canister's own derived address. This creates a clear educational contrast: - transaction_count: raw inter-canister call, derives address from principal - transaction_count_with_client: EvmRpcClient, accepts any ETH address Test 5 now uses the known funded Sepolia address and asserts count >= 3. README updated to show both use cases. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ging/production) - local: deploys backend + evm_rpc pre-built locally; icp-cli auto-injects PUBLIC_CANISTER_ID:evm_rpc - staging: backend only on ICP mainnet, Sepolia + TestKey1, points to shared EVM RPC canister (7hfb6-caaaa-aaaar-qadga-cai) - production: backend only on ICP mainnet, Mainnet + ProductionKey1, same shared EVM RPC canister Also fixes env var name mismatch: production env was setting EVM_RPC_CANISTER_ID but lib.rs reads PUBLIC_CANISTER_ID:evm_rpc (auto-injected by icp-cli pattern). README updated to show icp deploy -e staging / -e production instead of manual --argument flags. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…he canister's The ethereum_address(null), get_balance(null), and transaction_count_with_client(null, ...) functions all derive the address from the *caller's* IC principal, not the canister itself. The canister manages one Ethereum address per user. Updated README and test.sh labels accordingly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… default test_key_1 works in icp-cli's PocketIC environment; dfx_test_key was a dfx-specific artifact that is no longer needed. TestKey1 is now the default EcdsaKeyName, used for both local and staging. This lets staging drop its init_args entirely — local and staging share identical defaults (Sepolia + test_key_1). Only production needs init_args. icp.yaml is now visibly simpler: two environment blocks with no init_args, one with. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…onCount is outgoing-only eth_getTransactionCount returns the nonce — only outgoing transactions increment it. The known Sepolia address has 2 outgoing txs (nonce = 2), not 3 total (1 incoming + 2 outgoing). Updated test assertion and comments accordingly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…alls in CI icp canister call uses the anonymous principal when no identity exists, causing ethereum_address to trap. Create a named plaintext identity at test start — --storage-mode plaintext is required in CI containers where no keyring daemon is running. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…r icp identity new Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 'queries the canister's Sepolia balance' -> 'queries a known funded Sepolia address's balance' (test uses an external address, not any canister's balance) - 'funded canister wallet' -> 'funded Ethereum address' (consistent with the rest of the README which uses caller-centric language) - 'Both environments' -> 'Both mainnet environments' (local also deploys the evm_rpc canister, so this was ambiguous) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Migrates the rust/basic_ethereum example from the legacy dfx layout/tooling to icp-cli, updating project structure, build configuration, CI, and Rust canister code to use the current EVM RPC types/client patterns.
Changes:
- Replaced
dfx.json/ICP Ninja artifacts withicp.yaml, a Rust workspace layout (backend/), and anicp-cli-driven CI workflow. - Updated Rust canister code to use
evm_rpc_types/evm_rpc_client,ic-cdk = 0.20,ic-cdk-management-canister, and runtime env var lookup for the EVM RPC canister ID. - Added a
test.shscript that exercises address derivation and live Sepolia reads (balance + nonce) via HTTPS outcalls.
Reviewed changes
Copilot reviewed 15 out of 16 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| rust/basic_ethereum/test.sh | Adds an icp-cli test script covering address derivation and live Sepolia RPC reads. |
| rust/basic_ethereum/rust-toolchain.toml | Simplifies toolchain config to just the wasm target. |
| rust/basic_ethereum/README.md | Updates documentation from dfx/ICP Ninja to icp-cli deploy/test flows and new RPC client usage. |
| rust/basic_ethereum/icp.yaml | Defines icp-cli canisters/environments, including pre-built evm_rpc locally and mainnet env var wiring. |
| rust/basic_ethereum/dfx.json | Removed (dfx migration). |
| rust/basic_ethereum/Cargo.toml | Converts to a workspace root referencing backend/. |
| rust/basic_ethereum/Cargo.lock | Updates lockfile for the new crate split and dependency set. |
| rust/basic_ethereum/BUILD.md | Removed (ICP Ninja artifact). |
| rust/basic_ethereum/basic_ethereum.did | Removed (backend-only; interface now exported from Rust). |
| rust/basic_ethereum/backend/Cargo.toml | New backend crate manifest with updated dependencies (ic-cdk 0.20, evm_rpc_* crates). |
| rust/basic_ethereum/backend/lib.rs | Updates EVM RPC integration + adds transaction_count_with_client + exports Candid. |
| rust/basic_ethereum/backend/state.rs | Updates RPC service selection + switches to ic-cdk-management-canister API. |
| rust/basic_ethereum/backend/ethereum_wallet.rs | Switches ECDSA signing calls to ic-cdk-management-canister. |
| rust/basic_ethereum/backend/ecdsa.rs | Updates ECDSA public key response type import. |
| rust/basic_ethereum/.devcontainer/devcontainer.json | Removed (repo uses root devcontainer). |
| .github/workflows/basic_ethereum.yml | Adds CI job to deploy/test with icp-cli in the Rust dev env container. |
Comments suppressed due to low confidence (2)
rust/basic_ethereum/backend/lib.rs:23
- The comment describes
EVM_RPC_CANISTER_ID, but the code actually readsPUBLIC_CANISTER_ID:evm_rpc. Keeping these aligned avoids confusion when configuring environments viaicp.yaml.
rust/basic_ethereum/backend/lib.rs:28 - The
expectmessage referencesEVM_RPC_CANISTER_ID, but the actual env var being parsed isPUBLIC_CANISTER_ID:evm_rpc. This makes failures harder to diagnose.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…ctual --storage flag Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…l env var name Both referenced EVM_RPC_CANISTER_ID (old name) instead of the actual env var PUBLIC_CANISTER_ID:evm_rpc read by the code. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tring, rename staging to ic
EcdsaKeyName enum added unnecessary indirection — callers now pass the
key name directly ("test_key_1", "key_1") matching what the IC
management canister expects, same pattern as other examples.
icp.yaml:
- Remove production environment (not needed for an example)
- Rename staging -> ic (standard icp-cli environment name)
- Explicit init_args on ic environment with string key format
- Comment showing how to adapt init_args for production (Mainnet + key_1)
README: simplified deploy section, removed environment table.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Switch ic-secp256k1, ic-sha3, ic-ethereum-types from IC git repo to crates.io (0.3.0, 1.0.0, 1.0.0) — no need to pull the full IC repo - Pin getrandom from wildcard '*' to '0.2' - Fix grep pattern for Candid nat values: '[0-9][0-9_]*' + tr -d '_' to handle underscore digit separators (e.g. 1_000_000) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 16 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
rust/basic_ethereum/backend/state.rs:114
- This trap message drops the structured context (rejection code / message) and the key name involved, making ECDSA misconfiguration failures harder to diagnose. Including at least the key name in the message would make debugging deployments significantly easier.
…comment Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Makes misconfiguration failures diagnosable — e.g. a typo in the ecdsa_key_name init arg now shows which key name was attempted. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…testing Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 16 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
rust/basic_ethereum/backend/lib.rs:21
- This comment mentions “staging/production”, but
icp.yamlonly defineslocalandicenvironments. Keeping this aligned with the actual environment names avoids confusion about where thePUBLIC_CANISTER_ID:evm_rpcvalue comes from.
…with doc link authorize/updateProvider no longer exist in evm_rpc-v2.8.0. Rather than maintaining version-specific admin CLI commands in this README, point to the EVM RPC canister documentation instead. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Summary
Migrates
rust/basic_ethereumfrom dfx to icp-cli.Removed:
dfx.json,BUILD.md,basic_ethereum.did,.devcontainer/Changed:
src/tobackend/flat layoutEcdsaKeyNameenum removed — ECDSA key name is now passed as a plain string ("test_key_1","key_1") matching what the IC management canister expects, consistent with other examplesicp.yamlwith two environments:local(backend + pre-built EVM RPC canister) andic(backend only on ICP mainnet, defaults to Sepolia +test_key_1, with a comment showing how to adapt for production Mainnet +key_1)ic-secp256k1,ic-sha3,ic-ethereum-types) switched from IC git repo to crates.ioAdded:
transaction_count_with_clientfunction demonstrating the high-levelEvmRpcClientpattern (accepts an Ethereum address directly, likeget_balance)test.shwith 5 tests: address derivation (threshold ECDSA) +get_balanceandtransaction_count_with_clientagainst a known funded Sepolia address using real HTTPS outcalls.github/workflows/basic_ethereum.ymlTest plan
icp network start -d && icp deploy && bash test.shpasses locally🤖 Generated with Claude Code