{"_id":"@bootnodedev/canton-wallet-service","_rev":"2-45422e1fea9257f5cbc54dd6e9a09bcf","name":"@bootnodedev/canton-wallet-service","dist-tags":{"latest":"0.3.0"},"versions":{"0.2.1":{"name":"@bootnodedev/canton-wallet-service","version":"0.2.1","license":"MIT","_id":"@bootnodedev/canton-wallet-service@0.2.1","maintainers":[{"name":"pablofullana","email":"pablofullana@gmail.com"},{"name":"luchobonatti.bn","email":"luciano@bootnode.dev"},{"name":"gabitoesmiapodo","email":"exepotes@gmail.com"},{"name":"fernandomg","email":"fernando.greco@gmail.com"},{"name":"lmcorbalan","email":"lmcorbalan@gmail.com"},{"name":"nico_bn","email":"nicolas@bootnode.dev"},{"name":"fzavalia","email":"zavaliafernando+npmjs@gmail.com"}],"homepage":"https://github.com/BootNodeDev/canton-wallet-service#readme","bugs":{"url":"https://github.com/BootNodeDev/canton-wallet-service/issues"},"bin":{"canton-wallet-service":"dist/server.js"},"dist":{"shasum":"3e7f0e607618e376e99038adcd75f00912b02586","tarball":"https://registry.npmjs.org/@bootnodedev/canton-wallet-service/-/canton-wallet-service-0.2.1.tgz","fileCount":13,"integrity":"sha512-uPLTvzQp3nExOg4cbdW+t9oLmAp3GUxjl4cCL+JQnB0EvHjAoSR4F6D/y49B2NPAYa0YsF39IHE7YoiuOnXMiQ==","signatures":[{"sig":"MEUCIQCU/9xLdkZzSvcmZ7jWsFsV/mRjT5ICfOWhuLJyxri6SQIgLg5QkDknKHDCKV8Zah2/BxtMnG56wQB4XizpEeIP38Q=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":69373},"type":"module","engines":{"node":">=24.15.0"},"gitHead":"89e793f10984ca82d82a0ca0572621fcca973f07","scripts":{"dev":"tsx watch src/server.ts","knip":"knip","lint":"biome check","test":"node --test --experimental-strip-types \"test/**/*.test.ts\"","build":"tsc -p .","start":"node dist/server.js","format":"biome format --write","prepare":"tsc -p . && husky","release":"scripts/release.sh","lint:fix":"biome check --write","typecheck":"tsc --noEmit"},"_npmUser":{"name":"fernandomg","email":"fernando.greco@gmail.com"},"repository":{"url":"git+https://github.com/BootNodeDev/canton-wallet-service.git","type":"git"},"_npmVersion":"11.17.0","description":"JSON-RPC bridge between a CIP-0103 Canton wallet and a Canton participant","directories":{},"_nodeVersion":"24.19.0","dependencies":{"cors":"^2.8.5","dotenv":"^17.2.3","express":"^5.1.0","@canton-network/wallet-sdk":"1.3.1","@canton-network/core-splice-client":"1.10.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"packageManager":"pnpm@12.3.4","devDependencies":{"tsx":"^4.21.0","knip":"^6.33.0","husky":"^9.1.7","typescript":"^5.9.3","@types/cors":"^2.8.19","@types/node":"^25.0.2","lint-staged":"^17.4.1","@biomejs/biome":"2.5.10","@types/express":"^5.0.6","@commitlint/cli":"^21.2.2","@commitlint/config-conventional":"^21.2.2"},"_npmOperationalInternal":{"tmp":"tmp/canton-wallet-service_0.2.1_1788876008918_0.6477578460456002","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@bootnodedev/canton-wallet-service","version":"0.3.0","description":"JSON-RPC bridge between a CIP-0103 Canton wallet and a Canton participant","license":"MIT","repository":{"type":"git","url":"git+https://github.com/BootNodeDev/canton-wallet-service.git"},"type":"module","packageManager":"pnpm@12.3.4","engines":{"node":">=24.15.0"},"bin":{"canton-wallet-service":"dist/server.js"},"publishConfig":{"access":"public"},"scripts":{"build":"tsc -p .","prepare":"tsc -p . && husky","typecheck":"tsc --noEmit","dev":"tsx watch src/server.ts","start":"node dist/server.js","lint":"biome check","lint:fix":"biome check --write","format":"biome format --write","knip":"knip","test":"node --test --experimental-strip-types \"test/**/*.test.ts\"","release":"scripts/release.sh"},"dependencies":{"@canton-network/core-splice-client":"1.10.1","@canton-network/wallet-sdk":"1.3.1","cors":"^2.8.5","dotenv":"^17.2.3","express":"^5.1.0"},"devDependencies":{"@biomejs/biome":"2.5.10","@commitlint/cli":"^21.2.2","@commitlint/config-conventional":"^21.2.2","@types/cors":"^2.8.19","@types/express":"^5.0.6","@types/node":"^25.0.2","husky":"^9.1.7","knip":"^6.33.0","lint-staged":"^17.4.1","tsx":"^4.21.0","typescript":"^5.9.3"},"gitHead":"ef7fb5be38d23d7e0f593dae7ff6fca94ee1ce9a","_id":"@bootnodedev/canton-wallet-service@0.3.0","bugs":{"url":"https://github.com/BootNodeDev/canton-wallet-service/issues"},"homepage":"https://github.com/BootNodeDev/canton-wallet-service#readme","_nodeVersion":"24.19.0","_npmVersion":"11.17.0","dist":{"integrity":"sha512-C+cT4UBUpivKZBW1DPt16+0ySTwTN1tsgcWjyKqvsaYLpli1KGXWMSWuVijdtIzln/ff89S+8J2ygCvp1sMD5Q==","shasum":"9bf623d755038f7b2a899fab37f54e280a86f5c3","tarball":"https://registry.npmjs.org/@bootnodedev/canton-wallet-service/-/canton-wallet-service-0.3.0.tgz","fileCount":13,"unpackedSize":69845,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bootnodedev%2fcanton-wallet-service@0.3.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDtsWnbI2V3EgACTAQ2meyYLSMVU+K3B5rNz1TAuyD54gIhAOnvdbwwf572hpv0iasnKH/hLm/k92Ix8BcrSD6917Tu"}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:90575622-f817-4fd0-b124-a78f6c26aad6"}},"directories":{},"maintainers":[{"name":"pablofullana","email":"pablofullana@gmail.com"},{"name":"luchobonatti.bn","email":"luciano@bootnode.dev"},{"name":"gabitoesmiapodo","email":"exepotes@gmail.com"},{"name":"fernandomg","email":"fernando.greco@gmail.com"},{"name":"lmcorbalan","email":"lmcorbalan@gmail.com"},{"name":"nico_bn","email":"nicolas@bootnode.dev"},{"name":"fzavalia","email":"zavaliafernando+npmjs@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/canton-wallet-service_0.3.0_1788961384364_0.7785838416725455"},"_hasShrinkwrap":false}},"time":{"created":"2026-09-08T14:00:08.796Z","modified":"2026-09-09T13:43:05.063Z","0.2.1":"2026-09-08T14:00:09.066Z","0.3.0":"2026-09-09T13:43:04.496Z"},"bugs":{"url":"https://github.com/BootNodeDev/canton-wallet-service/issues"},"license":"MIT","homepage":"https://github.com/BootNodeDev/canton-wallet-service#readme","repository":{"type":"git","url":"git+https://github.com/BootNodeDev/canton-wallet-service.git"},"description":"JSON-RPC bridge between a CIP-0103 Canton wallet and a Canton participant","maintainers":[{"name":"pablofullana","email":"pablofullana@gmail.com"},{"name":"luchobonatti.bn","email":"luciano@bootnode.dev"},{"name":"gabitoesmiapodo","email":"exepotes@gmail.com"},{"name":"fernandomg","email":"fernando.greco@gmail.com"},{"name":"lmcorbalan","email":"lmcorbalan@gmail.com"},{"name":"nico_bn","email":"nicolas@bootnode.dev"},{"name":"fzavalia","email":"zavaliafernando+npmjs@gmail.com"}],"readme":"# Canton Wallet Service\n\nExpress JSON-RPC bridge between a CIP-0103 wallet and a Canton participant.\n\nIt is intentionally app-agnostic: app-specific Daml commands come from the\nconsumer, the wallet owns signing and approval UI, and this service only handles\nCanton connectivity, participant reads, prepared transaction execution, and\nwallet-internal party onboarding.\n\n## Install\n\n```bash\npnpm add -D @bootnodedev/canton-wallet-service\npnpm exec canton-wallet-service\n```\n\nThe package ships `dist/` prebuilt, so nothing of its own runs at install time.\npnpm may still stop twice, for reasons outside this package:\n\n- `protobufjs`, a dependency of the Canton SDK, has an install script that only\n  prints a version warning. Allow or deny it with `pnpm approve-builds`; pnpm 12\n  refuses `pnpm exec` until that is decided.\n- pnpm 12 holds back versions published less than a day ago\n  (`minimumReleaseAge`). To take a release the same day, list this package\n  under `minimumReleaseAgeExclude` or lower the setting.\n\nPin the exact version: a release is cut whenever the wire surface changes.\n\nConfiguration is environment-only (see `.env.example`), so a consumer supplies\nit however it already supplies env to its own processes.\n\n## Run\n\nRequires Node 24 (see `.nvmrc`) and a reachable Canton participant.\n\n```bash\npnpm install\ncp .env.example .env   # then fill CANTON_BACKEND_TOKEN\npnpm run dev           # or: pnpm run build && pnpm start\ncurl -fsS http://localhost:3010/health\n```\n\nThe image builds from this repository root and needs no wider build context:\n\n```bash\ndocker build -t canton-wallet-service .\n```\n\n`docker-compose.yml` builds that image and reads an `.env` beside it, which is\nhow the service is deployed on a host of its own:\n\n```bash\ncp .env.example .env   # then fill in the credentials for that network\ndocker compose up --build -d\n```\n\n## Token\n\nReal Canton calls require a bearer token the participant's ledger API accepts.\nThis service never mints one from a signing recipe; it takes credentials one of\ntwo ways, and refuses to start with neither.\n\n**Static token.** `CANTON_BACKEND_TOKEN` is a token minted wherever the\nparticipant's signing recipe lives — on Splice LocalNet, a dev JWT with subject\n`ledger-api-user`. This is the LocalNet path and needs nothing else.\n\n**OAuth client credentials.** A hosted validator issues short-lived tokens, so\nsetting any `EXTERNAL_OAUTH_*` variable switches the service to fetching one\nitself by client-credentials grant, caching it, and refreshing a minute before\nit expires. `CANTON_BACKEND_TOKEN` is then neither read nor needed.\n\n| Variable                       | Purpose                                        |\n| ------------------------------ | ---------------------------------------------- |\n| `EXTERNAL_OAUTH_TOKEN_URL`     | The provider's token endpoint.                 |\n| `EXTERNAL_OAUTH_CLIENT_ID`     | Machine-to-machine client id.                  |\n| `EXTERNAL_OAUTH_CLIENT_SECRET` | Its secret. Never comes from a preset.         |\n| `EXTERNAL_OAUTH_SCOPE`         | Usually `daml_ledger_api`.                     |\n| `EXTERNAL_OAUTH_AUDIENCE`      | Optional. Sent only when set, for providers that gate on `aud`. |\n| `EXTERNAL_PRESET`              | Optional. Supplies defaults for a known validator. |\n\nOn the OAuth path no localhost default is allowed to stand in for an endpoint:\n`CANTON_JSON_API_URL` and the three `SPLICE_*` URLs must name the hosted\nvalidator, whether from the environment or from `EXTERNAL_PRESET`. Missing,\nmalformed, or loopback values fail at startup naming the variable rather than at\nthe first Canton call — a service that boots green and refuses every Canton call\nis the worse outcome.\n\nA preset (`src/presets/`) is checked-in source, so it carries endpoints and\npublic OAuth fields only, never the secret. It fills what it knows and no more:\n`fivenorth` has no published scan host, so `SPLICE_SCAN_API_URL` still has to be\nsupplied alongside it.\n\n## API Boundary\n\nThe public dApp surface is CIP-0103. The wallet exposes that provider to dApps;\nthis service exposes only the HTTP JSON-RPC bridge the wallet needs at:\n\n```text\nPOST /rpc\n```\n\n- [CIP-0103 Provider API](https://github.com/canton-foundation/cips/blob/main/cip-0103/cip-0103.md#provider-api)\n- [CIP-0103 Synchronous dApp API](https://github.com/canton-foundation/cips/blob/main/cip-0103/cip-0103.md#synchronous-dapp-api)\n- [Vendored OpenRPC dApp API](api-specs/openrpc-dapp-api.json)\n\nService-specific methods:\n\n| Method               | Caller                          | Purpose                                                                                                          |\n| -------------------- | ------------------------------- | ---------------------------------------------------------------------------------------------------------------- |\n| `prepareTransaction` | the wallet                      | Calls Canton interactive submission prepare and returns the prepared transaction payload/hash for local signing. |\n| `executePrepared`    | the wallet                      | Submits the wallet's signature over a prepared transaction to Canton.                                            |\n| `ledgerApi`          | the wallet on behalf of the dApp | Proxies app-user JSON API reads/writes and injects the Canton bearer token. `resource` must resolve to the configured JSON API origin; anything off it is refused with `-32602`, since the injected token would otherwise travel with it. |\n\n### CIP-56 token methods\n\nThese add Canton token-standard reads and transfers plus Amulet (Canton Coin) preapproval. They are token-standard / Amulet logic, not consumer-dApp logic.\n\n| Method | Purpose |\n| --- | --- |\n| `cip56.listHoldingSummary` | Per-instrument token balance summaries for a party, from the participant's active contract snapshot. |\n| `cip56.listHoldings` | Raw token holding UTXOs for a party. |\n| `cip56.listPendingTransfers` | Pending incoming CIP-56 transfer instructions for a party. |\n| `cip56.createTransfer` | Prepares a token transfer for the caller to sign and execute. |\n| `cip56.acceptTransfer` | Prepares acceptance of a pending incoming transfer. |\n| `amulet.preapproval.status` | Reads the Amulet transfer-preapproval (auto-accept) status for a receiver. |\n| `amulet.preapproval.create` | Prepares enabling Amulet auto-accept. |\n| `amulet.preapproval.cancel` | Prepares disabling Amulet auto-accept. |\n| `amulet.preapproval.acceptProposal` | Accepts a `TransferPreapprovalProposal` for the receiver. |\n| `amulet.tap` | Prepares the fixed 100 AMT Splice DevNet faucet tap for a receiver (DevNet only). |\n\nThe write methods (`create*`, `acceptTransfer`, `amulet.preapproval.create/cancel/acceptProposal`, `amulet.tap`) return prepared transactions; the wallet signs locally and submits via `executePrepared`.\n\n`prepareExecute`, `prepareExecuteAndWait`, and `signMessage` stay in the\nwallet because they require the user's key and approval UI.\n\nFor `ledgerApi` semantics, read the upstream spec instead of duplicating it:\n\n- [CIP-0103 `ledgerApi`](https://github.com/canton-foundation/cips/blob/main/cip-0103/cip-0103.md#ledgerapi)\n- [CIP-0103 JSON Ledger API rationale](https://github.com/canton-foundation/cips/blob/main/cip-0103/cip-0103.md#interoperability-with-the-json-ledger-api)\n- [`LedgerApiRequest` schema](api-specs/openrpc-dapp-api.json)\n\n## Admin Endpoints\n\nExternal party onboarding is wallet/provider operational logic, not generic\ndApp API. See\n[CIP-0103 topology-related capabilities](https://github.com/canton-foundation/cips/blob/main/cip-0103/cip-0103.md#topology-related-capabilities).\n\nThe wallet uses these wallet-internal endpoints:\n\n| Endpoint                     | Purpose                                                                                              |\n| ---------------------------- | ---------------------------------------------------------------------------------------------------- |\n| `POST /admin/party/prepare`  | Prepares the external party topology transaction and returns `{ onboardingId, partyId, multiHash }`. |\n| `POST /admin/party/complete` | Submits the signed topology transaction, grants user rights, and returns the created party.          |\n\nThese endpoints stay outside `/rpc` so the dApp API remains a projection of\nthe CIP/OpenRPC surface.\n\n## Releasing\n\nMerging a version bump to `main` is the release. Nothing is published from a\nlaptop.\n\n```bash\npnpm release minor                 # or patch / major: branch release/X.Y.Z, commit \"chore: release X.Y.Z\"\ngit push -u origin release/X.Y.Z   # open the pull request, wait for the checks, merge\n```\n\nOn the merge, `.github/workflows/release.yml` sees a version that is not on npm\nyet, runs the same gates as a pull request, publishes, and creates the tag\n`vX.Y.Z` and the GitHub Release with notes since the previous tag. Ordinary\nmerges change nothing. A run that failed halfway can be re-run: what already\nexists is skipped.\n\nPublishing needs no token. npm's trusted publishing accepts the identity GitHub\ngives the run, registered on npmjs.com under the package's settings as GitHub\nActions, repository `BootNodeDev/canton-wallet-service`, workflow `release.yml`.\nProvenance is attached automatically.\n","readmeFilename":"README.md"}