@fairmint/wrapped-assets-sdk
v0.0.5
Published
Opinionated Canton Network Token Standard registry over the WrappedAssets-v01 DAML contracts: factories, choice contexts and instrument reads, assembled from a narrow ledger port.
Readme
@fairmint/wrapped-assets-sdk
The Canton Network Token Standard registry for the WrappedAssets-v01 DAML contracts: the registry
reads a wallet asks for, and a command builder for every choice the contracts define. Nothing here
submits — a builder returns a Ledger JSON API command plus the disclosures the submission carries,
and handing that to a ledger client is the caller's step.
Not the generated Daml bindings. Those are
@fairmint/wrapped-assets-daml-js,
published from this repository and versioned separately — and a dependency of this package rather
than an alternative to it. Every template id, interface id, choice name and choice-argument shape
here is read off those bindings, pinned to 0.0.2, so this SDK tracks exactly the DAR that version
was generated from: registry factories, instrument pause and compliance enforcement included. A
choice a later DAR renames or drops stops this package compiling instead of failing at submission
time.
This package is not opinionated about which ledger client you use. Inject a RegistryLedger, or a
duck-typed JSON API reader (getActiveContracts + getEventsByContractId). To read CIP-56 results,
use @fairmint/canton-node-sdk (or another client) with this package's CHOICES / TEMPLATE_IDS.
Install
npm install @fairmint/wrapped-assets-sdkimport { createWrappedAssetsRegistry } from '@fairmint/wrapped-assets-sdk';
// `ledger` is a RegistryLedger, or any JSON API reader with
// getActiveContracts + getEventsByContractId.
const registry = createWrappedAssetsRegistry({
ledger: client,
adminId: 'OTA::1220aaaa',
instruments: [{ id: 'FMT-A', name: 'Fairmint Wrapped A', symbol: 'FMTA', decimals: 6 }],
});
await registry.listInstruments();What to reach for
| Intent | Start at |
| --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| Serve the registry API: instruments, factories, choice contexts | createWrappedAssetsRegistry, createWrappedAssetsRegistryFromJsonApiClient |
| Issue or rewrap units (pause-gated) | getBurnMintFactory, buildMintCommand, buildBurnMintCommand |
| Retire units (pause-blind) | getBurnFactory, buildBurnCommand |
| Redeem: the owner consents, the transfer agent burns later | buildBurnOfferCreateCommand, and the Accept/Reject/Withdraw/Expire builders beside it |
| Send units, or settle one leg of a trade | buildTransferCommand, buildAllocateCommand, and the accept, reject, withdraw and cancel builders |
| Compliance: freeze, release, confiscate, pause | buildEnforceHoldingsCommand, buildBurnHoldingEnforcementCommand, buildEnforceInstrumentsCommand |
| Stand up or retire a factory or an instrument | build*ProposalCreateCommand and the accept, reject and withdraw builders for each |
| Name or match a template, interface or choice | TEMPLATE_IDS (commands), TEMPLATES + matchesTemplate (create events), CHOICES, *_INTERFACE_ID |
| Handle failure | NotFoundError (404), BadRequestError (400), UnavailableError (503) |
| Implement the ledger yourself, or read from something else | RegistryLedger, and test/support/fixtures.ts as a worked example |
| Validate a request or a response against the standard | @fairmint/wrapped-assets-sdk/schemas |
The ./schemas entry point is Zod schemas for every request and response the standard defines,
generated during npm run build from the four OpenAPI documents Splice publishes and pinned by
openapi/specs.lock.json, so a server validating against the standard does not run a generator of
its own. zod is an optional peer dependency, needed only by a consumer that imports that entry
point; the devDependency is pinned to the oldest version the peer range accepts, so a consumer
pinning that version shares one copy of Zod with these schemas rather than comparing two.
Minting is pause-gated and instrument-scoped as of 0.0.4, and a burn-mint caller that passed an
empty context has to fetch one now. CHANGELOG.md has the migration.
Every export carries its contract in a doc comment at its definition, including who controls each choice, which builders are pause-gated, and what each reader refuses to guess at. How the pieces fit together — the registry's place in the OTA architecture, and which DAR is deployed where — is in Fairmint/dev-docs.
Develop
npm install # from the repository root
npm run build:sdk
npm run test:sdkTests are node:test over tsx and never reach a participant node: builders are asserted against
expected JSON, registry reads against the fixture ledger, and test/schemas.test.ts parses every
registry read with the generated schema for the operation that serves it.
src/generated/ is not committed. Build, test and typecheck all run npm run generate first, which
fetches each pinned document if it is absent, refuses one that does not hash to what
openapi/specs.lock.json records, and writes the schemas — so the first run of any of them needs
network access.
Every template this SDK names is now in the WrappedAssets-v01 DAR, and test/templates.test.ts
holds it to that: the choices come off the published bindings, and one of its tests fails if the DAR
declares a choice no builder reaches. What is still unit-tested only is the behaviour of those
commands on a ledger — test/localnet/ reaches a live participant for the factory bootstrap alone,
so the transfer, allocation and enforcement builders are asserted against expected JSON rather than
submitted.
