Skip to content

feat: handle locks using relative expiresAfter - #2398

Merged
pascalhonegger-da merged 5 commits into
mainfrom
2388-expired-locked-holidings-should-be-available-for-transfers
Sep 9, 2026
Merged

pascalhonegger-da merged 5 commits into
mainfrom
2388-expired-locked-holidings-should-be-available-for-transfers

Conversation

@pascalhonegger-da

Copy link
Copy Markdown
Contributor

Closes #2388

@pascalhonegger-da pascalhonegger-da linked an issue Sep 3, 2026 that may be closed by this pull request
@pascalhonegger-da
pascalhonegger-da force-pushed the 2388-expired-locked-holidings-should-be-available-for-transfers branch from aec412e to 949167e Compare September 3, 2026 14:47
Comment thread core/tx-parser/src/types.ts Outdated
@pascalhonegger-da pascalhonegger-da self-assigned this Sep 3, 2026
@pascalhonegger-da
pascalhonegger-da force-pushed the 2388-expired-locked-holidings-should-be-available-for-transfers branch from 949167e to e9b9f63 Compare September 3, 2026 14:51
@pascalhonegger-da
pascalhonegger-da marked this pull request as ready for review September 3, 2026 17:32
@pascalhonegger-da
pascalhonegger-da requested a review from a team as a code owner September 3, 2026 17:32
@fayi-da

fayi-da commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Quick search for other uses of expiresAt and I noticed getInputHoldingsCids which might need some adjustment too as it only checks expiresAt. If we get a holding that has only expiresAfter, then we'll exclude it even after expiry.

cc @mjuchli-da

Comment thread core/tx-parser/src/parser.ts Outdated
Comment thread core/tx-parser/src/types.ts Outdated
@pascalhonegger-da
pascalhonegger-da force-pushed the 2388-expired-locked-holidings-should-be-available-for-transfers branch from e9b9f63 to 91ffbbf Compare September 7, 2026 20:25
@pascalhonegger-da
pascalhonegger-da marked this pull request as draft September 7, 2026 20:28
Signed-off-by: Pascal Honegger <pascal.honegger@digitalasset.com>
Signed-off-by: Pascal Honegger <pascal.honegger@digitalasset.com>
Signed-off-by: Pascal Honegger <pascal.honegger@digitalasset.com>
Signed-off-by: Pascal Honegger <pascal.honegger@digitalasset.com>
@pascalhonegger-da
pascalhonegger-da force-pushed the 2388-expired-locked-holidings-should-be-available-for-transfers branch from a60d5a9 to 99daea7 Compare September 9, 2026 11:56
@pascalhonegger-da
pascalhonegger-da requested a lite review from Copilot September 9, 2026 11:57

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

The new expiresAfter calculation converts microseconds to a JS number/milliseconds in a way that can truncate or lose precision, potentially unlocking holdings earlier or at incorrect times.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR updates holding lock handling so that locks with relative expirations (expiresAfter) are treated as unlocked once they expire, ensuring expired locked holdings can fund transfers and are reflected in available balances (per #2388).

Changes:

  • Update lock checks to use PrettyContract<HoldingView> so expiresAfter can be evaluated relative to the contract’s createdAt.
  • Align wallet SDK, examples, docs, and tx-parser types away from tx-parser’s local Holding shape toward HoldingView.
  • Extend/adjust tests and expected fixtures to reflect the new holding shapes (including contractId) and updated ledger client schema version.
File summaries
File Description
sdk/wallet-sdk/src/wallet/namespace/token/utxos/types.ts Switch UTXO types to PrettyContract<HoldingView> for consistent interface-view typing.
sdk/wallet-sdk/src/wallet/namespace/token/utxos/service.ts Use isHoldingLocked(PrettyContract, now) so relative expirations can be evaluated.
sdk/wallet-sdk/src/wallet/namespace/token/utxos/mergeDelegation.ts Update delegation API types to accept HoldingView-based UTXOs.
examples/portfolio/src/utils/holdings.ts Keep holdings as PrettyContract<HoldingView> instead of converting to a custom Holding object.
examples/portfolio/src/utils/aggregate-holdings.ts Aggregate balances from PrettyContract<HoldingView> and use updated lock check signature.
examples/portfolio/src/hooks/useWalletHoldings.ts Update hook result types to return PrettyContract<HoldingView>[].
docs/wallet-integration-guide/examples/scripts/16-amulet-namespace-no-validator-url.ts Update script typings to use HoldingView.
docs/wallet-integration-guide/examples/scripts/05-preapproval.ts Update script typings to use HoldingView.
core/tx-parser/src/utils.ts Use token-standard HoldingView/Metadata types and tighten metadata helper signatures.
core/tx-parser/src/types.ts Replace local Holding definition with HoldingView-based alias; tighten meta typing.
core/tx-parser/src/test-data/expected/txs.json Update expected outputs to include contractId in holding entries.
core/tx-parser/src/parser.ts Ensure holdings changes include contractId consistently; adjust types to HoldingView/Lock.
core/tx-parser/src/parser.test.ts Bump ledger client schema types from v3_4 to v3_5 for tests.
core/token-standard-service/src/token-standard-service.ts Implement relative expiration (expiresAfter) support in isHoldingLocked and reuse it for filtering.
core/token-standard-service/src/token-standard-service.test.ts Add table-driven tests for absolute/relative lock expirations and precedence behavior.
core/token-standard-service/src/test-data/expected/utility-payload-ledger-effects-sender.json Update expected fixture to include contractId in holdings.
core/token-standard-service/src/test-data/expected/txs.json Update expected fixture to include contractId in holdings.
core/token-standard-service/src/parser.test.ts Bump ledger client schema types from v3_4 to v3_5 for tests.
Review details
  • Files reviewed: 18/18 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread core/token-standard-service/src/token-standard-service.ts
@pascalhonegger-da
pascalhonegger-da marked this pull request as ready for review September 9, 2026 12:10
@pascalhonegger-da

Copy link
Copy Markdown
Contributor Author

Proposed changelog entries for @canton-network/wallet-sdk / breaking changes from this PR (@alexmatson-da FYI)

Proposal:

  • UtxoNamespace.list(...) return type has been narrowed to HoldingView from @canton-network/core-token-standard. The new typing has two incompatibilities:

    • The previously required result.interfaceViewValue.contractId was always undefined at runtime, use result.contractId instead.
    • The previous typing for result.interfaceViewValue.lock included an expiresAfter: string. The new type matches the runtime behavior: expiresAfter: { microseconds: number }.
  • TokenStandardService.isHoldingLocked now requires PrettyContract<HoldingView> as an input. Previously, holdings passed to this function could end up as locked forever even though they should only have been locked for a short period of time (see Expired locked holdings should be available for transfers #2388)

Comment thread core/tx-parser/src/types.ts Outdated
Signed-off-by: Pascal Honegger <pascal.honegger@digitalasset.com>
@pascalhonegger-da
pascalhonegger-da merged commit 057caf1 into main Sep 9, 2026
29 checks passed
@pascalhonegger-da
pascalhonegger-da deleted the 2388-expired-locked-holidings-should-be-available-for-transfers branch September 9, 2026 19:55
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.

Expired locked holdings should be available for transfers

5 participants