feat(token): add token crate with generic CIP-56 operations - #27
feat(token): add token crate with generic CIP-56 operations#27hubagaspar91 wants to merge 25 commits into
Conversation
Add a new token crate seeded with an unmodified copy of cbtc-lib's CIP-56 modules so the genericization diff stays reviewable in the follow-up commits. mint_redeem is excluded as cbtc-specific; the Holding struct consolidate.rs needs is lifted from its models into holding.rs. Filtering still hardcodes cbtc at this point. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019K2Sr8YQFWVULxp3kTG8V8
Replace the hardcoded cbtc ACS filters with checks against an InstrumentId supplied by the caller, threaded through the param structs that fetch holdings or pending transfers. The instrument id is matched case-insensitively and the admin party exactly: the admin is always known to callers (it is a registry-API input, not something queried from it), and without it holdings of a same-ticker token from another admin would be selected as inputs and fail at expectedAdmin. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019K2Sr8YQFWVULxp3kTG8V8
Reword doc comments and examples for any token; examples switch to the token crate name and neutral placeholder ids. The two no_run examples become ignore: they never compiled in cbtc-lib either (nonexistent withdraw module, top-level await), matching the ignore fences the other examples already use. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019K2Sr8YQFWVULxp3kTG8V8
Live integration tests read INSTRUMENT_ID and DECENTRALIZED_PARTY_ID from the environment instead of hardcoding CBTC devnet values, in line with the .env convention the other crates' live tests use. Pure unit-test fixtures keep their original literals to keep the diff against cbtc-lib minimal. The DAR-scanning test gets vendored token-standard and utility DARs as its fixture directory. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019K2Sr8YQFWVULxp3kTG8V8
Thin convenience client bound to one token, party, and participant. It caches the Keycloak credentials (auto-refreshing the access token via transfer::TokenState) and the instrument config, and forwards to the free functions in the operation modules. Purely additive. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019K2Sr8YQFWVULxp3kTG8V8
TokenClient::send takes an optional chrono::Duration for the offer's execute-before window. The one-week default stays when the caller passes None. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019K2Sr8YQFWVULxp3kTG8V8
Records the approved design: two test suites, the env-driven IntegrationTestState fixture, the three client-level flows, and the accepted assumptions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P2oS4Ke7N1pBVgjqdCeEzv
The 17 env-driven tests fail in a plain checkout, which hides real regressions. Marking them ignored makes 'cargo test --workspace' a pure unit suite that always runs green. Each test still runs when named explicitly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P2oS4Ke7N1pBVgjqdCeEzv
Adds three env-driven flows against devnet: offer/accept round trip, cancel and reject, and distribute with cleanup. Tests tag transfers with a per-run uuid reference, so ACS checks only see their own contracts and a successful run restores both wallet balances. The tests are ignored and name-prefixed, which splits the workspace into two suites: 'cargo test --workspace' for units, and 'cargo test --workspace -- --ignored --test-threads=1 integration_' for live tests. A static lock also serializes the tests themselves, so they never mutate the shared wallets concurrently. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P2oS4Ke7N1pBVgjqdCeEzv
…ith shared utilities
The consolidate, split and credential live tests used their own env var names and raw module calls. The consolidate and split flows now run through TokenClient in client.rs, next to the other client-level integration tests, with balance and UTXO assertions. The credential tests stay in credentials.rs, because TokenClient has no credential methods, but they now use IntegrationTestState and SERIAL_LOCK. Party 1 is the acting party everywhere. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q3gjQvX6nBshnhoa2RSg25
…clarity and environment variable handling
…improved environment variable handling
…clarity and environment variable handling
…roved clarity and environment variable handling
…en mining rounds with improved clarity and environment variable handling
…gration test documentation
…ts for improved token operations
…nce and cancellation
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
There was a problem hiding this comment.
Pull request overview
This PR introduces a new token crate to the workspace that provides reusable, instrument-agnostic CIP-56 token operations and a convenience TokenClient, and it standardizes how live integration tests are organized and configured across the workspace.
Changes:
- Added the new
crates/tokencrate with CIP-56 operation modules (transfer, accept/reject/cancel, split/consolidate, distribute/batch, allocation, credentials, dar_check) plus aTokenClientwrapper. - Consolidated live integration test conventions (naming,
#[ignore], shared env var scheme,.envloading) acrossledger,registry, andwallet. - Updated workspace dependencies and developer documentation/examples to support the new crate and test workflow.
Reviewed changes
Copilot reviewed 37 out of 58 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| README.md | Documents unit vs live integration test workflows and required env vars. |
| crates/wallet/src/mining_rounds.rs | Renames live test module, marks test ignored, switches to standardized env vars and .env loading. |
| crates/wallet/src/amulet_rules.rs | Same integration test standardization for wallet rules query. |
| crates/token/src/utils.rs | Adds helpers for amount extraction and fetching incoming/outgoing transfer offers; includes typed response fixtures for parser unit tests. |
| crates/token/src/transfer.rs | Implements transfer submission plus sequential chained transfers and response parsing; includes token refresh state and parser tests. |
| crates/token/src/test_utils.rs | Adds shared integration test setup/state and helper functions for token crate live tests. |
| crates/token/src/split.rs | Implements split (merge-split self-transfer) and response parsing plus parser unit tests. |
| crates/token/src/reject.rs | Adds receiver-side rejection operation with direct registry reject choice-context fetch. |
| crates/token/src/lib.rs | Exposes token crate modules and re-exports TokenClient types. |
| crates/token/src/holding.rs | Adds a typed Holding parser and lock-check helper for holding contracts. |
| crates/token/src/event_helpers.rs | Centralizes event variant matching for generated Ledger API event types. |
| crates/token/src/distribute.rs | Implements multi-recipient distribution via sequential chained transfers with optional callbacks and reference IDs. |
| crates/token/src/dar_check.rs | Adds DAR scanning/version selection and participant package presence checks (plus unit tests). |
| crates/token/src/credentials.rs | Adds credential/offer listing and acceptance helpers, plus live integration tests and parser tests. |
| crates/token/src/consolidate.rs | Adds UTXO consolidation/check-and-consolidate operations with parser tests. |
| crates/token/src/client.rs | Implements TokenClient wrapper that refreshes auth between calls and forwards to operation modules; includes live integration tests. |
| crates/token/src/cancel_offers.rs | Adds withdraw/cancel operations including batched and “withdraw all” flows. |
| crates/token/src/batch.rs | Adds CSV-driven batch distribution plus a live integration test. |
| crates/token/src/allocation.rs | Adds CIP-56 allocation operations and unit tests around choice wiring. |
| crates/token/src/active_contracts.rs | Adds holdings query helper scoped to an instrument, plus integration test. |
| crates/token/src/accept.rs | Adds accept and accept-all flows (with batching) for pending transfer offers. |
| crates/token/Cargo.toml | Declares the new token crate and its dependencies/dev-dependencies. |
| crates/registry/src/transfer_factory.rs | Updates live test to standardized env vars and makes it instrument-agnostic. |
| crates/ledger/src/websocket/update.rs | Renames and ignores live websocket test; standardizes auth/env vars and adds timeout semantics. |
| crates/ledger/src/websocket/active_contracts.rs | Same live websocket ACS test standardization and adds non-empty assertion. |
| crates/ledger/src/submit.rs | Formatting-only tweak in a unit test. |
| crates/ledger/src/ledger_end.rs | Renames and ignores live test; standardizes client-credentials env vars and .env loading. |
| crates/ledger/src/common.rs | Formatting-only changes in identifier-filter conversion and tests. |
| crates/ledger/src/active_contracts.rs | Standardizes live test module naming/env vars and improves assertions; minor log formatting. |
| crates/examples/src/delete_executed_transfers.rs | Formatting-only import cleanup. |
| crates/common/src/transfer.rs | Formatting-only test assertion change. |
| crates/common/src/transfer_factory.rs | Formatting-only changes in tests. |
| crates/common/src/submission.rs | Formatting-only attribute formatting. |
| crates/common/src/filters.rs | Formatting-only changes mirroring ledger/common conversion tests. |
| crates/common/src/decimal.rs | Formatting-only changes in decimal tests. |
| Cargo.toml | Adds crates/token to the workspace and introduces new shared workspace dependencies (canton-api-client, csv, semver, zip, uuid, log, env_logger, etc.). |
| Cargo.lock | Locks dependency graph including new token crate dependencies. |
| .env.example | Updates and standardizes integration test environment variables and documentation. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| result.value(), | ||
| Decimal::from_str("0.0152415788").unwrap() | ||
| ); | ||
| assert_eq!(result.value(), Decimal::from_str("0.0152415788").unwrap()); |
There was a problem hiding this comment.
I see a lot of whitespace changes. Was clippy/rustfmt not configured correctly until now and this is the correct one, or is your machine misconfigured? This lib should have strict formatting rules like all other repos, I wonder how this would happen.
There was a problem hiding this comment.
Claude says, that the project uses rust fmt defaults, which are pinned by:
- edition = "2024" in Cargo.toml
- channel = "1.94.1" in rust-toolchain.toml
So unless others working on a project have a user-level rustfmt.toml, the formatting changes are simply due to the fact that noone really ran fmt for some time.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
988c5fd to
3c95cf4
Compare
…ials flow in tests
| |----------|---------| | ||
| | `PARTY_ID_1` | First test party | | ||
| | `PARTY_ID_2` | Second test party | | ||
| | `DECENTRALIZED_PARTY_ID` | Registrar (admin) of the instrument | |
There was a problem hiding this comment.
I wonder if we should rename this (with some graceful fallback deprecation warning period) to INSTRUMENT_ADMIN, now that it's not necessarily a decparty at all, if this library can be used with any CIP56 token.
What
This PR adds a new token crate to the workspace. The crate faithfully ports the CIP-56 operation modules from cbtc-lib and removes everything CBTC-specific. The caller now supplies the instrument for every operation.
The crate provides:
The PR also consolidates integration test between the token crate and the rest of the workspace:
cargo test --workspacepasses offline.cargo test --workspace -- --ignored --test-threads=1 integration_.Why
The token operations lived in cbtc-lib and were hardcoded to CBTC. Moving them into canton-lib makes them reusable for any CIP-56 instrument.
How tested
cargo test --workspaceruns the unit tests. They need no network access.cargo test --workspace -- --ignored --test-threads=1 integration_runs the live suite against devnet with two test parties.Key decisions
cbtc-libmodules verbatim. Later commits genericize them, so the reviewer can diff the actual code changes in the port.New dependencies
canton-api-client— generated types and client for the Canton JSON Ledger API; the core of the port.csv— parses the batch-distribution input files.zip+semver— dar_check opens DAR archives (they are zip files) and compares their versions.uuid— generates unique command identifiers.log/env_logger— logging in the crate and in the test runs.