Skip to content

chore: migrate rust/icp_transfer to icp-cli - #1412

Merged
marc0olo merged 12 commits into
masterfrom
chore/migrate-rust-icp-transfer-to-icp-cli
Jun 17, 2026
Merged

marc0olo merged 12 commits into
masterfrom
chore/migrate-rust-icp-transfer-to-icp-cli

Conversation

@marc0olo

@marc0olo marc0olo commented Jun 16, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Migrates rust/icp_transfer to icp-cli, aligned with the already-merged motoko/icp_transfer (#1389). Also patches motoko/icp_transfer (security doc links, hex string API for transferToAccountId).

rust/icp_transfer

  • icp.yaml: replaces dfx.json; uses @dfinity/rust@v3.3.0
  • backend/src/lib.rs: three public functions matching the Motoko example:
    • to_account_id_hex(principal, subaccount) — query returning the AccountIdentifier as a 64-char hex string (block explorer / CEX deposit format)
    • transfer_to_principal(amount, principal, subaccount) — calls AccountIdentifier::new internally
    • transfer_to_account_id(amount, account_id_hex) — accepts a 64-char hex string; uses AccountIdentifier::from_hex which validates the CRC32 checksum
  • Cargo.toml: ic-cdk 0.20, ic-ledger-types 0.16 (0.15 + ic-cdk 0.18 had an ic-cdk-executor links conflict; 0.16 requires ^0.19 so both use executor v2)
  • Makefile: 3 tests aligned with the Motoko example — no manual ledger deployment (icp-cli pre-deploys it), no python3:
    • Test 1: icp identity account-id --format ledger matches to_account_id_hex
    • Test 2: transfer_to_principal — asserts exact 1 ICP deduction (99_990_000 amount + 10_000 fee)
    • Test 3: transfer_to_account_id via hex string — same deduction, backend drains to zero
  • CI: icp-dev-env-rust:1.0.1 (1.0.0 bundled candid-extractor 0.1.4 which fails on ic-cdk ≥ 0.19 due to ic0::cost_call; fixed in 0.1.6)
  • Deleted: dfx.json, demo.sh, src/, old workflow

motoko/icp_transfer (follow-up patch to #1389)

  • transferToAccountId now accepts a 64-char hex string instead of a raw blob — consistent with Rust, ergonomic for CEX integrations, uses mo:hex for decoding; note on CRC32 library gap added
  • Security doc links updated to specific anchors (inter-canister-calls/#securely-handle-traps-in-callbacks, data-integrity-and-authenticity/#certified-variables)

Test plan

  • icp network start -d && icp deploy && make test passes locally (rust)
  • icp network start -d && icp deploy && make test passes locally (motoko)
  • Verified locally with icp-dev-env-rust:1.0.1 Docker image
  • CI workflow passes (rust-icp_transfer and motoko-icp_transfer jobs)

🤖 Generated with Claude Code

marc0olo and others added 5 commits June 17, 2026 15:05
Replaces dfx.json with icp.yaml (@dfinity/rust@v3.3.0), moves the
canister source from src/icp_transfer_backend/ to backend/, renames the
Cargo package to `backend`, adds a Makefile that deploys the ICP ledger
locally at ryjl3-tyaaa-aaaaa-aaaba-cai and runs end-to-end transfer
tests, and adds a CI workflow using icp-dev-env-rust:1.0.0.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…st structure

Backend:
- Replace single transfer() with to_account_id_hex, transfer_to_principal,
  transfer_to_account_id (mirrors motoko example)
- AccountIdentifier::new for principal path; raw 32-byte blob for account ID path
- Bump ic-cdk 0.18 → 0.20; remove unused serde dependency

Makefile:
- Drop make deploy-ledger (icp network start -d pre-deploys the ledger)
- Drop python3 dependency
- Same 3-test structure as motoko: CLI hex vs backend hex, transferToPrincipal
  balance check, transferToAccountId via vec nat8
- Fund 2 ICP, drain to zero (99_990_000 e8s + 10_000 fee = exactly 1 ICP/test)

README:
- Aligned with motoko README; remove stale token_transfer references

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace manual byte-stripping with from_hex(), which validates the 4-byte
CRC32 prefix before constructing the AccountIdentifier. Fails fast in the
canister with a readable error instead of propagating invalid bytes to the
ICP ledger.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Passing a 64-char hex string (the format CEXs and block explorers provide)
is cleaner than a raw blob: AccountIdentifier::from_hex validates the CRC32
in one call with no byte-manipulation, the Makefile test passes the hex
string directly, and the Candid type text avoids vec nat8 complexity.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@marc0olo
marc0olo force-pushed the chore/migrate-rust-icp-transfer-to-icp-cli branch from d85357c to 1382f67 Compare June 17, 2026 13:05
marc0olo and others added 6 commits June 17, 2026 15:15
… Rust

Replace generic /guides/security/overview with:
- /inter-canister-calls/#securely-handle-traps-in-callbacks
- /data-integrity-and-authenticity/#certified-variables

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…flict

ic-ledger-types 0.15 pins ic-cdk = "^0.18". Upgrading our backend to 0.20
pulls in ic-cdk-executor v2 alongside ic-cdk-executor v1 (from
ic-ledger-types), which hits Cargo's `links` uniqueness constraint and
fails the build.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ic-ledger-types 0.16 requires ic-cdk ^0.19, so both 0.19 and 0.20 use
ic-cdk-executor v2 — no more `links` uniqueness conflict that occurred
when mixing ic-ledger-types 0.15 (ic-cdk-executor v1) with ic-cdk 0.20
(ic-cdk-executor v2).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mirrors the Rust example: transferToAccountId now takes a 64-char hex
string instead of a raw blob. Uses mo:hex for decoding; length is checked
(must be 32 bytes / 64 hex chars). CRC32 validation is delegated to the
ICP ledger — a fromHex helper with CRC32 validation would be a valuable
addition to a future Motoko ICP library.

Makefile Test 3 simplifies: pass "$cli_hex" directly instead of the
vec nat8 construction workaround.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ndid-extractor

ic-cdk 0.20 uses ic0::cost_call (new IC system API) which candid-extractor
in icp-dev-env-rust:1.0.0 does not recognise, causing the Candid extraction
step to fail. ic-cdk 0.19 avoids this import while still satisfying
ic-ledger-types 0.16's ^0.19.0 requirement and sharing ic-cdk-executor v2.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
candid-extractor 0.1.6 (shipped in icp-dev-env-rust:1.0.1) supports
ic0::cost_call, unblocking ic-cdk 0.20 in CI.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@marc0olo
marc0olo marked this pull request as ready for review June 17, 2026 13:59
@marc0olo
marc0olo requested review from a team as code owners June 17, 2026 13:59

@mbjorkqvist mbjorkqvist left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @marc0olo, just a couple of nits!

Comment thread rust/icp_transfer/Makefile Outdated
Comment thread rust/icp_transfer/icp.yaml Outdated
- Makefile: fix stale 'blob' in PASS message — function now accepts hex
- icp.yaml: drop redundant networks block (managed is the default,
  matches motoko/icp_transfer which omits it on master)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@marc0olo
marc0olo merged commit 5736146 into master Jun 17, 2026
7 checks passed
@marc0olo
marc0olo deleted the chore/migrate-rust-icp-transfer-to-icp-cli branch June 17, 2026 14:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants