Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
abc4829
refactor(core-token-standard): update type export
mateuszpiatkowski-da Jul 18, 2026
8455fa6
fix(core-token-standard-service): revert code
mateuszpiatkowski-da Jul 18, 2026
36825ea
refactor(wallet-sdk,core-ledger-client-types): move wrappedcommand type
mateuszpiatkowski-da Jul 18, 2026
71ffc8e
feat(core-test-token): update test token core export
mateuszpiatkowski-da Jul 18, 2026
fc46701
chore: docs minor corrections (#2172)
mjuchli-da Jul 20, 2026
e6e0f81
feat: add generate types script (#2171)
mateuszpiatkowski-da Jul 20, 2026
0acd2f6
fix(core-token-standard-service): revert code
mateuszpiatkowski-da Jul 20, 2026
b91d3a2
chore: splice provide readme (#2174)
mjuchli-da Jul 20, 2026
f51f3ae
feat: show an offers count badge in the sidebar (#2162)
fayi-da Jul 20, 2026
1c5198c
chore: provider diagram (#2175)
mjuchli-da Jul 20, 2026
ed79d51
chore(deps): bump axios from 1.16.0 to 1.18.1 (#2178)
dependabot[bot] Jul 21, 2026
3ac3556
chore(deps): bump body-parser from 1.20.4 to 1.20.6 (#2180)
dependabot[bot] Jul 21, 2026
87b5ae4
chore(deps): bump tar from 7.5.11 to 7.5.20 (#2181)
dependabot[bot] Jul 21, 2026
e953107
chore: readme (#2179)
mjuchli-da Jul 21, 2026
abe5325
chore: refactor portfolio registry discovery and reachability (#2177)
fayi-da Jul 21, 2026
088f8a8
feat(example-test-token-v1-registry): create backend registry example
mateuszpiatkowski-da Jul 21, 2026
1ed77b2
fix(example-test-token-v1-registry): adjust code after rebase
mateuszpiatkowski-da Jul 21, 2026
e6377bf
chore(deps): migrate monorepo library builds from tsup to tsdown (#2173)
singhyash05 Jul 21, 2026
7006d92
fix: add pagination to list tx (#2166)
rukmini-basu-da Jul 21, 2026
83da103
feat: update core-test-token, add type export refactor (#2170)
mateuszpiatkowski-da Jul 22, 2026
7cc19e9
feat(example-test-token-v1-registry): adjust after merge
mateuszpiatkowski-da Jul 22, 2026
33b5ff8
chore: reinstall yarn deps
mateuszpiatkowski-da Jul 22, 2026
2fa8c16
Merge remote-tracking branch 'origin/main' into mateuszpiatkowski-da/…
mateuszpiatkowski-da Jul 22, 2026
974cb7d
fix(example-portfolio): fix build
mateuszpiatkowski-da Jul 22, 2026
8809a6b
fix(example-test-token-v1-registry): fix path
mateuszpiatkowski-da Jul 23, 2026
5973b19
fix(core-test-token): fix circular dependency
mateuszpiatkowski-da Jul 23, 2026
abbc086
test(example-test-token-v1-registry): add test, fix coverage
mateuszpiatkowski-da Jul 23, 2026
42c4596
docs(example-test-token-v1-registry): add openapi-ts files
mateuszpiatkowski-da Jul 23, 2026
f60e582
refactor(example-test-token-v1-registry): removed unused code
mateuszpiatkowski-da Jul 23, 2026
daea919
refactor(example-test-token-v1-registry): change package commands, es…
mateuszpiatkowski-da Jul 23, 2026
bb61773
refactor(example-test-token-v1-registry): change backend port
mateuszpiatkowski-da Jul 23, 2026
b6f337e
docs(example-test-token-v1-registry): update docs
mateuszpiatkowski-da Jul 23, 2026
67fcfbf
docs(example-test-token-v1-registry): add inline comments
mateuszpiatkowski-da Jul 23, 2026
9950f44
docs(example-test-token-v1-registry): add explanatory comments
mateuszpiatkowski-da Jul 23, 2026
2000aca
refactor(example-test-token-v1-registry): split boolean
mateuszpiatkowski-da Jul 23, 2026
7e7b421
refactor(example-test-token-v1-registry): rename admin to operator
mateuszpiatkowski-da Jul 23, 2026
ae67839
feat(core-token-standard): enable using off-ledger interfaces
mateuszpiatkowski-da Jul 24, 2026
26a37be
feat(example-test-token-v1-registry): switch to core-token-standard i…
mateuszpiatkowski-da Jul 24, 2026
d9f7a53
docs(example-test-token-v1-registry): add mermaid diagram
mateuszpiatkowski-da Jul 24, 2026
39f752e
test(example-test-token-v1-registry): update tests
mateuszpiatkowski-da Jul 24, 2026
6cc94da
Merge branch 'main' into mateuszpiatkowski-da/ref-token-backend-regis…
mateuszpiatkowski-da Jul 24, 2026
e4c0c32
fix(core-wallet-test-utils): fix build
mateuszpiatkowski-da Jul 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ packageExtensions:
dependencies:
'@inquirer/prompts': ^3.0.0
'@open-rpc/schema-utils-js': ^2.0.2
openapicmd@*:
dependencies:
lodash: '*'
indent-string: ^4.0.0
strip-ansi: '*'
chalk: '*'
undici-types@*:
dependencies:
'@types/node': '*'
Expand Down
1 change: 1 addition & 0 deletions core/eslint-config/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export function createConfig({ rootDir }) {
'damljs/**',
'docs/wallet-integration-guide/examples/**',
'examples/ping/playwright-report/**',
'examples/test-token-v1-registry/src/openapi-ts/**',
'core/rpc-generator/templates/client/typescript/src/index.ts',
],
},
Expand Down
2 changes: 1 addition & 1 deletion core/test-token/src/commands.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025-2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

import { TestTokenV1 } from 'src'
import { TestTokenV1 } from './token'
import {
Allocation,
AllocationFactory,
Expand Down
5 changes: 1 addition & 4 deletions core/test-token/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
// Copyright (c) 2025-2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

import { Splice } from '@daml.js/test-token-v1'

export { packageId } from '@daml.js/test-token-v1'
export const TestTokenV1 = Splice.Testing.Tokens.TestTokenV1
export * from './token'
export * from './commands'
7 changes: 7 additions & 0 deletions core/test-token/src/token.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Copyright (c) 2025-2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

import { Splice } from '@daml.js/test-token-v1'

export { packageId } from '@daml.js/test-token-v1'
export const TestTokenV1 = Splice.Testing.Tokens.TestTokenV1
7 changes: 7 additions & 0 deletions core/token-standard/src/generated-clients/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Copyright (c) 2025-2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

export * as AllocationInstructionV1 from './splice-api-token-allocation-instruction-v1/allocation-instruction-v1'
export * as AllocationV1 from './splice-api-token-allocation-v1/allocation-v1'
export * as MetadataV1 from './splice-api-token-metadata-v1/token-metadata-v1'
export * as TransferInstructionV1 from './splice-api-token-transfer-instruction-v1/transfer-instruction-v1'
1 change: 1 addition & 0 deletions core/token-standard/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
export * from './token-standard-client.js'
export * from './interface-ids.const.js'
export * from './types'
export * as OffLedger from './generated-clients/index.js'

export * from '@daml.js/token-standard-models-1.0.0'
13 changes: 11 additions & 2 deletions core/wallet-test-utils/src/signing-provider-mocks/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@

import * as http from 'node:http'

type BodyChunk = Buffer | string | Uint8Array

interface BodyReadableRequest {
method?: string | undefined
on(event: 'data', listener: (chunk: BodyChunk) => void): this
on(event: 'end', listener: () => void): this
on(event: 'error', listener: (error: Error) => void): this
}

export interface MockHttpResponse {
status?: number
body?: unknown
Expand Down Expand Up @@ -47,7 +56,7 @@ export interface SigningProviderMockServer {
close(): Promise<void>
}

function readRawBody(req: http.IncomingMessage): Promise<string> {
function readRawBody(req: BodyReadableRequest): Promise<string> {
return new Promise((resolve, reject) => {
const chunks: Buffer[] = []
req.on('data', (chunk) => chunks.push(Buffer.from(chunk)))
Expand All @@ -58,7 +67,7 @@ function readRawBody(req: http.IncomingMessage): Promise<string> {
})
}

async function parseRequestBody(req: http.IncomingMessage): Promise<unknown> {
async function parseRequestBody(req: BodyReadableRequest): Promise<unknown> {
if ((req.method ?? 'GET').toUpperCase() !== 'POST') {
return {}
}
Expand Down
188 changes: 188 additions & 0 deletions examples/test-token-v1-registry/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
# @canton-network/example-test-token-v1-registry

Example backend registry implementation for CIP-0056 token flows on Canton.

## Overall Description

This project is a reference implementation of a token registry backend for the Test Token V1 standard. It exposes registry API endpoints for:

- token metadata
- transfer instructions
- allocations
- allocation instructions

Comment thread
mateuszpiatkowski-da marked this conversation as resolved.
### Purpose

- provides a reusable second CIP-0056 test token backend (beyond Amulet) so application tests do not become Amulet-specific
- reduces duplication across teams by offering a shared, easy-to-deploy testing token instead of requiring each team to build a token from scratch
- modernizes and harden the earlier prototype by aligning with current Wallet SDK usage and adding verification via automated tests
- provides practical coverage of registry-facing CIP-0056 workflows to complement on-ledger-only token examples

### App Logic Flow

```mermaid
flowchart LR
subgraph MAIN[Main request path]
direction LR
REQ[/HTTP Request/] --> APP[Registry App] --> ROUTER[Router] --> HANDLER[API handlers] --> RES[/HTTP Response/]
end

subgraph INIT[Startup and initialization]
direction TB
APP --> ADMIN[Admin initialization]
APP --> VET[DAR vetting in dev mode]
end

subgraph DEPS[Package dependencies]
direction TB
WSDK{{"@canton-network/wallet-sdk"}}
CORETEST{{"@canton-network/core-test-token"}}
CORESTD{{"@canton-network/core-token-standard"}}
end

WSDK --> ADMIN
WSDK --> VET
WSDK --> HANDLER
CORETEST --> HANDLER
CORESTD --> HANDLER
```

## Getting Started

### Prerequisites

- Node.js 20+
- Yarn 4.x
- dependencies installed at repository root
- local Canton/localnet setup if you want full end-to-end behavior

### Installation

From repository root:

```bash
yarn install
```

Build only this example:

```bash
yarn workspace @canton-network/example-test-token-v1-registry build
```

Run in development mode:

```bash
yarn workspace @canton-network/example-test-token-v1-registry dev
```

The API listens on `http://localhost:5634`.

## Project Structure

### Local Structure Overview

```text
examples/test-token-v1-registry/
src/
index.ts # app startup, admin init, dev vetting hook
router.ts # route prefix to API handler mapping
common/
sdk.ts # Wallet SDK bootstrap/auth
admin.ts # admin party initialization
vetDaml.ts # dev-only DAR vetting helper
getOpenApiPath.ts # OpenAPI source path resolution
api/
metadata/ # metadata endpoints + tests
transfer-instruction/ # transfer-instruction endpoints + tests
allocation/ # allocation endpoints + tests
allocation-instruction/ # allocation-instruction endpoints + tests
common.ts # shared API context typing helpers
openapi-ts/ # generated TypeScript types from OpenAPI
scripts/
generateTypes.ts # regenerates openapi-ts bindings
__test__/
mocks.ts # test mocks
vitest.config.ts # node+browser test projects and coverage
tsup.config.ts # build configuration
tsconfig.json
```

## Testing

Run tests:

```bash
yarn workspace @canton-network/example-test-token-v1-registry test
```

Run tests with coverage:

```bash
yarn workspace @canton-network/example-test-token-v1-registry test:coverage
```

Notes:

- tests are discovered under `src/**/*.test.ts`
- both node and browser projects are executed
- coverage thresholds are defined in `vitest.config.ts`

## Development & Contribution Guide

## @customize Flag

This example includes `@customize` comments in selected files.

What it is for:

- marks places that are intentionally project-specific
- highlights decisions made for this reference implementation that you will likely want to change in your own token backend
- acts as a migration checklist when copying this project into a new repository or package

When to look it up:

- right after copying/scaffolding this example for your own token
- before first production-like deployment
- when replacing test/demo behavior with your real business logic and infrastructure

How to use it:

1. Search the project for `@customize`.
1. Review each marked location and decide whether to keep, replace, or remove that logic.
1. Prioritize security, auth, persistence, and startup/init code paths first.

Development loop:

1. Modify API handlers and domain logic in `src/api/**`.
2. If API specs change, regenerate types:

```bash
yarn workspace @canton-network/example-test-token-v1-registry generate:types
```

3. Run tests and coverage.
4. Build before opening a PR.

General contribution guidelines for the monorepo: [Contributing Guide](https://github.com/canton-network/wallet/blob/main/docs/CONTRIBUTING.md)

## 6. License

Apache-2.0

## 7. Additional Resources

- [Wallet Repository](https://github.com/canton-network/wallet)
- [dApp Building Documentation](https://github.com/canton-network/wallet/tree/main/docs/dapp-building)
- [Wallet Integration Guide](https://github.com/canton-network/wallet/tree/main/docs/wallet-integration-guide)
- [CIP Repository (including CIP-0056 context)](https://github.com/canton-foundation/cips)

## 8. Bug Reporting

If you find a bug:

1. Open an issue at: [canton-network/wallet issues](https://github.com/canton-network/wallet/issues)
1. Include reproduction steps, expected behavior, and actual behavior.
1. Attach logs and relevant request/response payloads when possible.

If issue templates are available in the repository, prefer using the most specific template.
66 changes: 66 additions & 0 deletions examples/test-token-v1-registry/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
"name": "@canton-network/example-test-token-v1-registry",
"version": "1.0.0",
"type": "module",
"description": "Example registry backend app for CIP-0056 token.",
"license": "Apache-2.0",
"author": "Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>",
"main": "dist/index.cjs",
"module": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"require": "./dist/index.cjs",
"default": "./dist/index.js"
}
},
"scripts": {
"build": "tsdown --onSuccess \"tsc\"",
"dev": "NODE_ENV=development tsx --watch src/index.ts",
"clean": "tsc -b --clean; rm -rf dist",
"flatpack": "yarn pack --out \"$FLATPACK_OUTDIR\"",
"test": "vitest run --project node --project browser",
"test:coverage": "vitest run --project node --project browser --coverage"
},
"devDependencies": {
"@types/koa": "^3",
"@types/koa-bodyparser": "^4",
"@types/lodash": "^4.17.24",
"@types/node": "^25.9.3",
"@vitest/browser-playwright": "^4.1.8",
"@vitest/coverage-v8": "^4.1.8",
"openapicmd": "^2.9.2",
"playwright": "^1.60.0",
"typescript": "^5.9.3",
"vitest": "^4.1.8"
},
"dependencies": {
"@canton-network/core-test-token": "workspace:^",
"@canton-network/core-token-standard": "workspace:^",
"@canton-network/core-types": "workspace:^",
"@canton-network/wallet-sdk": "workspace:^",
"koa": "^3.2.1",
"koa-bodyparser": "^4.4.1",
"openapi-backend": "^5.18.0",
"tsdown": "^0.22.12",
"tsx": "^4.23.0",
"zod": "^4.4.3"
},
"files": [
"dist/**"
],
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "git+https://github.com/canton-network/wallet.git",
"directory": "examples/test-token-v1-registry"
},
"homepage": "https://github.com/canton-network/wallet/tree/main/examples/test-token-v1-registry#readme",
"bugs": {
"url": "https://github.com/canton-network/wallet/issues"
}
}
44 changes: 44 additions & 0 deletions examples/test-token-v1-registry/src/__test__/mocks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (c) 2025-2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

import { vi } from 'vitest'

const execute = vi.fn().mockResolvedValue({
completionOffset: 100,
})
const sign = vi.fn().mockReturnValue({ execute })
const prepare = vi.fn().mockReturnValue({ sign })
const create = vi.fn().mockReturnValue({ sign })

const sdk = {
ledger: {
acsReader: {
readJsContracts: vi.fn(),
},
prepare,
},
keys: {
generate: vi.fn().mockReturnValue({
publicKey: 'test-public-key',
privateKey: 'test-private-key',
}),
},
testToken: {
create: {
rules: vi.fn(),
},
},
party: {
external: {
create,
},
},
}

export const mock = {
sdk,
prepare,
sign,
execute,
create,
}
Loading