Skip to content

Token Registry Integration tests - #668

Open
RodrigoAD wants to merge 11 commits into
mainfrom
test/registry-token-compat
Open

Token Registry Integration tests#668
RodrigoAD wants to merge 11 commits into
mainfrom
test/registry-token-compat

Conversation

@RodrigoAD

@RodrigoAD RodrigoAD commented Jun 11, 2026

Copy link
Copy Markdown
Member
  • Add Canton registry generated bindings through dynamic dar loading
  • Add Integration tests for Inbound/Outbound token transfers for tokens issued through Registry with BnM TPs (in integration-tests module)

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.

Pull request overview

This PR introduces a new registry-kit Go module providing Canton Registry utility onboarding/mint/supply verification helpers plus CCIP “token registry” utilities, and wires these utilities into existing CCIP integration tests.

Changes:

  • Added registry-kit CLI + config/state management for devnet Registry onboarding, minting, and CCIP TokenAdminRegistry linking.
  • Added registry/CCIP utility helpers (ACS discovery, choice-context building, disclosures, pool deploy/send/release helpers, package/DAR checks).
  • Updated integration tests to consume registry-kit and added generated bindings / contract package metadata for Utility DARs.

Reviewed changes

Copilot reviewed 40 out of 58 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
registry-kit/registry/verify.go Adds holding verification utilities (template + interface view + aggregated balance).
registry-kit/registry/supply.go Adds supply aggregation query over Registry Holding contracts.
registry-kit/registry/packages.go Adds Utility DAR loading and package presence checks.
registry-kit/registry/onboarding.go Adds devnet onboarding flows for Provider/Registrar services + instrument configuration creation.
registry-kit/registry/mint.go Adds local mint flow via AllocationFactory with manually assembled choice-context.
registry-kit/registry/mint_devnet.go Adds devnet mint flow using DA operator backend choice-context + disclosures.
registry-kit/registry/discover.go Adds ACS discovery for Registry service/factory contracts.
registry-kit/registry/context.go Adds Registry mint choice-context construction helpers.
registry-kit/registry/bootstrap.go Adds local bootstrap for Registry services (operator=provider=registrar).
registry-kit/registry/acs.go Adds generic ACS contract lookup helpers by template/entity.
registry-kit/registry-kit.yaml.example Adds example devnet configuration (TOML-formatted).
registry-kit/operator/backend.go Adds HTTP client for DA operator backend choice-context + disclosed contract parsing.
registry-kit/main.go Adds CLI entrypoint for canton-registry-kit.
registry-kit/ledger/parse.go Adds transaction parsing helpers (created contract IDs, lock/burn & release outputs).
registry-kit/ledger/devnet_client.go Adds devnet client connection helper using CLDF RPC participant + auth.
registry-kit/ledger/ctf_client.go Adds participant-backed command submission wrapper (create/exercise + disclosures).
registry-kit/ledger/client.go Adds ledger client interface abstraction for registry-kit.
registry-kit/go.mod Introduces standalone Go module for registry-kit.
registry-kit/config/state.go Adds persisted state file for CLI progress tracking.
registry-kit/config/config.go Adds config loader/validator and party-role selection helpers.
registry-kit/config/config_test.go Adds config + state round-trip test.
registry-kit/cmd/runtime.go Adds CLI runtime (config/state loading, connecting, operator client, timeouts).
registry-kit/cmd/root.go Adds Cobra root command + global flags.
registry-kit/cmd/operator.go Adds CLI commands for TAR linking and validation.
registry-kit/cmd/onboarding.go Adds CLI onboarding commands (package checks, provider service request/wait, registrar onboarding, discovery).
registry-kit/cmd/issuer.go Adds CLI issuer lifecycle commands (create instrument, mint, accept mint, query supply).
registry-kit/ccip/validate.go Adds read-only TAR/pool mapping validation and holdings visibility checks.
registry-kit/ccip/send.go Adds BurnMintTokenPool LockOrBurn helpers + SendingMessage creation and TAR factory config.
registry-kit/ccip/release.go Adds BurnMintTokenPool ReleaseFromTicket helper.
registry-kit/ccip/register.go Adds TAR token pool registration helpers (sequence-based + explicit actAs via ledger client).
registry-kit/ccip/pool_context.go Adds disclosure builders and nested extraContext construction for pool send/release/execute.
registry-kit/ccip/pool_context_v1.go Adds “latest bindings” variant of pool extraContext for integration-test compatibility.
registry-kit/ccip/deploy.go Adds helpers to deploy rate limiters and burn/mint pools for a given owner party.
registry-kit/ccip/bundle.go Adds CLDF operations bundle helper.
integration-tests/go.mod Adds local replace for registry-kit and switches canton dep to local v0.0.0.
integration-tests/ccip/registry_send_helpers_test.go Adds helpers for building pool disclosures/choice-context for registry token pool tests.
integration-tests/ccip/ccip_execute_token_registry_test.go Adds full receive-flow integration test using Registry holdings + registrar-owned token pool.
contracts/contracts.go Adds Utility DAR packages + pinned package IDs + splice package constants.
contracts/cmd/bindings/main.go Adjusts bindings generation to skip prim/stdlib dalfs.
bindings/generated/latest/utility/registry_holding_v0/tuple2.go Adds Tuple2 shim type required by utility DAR bindings.
bindings/generated/latest/utility/credential_v0/tuple2.go Adds Tuple2 shim type required by utility DAR bindings.
bindings/generated/latest/utility/credential_v0/credential_v0.go Adds generated utility credential bindings.
bindings/generated/latest/splice/splice_api_token_allocation_v1/splice_api_token_allocation_v1.go Adds generated splice allocation bindings.
bindings/generated/latest/splice/splice_api_token_allocation_instruction_v1/splice_api_token_allocation_instruction_v1.go Adds generated splice allocation-instruction bindings.
bindings/generated/latest/splice/splice_api_featured_app_v1/splice_api_featured_app_v1.go Adds generated splice featured-app bindings.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread registry-kit/registry/context.go
Comment thread registry-kit/ccip/pool_context.go Outdated
Comment thread registry-kit/ccip/pool_context_v1.go
Comment thread registry-kit/ccip/pool_context_v1.go
Comment thread registry-kit/config/config.go Outdated
Comment thread registry-kit/registry/verify.go Outdated
Comment thread registry-kit/registry/verify.go Outdated
Comment thread registry-kit/registry/supply.go Outdated
Comment thread registry-kit/ccip/validate.go Outdated
Comment thread contracts/cmd/bindings/main.go Outdated
@RodrigoAD
RodrigoAD requested a review from friedemannf June 15, 2026 09:58
@RodrigoAD
RodrigoAD marked this pull request as ready for review June 15, 2026 09:58
@RodrigoAD
RodrigoAD requested a review from a team as a code owner June 15, 2026 09:58
@RodrigoAD
RodrigoAD force-pushed the test/registry-token-compat branch 2 times, most recently from 2a2b453 to e229d2f Compare June 30, 2026 13:25
Copilot AI review requested due to automatic review settings August 5, 2026 15:15

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.

Pull request overview

Copilot reviewed 54 out of 66 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • contracts/cmd/bindings/utility_patch.go: Generated file
Suppressed comments (8)

registry-kit/registry/acs.go:51

  • FindFirstContractByEntity also accepts template as any; with FindContractsByEntity updated to require GetTemplateID, this helper should use the same interface type to avoid runtime panics and keep the API consistent.
    registry-kit/registry/supply.go:39
  • QuerySupply filters holdings only by Instrument.Id and ignores the instrument admin/registrar. If two registrars use the same instrument ID string, this will aggregate unrelated holdings into the same supply total.
    registry-kit/registry/mint_devnet.go:121
  • FindMintRequestForInstrument takes an instrumentID parameter but never uses it, so it can return a MintRequest for a different instrument when multiple requests exist in the ACS.
    registry-kit/registry/packages.go:83
  • PackageCheckResult.FoundID is always set to the expected ID even when the package is missing, which makes the result struct misleading for callers/logging.
    registry-kit/registry/acs.go:21
  • FindContractsByEntity uses a forced type assertion (template.(interface{ GetTemplateID() string })) which will panic at runtime if a caller passes the wrong template type. Since GetTemplateID is the only requirement, accept an interface type in the signature instead.

This issue also appears on line 48 of the same file.
registry-kit/ccip/pool_context.go:217

  • DisclosePoolReleaseContracts always uses the provided client for disclosing CCIP-owned contracts (TokenAdminRegistry, RMNRemote, TokenReceiveTicket). This makes the helper unusable in the same multi-participant setups that PoolSend/PoolExecute support via a separate CcipClient.
    integration-tests/ccip/ccip_execute_test.go:87
  • finalityConfigValueFromBlockConfirmations no longer accepts a blockConfirmations argument, but the name still implies it does. Making the parameter optional (variadic) keeps the current call sites working while restoring the meaning of the name (and the previous WaitForFinality behavior for 0).
func finalityConfigValueFromBlockConfirmations() *apiv2.Value {
	return &apiv2.Value{Sum: &apiv2.Value_Variant{Variant: &apiv2.Variant{
		Constructor: "BlockDepth",
		Value:       &apiv2.Value{Sum: &apiv2.Value_Int64{Int64: 2000}},
	}}}
}

contracts/utilitydars/fetch.go:188

  • downloadBundle uses http.DefaultClient with no timeout. If ctx has no deadline/cancel, a network stall can hang indefinitely while fetching the utility DAR bundle (and GetDar currently calls EnsureCache with context.Background()). Consider using an http.Client with a sane Timeout and/or enforcing a default deadline when ctx has none.
func downloadBundle(ctx context.Context, url string) ([]byte, error) {
	req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
	if err != nil {
		return nil, fmt.Errorf("create utility bundle request: %w", err)
	}

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("download utility bundle: %w", err)
	}
	defer resp.Body.Close()

Comment thread registry-kit/ccip/send.go Outdated
Comment on lines +263 to +272
// EncodeUint256Hex encodes a base-10 integer string as a 32-byte hex string (CCIP MessageCodec style).
func EncodeUint256Hex(decimalValue string) string {
n := new(big.Int)
_, ok := n.SetString(decimalValue, 10)
if !ok {
panic("invalid decimal: " + decimalValue)
}
hexStr := n.Text(16)
return strings.Repeat("0", 64-len(hexStr)) + hexStr
}
Copilot AI review requested due to automatic review settings August 5, 2026 15:36

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.

Pull request overview

Copilot reviewed 55 out of 68 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • contracts/cmd/bindings/utility_patch.go: Generated file
Suppressed comments (4)

registry-kit/ccip/send.go:271

  • EncodeUint256Hex currently panics on parse failures and can also panic if the input overflows 256 bits (negative padding length). Since this is in a non-test package and exported, it should return an error instead of panicking and validate uint256 bounds.
    contracts/utilitydars/fetch.go:186
  • downloadBundle uses http.DefaultClient with no timeout. Since this can run in CI or at runtime (via contracts.GetDar), a stalled connection can hang indefinitely. Use an http.Client with a reasonable timeout (or enforce a context deadline).
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("download utility bundle: %w", err)
	}

registry-kit/registry/packages.go:83

  • CheckPackages sets FoundID to expectedID even when the package is missing, which makes the per-package results misleading (a missing package appears to have a found ID). Consider using the actual found ID from the lookup (empty when missing).
    integration-tests/ccip/ccip_execute_test.go:86
  • finalityConfigValueFromBlockConfirmations no longer accepts a block depth and always returns a constant (2000), so the name is now misleading and may confuse future changes/tests. Consider renaming it to reflect the fixed value or reintroducing the parameter.
func finalityConfigValueFromBlockConfirmations() *apiv2.Value {
	return &apiv2.Value{Sum: &apiv2.Value_Variant{Variant: &apiv2.Variant{
		Constructor: "BlockDepth",
		Value:       &apiv2.Value{Sum: &apiv2.Value_Int64{Int64: 2000}},
	}}}

Comment thread registry-kit/operator/backend.go Outdated
Comment on lines +203 to +208
for i := range len(raw) {
if raw[i] == ':' {
out = append(out, raw[start:i])
start = i + 1
}
}
Copilot AI review requested due to automatic review settings August 5, 2026 16:02

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.

Pull request overview

Copilot reviewed 55 out of 68 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • contracts/cmd/bindings/utility_patch.go: Generated file
Suppressed comments (1)

registry-kit/registry/packages.go:83

  • FoundID is always set to the expected package ID, even when the package is missing. This makes the output misleading (a missing package will still report a non-empty FoundID). Set FoundID only when found is true (or populate it from the installed package details).

Comment thread registry-kit/registry/acs.go Outdated
Copilot AI review requested due to automatic review settings August 6, 2026 10:14

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.

Pull request overview

Copilot reviewed 55 out of 68 changed files in this pull request and generated no new comments.

Files not reviewed (1)
  • contracts/cmd/bindings/utility_patch.go: Generated file
Suppressed comments (4)

contracts/contracts.go:253

  • getUtilityDar calls EnsureCache with context.Background(), so a network fetch for utility DARs can block indefinitely (no cancellation/deadline). Using a bounded context here avoids hanging CLI/test runs when the bundle URL is slow/unreachable.
	if err := utilitydars.EnsureCache(context.Background(), utilityPackageIDs()); err != nil {
		return nil, fmt.Errorf("ensure utility DAR cache: %w", err)
	}

integration-tests/ccip/ccip_execute_test.go:86

  • finalityConfigValueFromBlockConfirmations no longer takes a confirmation count and always returns BlockDepth=2000, so the name is now misleading. Consider either restoring a parameter or renaming to reflect the fixed default.
func finalityConfigValueFromBlockConfirmations() *apiv2.Value {
	return &apiv2.Value{Sum: &apiv2.Value_Variant{Variant: &apiv2.Variant{
		Constructor: "BlockDepth",
		Value:       &apiv2.Value{Sum: &apiv2.Value_Int64{Int64: 2000}},
	}}}

registry-kit/registry/packages.go:84

  • PackageCheckResult.FoundID is always set to the expected ID, even when Found is false, which makes the output misleading (it looks like the package ID was found when it wasn’t). Set FoundID only when the package is present.
    registry-kit/ccip/send.go:282
  • EncodeUint256Hex panics on invalid input. Since this is an exported helper, returning an error is safer than crashing the process (especially if this gets reused in CLI paths).

Copilot AI review requested due to automatic review settings August 6, 2026 10:42

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.

Pull request overview

Copilot reviewed 55 out of 68 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • contracts/cmd/bindings/utility_patch.go: Generated file
Suppressed comments (4)

registry-kit/operator/backend.go:205

  • for i := range len(raw) does not compile in Go (cannot range over an int). Range over the string itself to iterate indices.
    registry-kit/registry/context.go:23
  • new(types.CONTRACT_ID(instrumentConfigCID)) / new(types.BOOL(true)) won’t compile because new takes a type, not a value. Create typed variables and take their addresses instead so the ChoiceContext contains the intended values.
    registry-kit/ccip/pool_context_v1.go:20
  • This function uses new(types.CONTRACT_ID(...)) and new(types.BOOL(true)), which won’t compile because new takes a type, not a value. Use typed variables and take their addresses so the ChoiceContext encodes the intended contract IDs/bool.
    contracts/utilitydars/fetch.go:186
  • http.DefaultClient has no timeouts, so fetching the utility bundle can hang indefinitely if the remote stalls (and callers might not set a deadline on ctx). Consider enforcing a bounded timeout for the download.
	resp, err := http.DefaultClient.Do(req)

Comment thread registry-kit/ccip/pool_context.go Outdated
Comment on lines +54 to +73
func registryPoolBurnMintExtraContext(
rateLimiterCID, allocationFactoryCID, instrumentConfigCID string,
enableResultContracts bool,
) splice_api_token_metadata_v1.ChoiceContext {
nestedValues := registry.MintChoiceContext(instrumentConfigCID, enableResultContracts).Values

return splice_api_token_metadata_v1.ChoiceContext{
Values: map[string]splice_api_token_metadata_v1.AnyValue{
string(ratelimiter.RateLimiterContextKey): {
AVContractId: new(types.CONTRACT_ID(rateLimiterCID)),
},
string(burnminttokenpool.BurnMintFactoryContextKey): {
AVContractId: new(types.CONTRACT_ID(allocationFactoryCID)),
},
string(burnminttokenpool.BurnMintFactoryExtraArgsContextValuesContextKey): {
AVMap: &nestedValues,
},
},
}
}
}}}
}

func finalityConfigValueFromBlockConfirmations() *apiv2.Value {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What's this? 😆

The method is called FromBlockConfirmations but we're removing the parameter?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Every test was using the same 2000 value

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I see that - it just seems like an odd choice and LLM-y to touch this unrelated function here and keep calling it FromBlockConfirmations when there isn't anything to take the block confirmations from anymore

add integration tests with registry

fix rebase

add small fixes

fix lint

tidy mods

remove not used reg dars

add registry mod to ci

remove utility dars
@RodrigoAD
RodrigoAD force-pushed the test/registry-token-compat branch from accb943 to 4653040 Compare August 12, 2026 12:09
@github-actions

github-actions Bot commented Aug 12, 2026

Copy link
Copy Markdown

Invalid CODEOWNERS file detected - @RodrigoAD.

1 error(s) were found in the CODEOWNERS file.

See the workflow summary and PR annotations for more information.

@RodrigoAD RodrigoAD changed the title Add Token Registry utilities + Integration tests Token Registry Integration tests Aug 12, 2026
Meta: emptyMetadata(),
},
}
res, err := client.SubmitExerciseMulti(ctx, mintActAs(bootstrap.Party, owner), registryapp.AllocationFactory{}, bootstrap.AllocationFactory, "AllocationFactory_RequestMint", args, []*apiv2.DisclosedContract{disclosed})

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Shouldn't the mint be requested from just the owner? By acting as both parties, doesn't this defeat the purpose of the request-accept-pattern?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

We are using a a single-participant test bootstrap in the test, so for this case makes sense. If we want a realistic mint where the holder and registrar are on different participants with separate credentials, then yes, we'd want two separate submissions

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