chore: migrate motoko/icrc2-swap to icp-cli#1386
Merged
Merged
Conversation
Replace dfx.json with icp.yaml, migrate Motoko sources from src/swap/ to backend/, add icp-dev-env-motoko:0.3.2 CI workflow, update mops.toml to moc 1.9.0 / core 2.5.0 with --default-persistent-actors. Remove JS/Jest test suite, old deploy.sh, and prettier config; add Makefile with deploy and test targets that handle the multi-step deployment (token_a, token_b ICRC-1 ledger canisters via pre-built WASM, then backend swap canister with dynamic init args containing the token canister IDs). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… README 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>
Deploy: - --argument → --args (correct icp-cli flag) - icp canister id → icp canister status X -i Tests: - Replace single-user contrived test with real two-user scenario: Alice deposits token_a, Bob deposits token_b, they swap 1:1, each withdraws the other's token - Use --identity test-alice/test-bob for two distinct callers README: - Credit original author 0xAegir (AegirFinance) - Remove "DeFi is experimental" disclaimer - Fix security link: old URL → docs.internetcomputer.org/guides/security/inter-canister-calls - Note that make deploy must be used instead of icp deploy - Explain what make test actually tests Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…quired Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…init args - Change from actor class Swap(init_args) to plain actor Swap - Token principals read from PUBLIC_CANISTER_ID:token_a / token_b via Runtime.envVar<system>() — injected automatically by icp-cli during deploy - Remove --args from make deploy backend step; no init args needed - Backend deploys last so icp-cli has both token IDs to inject - Makefile deploy and test use correct icp-cli flags (--args, status -i) - M0155 (Nat subtraction may trap) intentionally left as a warning — subtraction is guarded by explicit balance check but Motoko's type checker lacks path-sensitive refinement Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Create icrc2-alice and icrc2-bob identities in make deploy (idempotent) - token_a initial_balances → icrc2-alice; token_b → icrc2-bob - No funding/minting step needed in make test — identities start with tokens - Tests use --identity icrc2-alice/icrc2-bob for realistic two-user flow - README updated to explain the named identities and env var discovery Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
$(eval ALICE := $(shell ...)) in Make recipe bodies expands before any recipe commands run — so icp identity principal ran before icp identity new. Fix: use a single shell block with set -e so identity creation and principal lookup happen in the correct order within one shell process. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
.gitignore: remove stale token_a.args/token_b.args/backend.args entries from the old dfx arg-file approach Makefile: - Tests 5/6 use single shell block to capture balance delta (before/after) making them idempotent across multiple make test runs - Fee arithmetic comments added to approve/withdraw steps README: - Lead with the two key safety patterns (debit-before-transfer, atomic swap) which are the core educational content — previously buried in code comments - Add ic-mops to prerequisites - Explain ICRC.mo inline type definitions - Add fee handling section explaining the approve/withdraw arithmetic - Clarify make deploy vs icp deploy and why - Tighten known limitations section 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>
…ejection From canister-security skill review: Pitfall #11 (callback trap after state mutation): - withdraw: balance is debited before await icrc1_transfer - if the token ledger TRAPS (not just returns an error), the callback never ran and the refund in the #Err branch is skipped - Fix: wrap await icrc1_transfer in try/catch; on trap, refund and return #CallFailed with the error message - Add #CallFailed error variant to WithdrawError Pitfall #2 (anonymous principal): - withdraw uses msg.caller as balance key but never rejected anonymous - Fix: trap on anonymous caller at entry README known limitations updated to accurately describe: - the async edge case for trusted-only token canisters (not "deadlock") - the deposit ambiguous-outcome scenario Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tor escalation Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
swap() now returns InsufficientBalance if either user has no deposit — previously it silently succeeded moving zero tokens. Add Test 2 (before any deposits) to verify InsufficientBalance fires, making the guard visible in the test output. 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>
The default --storage keyring requires a system keyring unavailable in CI containers. --storage plaintext stores the key as a plain PEM file, which works in both CI and local dev. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
lwshang
approved these changes
Jun 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Migrates
motoko/icrc2-swapfrom dfx to icp-cli.Code:
backend/app.mo: converted fromactor class Swap(init_args)to plainactor Swap; token principals read fromPUBLIC_CANISTER_ID:token_a/PUBLIC_CANISTER_ID:token_bviaRuntime.envVar<system>— icp-cli injects them during deploy; no init args neededwithdraw: addedtry/catcharoundicrc1_transfer— if the token ledger traps, the balance is refunded and#CallFailedreturned; previously the balance was permanently debitedwithdraw: reject anonymous principal (usesmsg.callerfor balance lookup)swap: check both users have non-zero balances before swapping; returns#InsufficientBalanceinstead of silently moving zero tokensICRC.mo: inline ICRC-1/2 type definitions kept for educational visibilityDeploy (
make deploy):icrc2-alice/icrc2-bobidentities with--storage plaintext(compatible with CI containers that have no system keyring)token_apre-funded foricrc2-alice,token_bpre-funded foricrc2-bobbackendwith--mode reinstall -y(works on fresh and existing deployments)--argsneeded for backend — it discovers token principals via env varsTests (
make test, 7 tests, idempotent):InsufficientBalanceREADME:
#CallFailedguidance: retry; if persistent, contact token ledger operatorTest plan
mops checkpassesmotoko-icrc2-swapjob passes all 7 tests