Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 12 additions & 0 deletions core/ledger-client-types/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,15 @@ export const LedgerPostRoutes = new Set<string>([
...postPaths_v3_4,
...postPaths_v3_5,
])

export type RawCommandMap = {
ExerciseCommand: LedgerCommonSchemas['ExerciseCommand']
CreateCommand: LedgerCommonSchemas['CreateCommand']
CreateAndExerciseCommand: LedgerCommonSchemas['CreateAndExerciseCommand']
}

export type WrappedCommand<
K extends keyof RawCommandMap = keyof RawCommandMap,
> = {
[P in K]: { [Q in P]: RawCommandMap[P] }
}[K]
3 changes: 3 additions & 0 deletions core/test-token/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.daml
daml
.rollup.cache
106 changes: 106 additions & 0 deletions core/test-token/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# @canton-network/core-test-token

TypeScript wrapper package for the Test Token DAML codegen.

## Exports

From [src/index.ts](src/index.ts):

- `TestTokenV1`: shortcut to `Splice.Testing.Tokens.TestTokenV1`
- `packageId`: re-export from `@daml.js/test-token-v1`
- `commands`: command builders for Test Token templates and choices

## Build

From the repo root:

```sh
yarn workspace @canton-network/core-test-token build
```

The build produces:

- ESM: `dist/index.js`
- CJS: `dist/index.cjs`
- Browser ESM: `dist/index.browser.js`
- Types: `dist/index.d.ts`

## Regenerating DAML Codegen Inputs

This package depends on generated DAML JS artifacts under
`damljs/test-token-v1`.

To refresh those artifacts, run:

```sh
yarn script:generate:test-token
```

Then rebuild this package.

## Usage

```ts
import {
TestTokenV1,
packageId,
commands,
} from '@canton-network/core-test-token'

const template = TestTokenV1
console.log(packageId)

// Build a create command for TokenRules
const createRules = commands.create.rules({ admin: 'Alice::1220...' })

// Build an exercise command for TokenTransferOffer.Accept
const acceptTransfer = commands.exercise.transferOffer.accept({
contractId: '00a1b2c3d4...',
choiceArgument: {},
})
```

## Command Helpers

The `commands` export provides typed helpers that return
`WrappedCommand<'CreateCommand'>` and `WrappedCommand<'ExerciseCommand'>`.

Available builders:

- `commands.create.transferOffer`
- `commands.create.allocation`
- `commands.create.rules`
- `commands.exercise.transferOffer.accept`
- `commands.exercise.transferOffer.reject`
- `commands.exercise.transferOffer.withdraw`
- `commands.exercise.transferOffer.update`
- `commands.exercise.allocation.executeTransfer`
- `commands.exercise.allocation.cancel`
- `commands.exercise.allocation.withdraw`
- `commands.exercise.rules.transfer.transfer`
- `commands.exercise.rules.transfer.publicFetch`
- `commands.exercise.rules.allocation.allocate`
- `commands.exercise.rules.allocation.publicFetch`

Example:

```ts
import { commands } from '@canton-network/core-test-token'

const createAllocation = commands.create.allocation({
allocation: {
// Fill with your AllocationSpecification payload
},
})

const executeTransfer = commands.exercise.allocation.executeTransfer({
contractId: '00f00d...',
choiceArgument: {
// Fill with Allocation_ExecuteTransfer choice argument
},
})
```

## License

Apache-2.0
66 changes: 66 additions & 0 deletions core/test-token/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
"name": "@canton-network/core-test-token",
"version": "1.0.0",
"type": "module",
"description": "daml codegen js for test-token package",
"author": "Mateusz Piątkowski <mateusz.piatkowski@digitalasset.com>",
"license": "Apache-2.0",
"main": "dist/index.cjs",
"module": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"browser": "./dist/index.browser.js",
"import": "./dist/index.js",
"require": "./dist/index.cjs",
"default": "./dist/index.js"
}
},
"scripts": {
"build": "yarn generate:test-token && yarn clean && rollup -c && yarn clean:types-tmp",
"dev": "rollup -c -w",
"clean:types-tmp": "rm -rf dist/types",
"flatpack": "yarn pack --out \"$FLATPACK_OUTDIR\"",
"clean": "rm -rf dist"
},
"dependencies": {
"@canton-network/core-ledger-client-types": "workspace:^",
"@canton-network/core-token-standard": "workspace:^",
"@canton-network/core-types": "workspace:^",
"@canton-network/core-wallet-auth": "workspace:^",
"@daml/types": "^3.5.1",
"@mojotech/json-type-validation": "^3.1.0",
"lodash": "^4.18.1",
"openapi-fetch": "^0.17.0",
"uuid": "^14.0.0",
"zod": "^4.4.3"
},
"devDependencies": {
"@rollup/plugin-alias": "^5.1.1",
"@rollup/plugin-commonjs": "^29.0.3",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^16.0.3",
"@rollup/plugin-typescript": "^12.3.0",
"playwright": "^1.60.0",
"rollup": "^4.62.0",
"rollup-plugin-dts": "^6.4.1",
"tslib": "^2.8.1",
"typescript": "^5.9.3"
},
"files": [
"dist/**"
],
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "git+https://github.com/canton-network/wallet.git",
"directory": "core/test-token"
},
"homepage": "https://github.com/canton-network/wallet/tree/main/core/test-token#readme",
"bugs": {
"url": "https://github.com/canton-network/wallet/issues"
}
}
178 changes: 178 additions & 0 deletions core/test-token/rollup.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
// Copyright (c) 2025-2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

import typescript from '@rollup/plugin-typescript'
import commonjs from '@rollup/plugin-commonjs'
import { nodeResolve } from '@rollup/plugin-node-resolve'
import json from '@rollup/plugin-json'
import alias from '@rollup/plugin-alias'

import fs from 'node:fs'
import path from 'node:path'
import dts from 'rollup-plugin-dts'

const TEST_TOKEN_BASE = path.resolve(
import.meta.dirname,
'../../damljs/test-token-v1'
)

function buildDamlJsPackagesMap(baseDir) {
const packages = {}
const entries = fs.readdirSync(baseDir, { withFileTypes: true })

for (const entry of entries) {
if (!entry.isDirectory()) {
continue
}

const pkgDir = path.join(baseDir, entry.name)
const pkgJsonPath = path.join(pkgDir, 'package.json')

if (!fs.existsSync(pkgJsonPath)) {
continue
}

const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf8'))
if (typeof pkgJson.name !== 'string') {
continue
}

if (!pkgJson.name.startsWith('@daml.js/')) {
continue
}

packages[pkgJson.name] = pkgDir
}

return packages
}

const DAML_JS_PACKAGES = buildDamlJsPackagesMap(TEST_TOKEN_BASE)
const TEST_TOKEN_COMPAT_ALIAS = '@daml.js/test-token-v1'
const TEST_TOKEN_CANONICAL_NAME = '@daml.js/splice-test-token-v1-1.0.0'

if (DAML_JS_PACKAGES[TEST_TOKEN_CANONICAL_NAME]) {
DAML_JS_PACKAGES[TEST_TOKEN_COMPAT_ALIAS] =
DAML_JS_PACKAGES[TEST_TOKEN_CANONICAL_NAME]
}

function buildPathsMap(packageDirs) {
const map = {}
for (const [name, pkgDir] of Object.entries(packageDirs)) {
const pkgJson = JSON.parse(
fs.readFileSync(path.join(pkgDir, 'package.json'), 'utf8')
)
const typesRel = pkgJson.types || pkgJson.typings || 'lib/index.d.ts'
const typesAbs = path.resolve(pkgDir, typesRel)
const libDir = path.resolve(pkgDir, 'lib')
map[name] = [typesAbs]
map[`${name}/*`] = [path.join(libDir, '*')]

// Force deep "module.js" -> ".d.ts" resolution so dts can inline
map[`${name}/lib/*/module.js`] = [path.join(libDir, '*/module.d.ts')]
map[`${name}/lib/*/index.js`] = [path.join(libDir, '*/index.d.ts')]
}
return map
}

function buildAliasEntries(packageDirs) {
const entries = []
for (const [name, pkgDir] of Object.entries(packageDirs)) {
const pkgJson = JSON.parse(
fs.readFileSync(path.join(pkgDir, 'package.json'), 'utf8')
)
const mainAbs = path.resolve(pkgDir, pkgJson.main || 'lib/index.js')
const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
// Sub-path must come before main to avoid premature matching
entries.push({
find: new RegExp(`^${escapedName}/(.+)$`),
replacement: `${pkgDir}/$1`,
})
entries.push({ find: name, replacement: mainAbs })
}
return entries
}

const pathsMap = buildPathsMap(DAML_JS_PACKAGES)
const damlJsAlias = alias({ entries: buildAliasEntries(DAML_JS_PACKAGES) })
const commonjsPlugin = commonjs({
transformMixedEsModules: true,
esmExternals: true,
requireReturnsDefault: false,
})

const pkgPath = path.resolve(process.cwd(), 'package.json')
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'))

// Collect deps + peerDeps (but not devDeps, or excepted ones)
const exceptions = [
'@daml/types',
'@daml/ledger',
'@mojotech/json-type-validation',
]
const external = [
...Object.keys(pkg.dependencies || {}),
...Object.keys(pkg.peerDependencies || {}),
].filter((dep) => !exceptions.includes(dep))

// bundle ESM
const codeEsm = {
input: 'src/index.ts',
output: { file: 'dist/index.js', format: 'es', sourcemap: true },
external,
plugins: [damlJsAlias, json(), commonjsPlugin, nodeResolve(), typescript()],
}

// bundle CJS
const codeCjs = {
input: 'src/index.ts',
output: {
file: 'dist/index.cjs',
format: 'cjs',
interop: 'auto',
sourcemap: true,
exports: 'named',
},
external,
plugins: [damlJsAlias, json(), commonjsPlugin, nodeResolve(), typescript()],
}

// bundle for browser
const codeBrowser = {
input: 'src/index.ts',
output: {
file: 'dist/index.browser.js',
format: 'es',
sourcemap: true,
},
external,
plugins: [
damlJsAlias,
json(),
commonjsPlugin,
nodeResolve({
browser: true, // Prefer browser entrypoints
preferBuiltins: false, // Do NOT use Node builtins
}),
typescript(),
],
}

// bundle DTS including types from codegen
const types = {
input: 'src/index.ts',
output: { file: 'dist/index.d.ts', format: 'es' },
plugins: [
dts({
respectExternal: false,
compilerOptions: {
baseUrl: '.',
paths: pathsMap,
declaration: true,
emitDeclarationOnly: true,
},
}),
],
}

export default [codeEsm, codeCjs, codeBrowser, types]
Loading