@dotk/wasm
v2.1.0
Published
The dotk protocol engine and Kaspa node client as WebAssembly: derive, verify and build .k name transactions in the browser
Maintainers
Readme
@dotk/wasm
The protocol engine behind dotk.name, compiled to WebAssembly. It derives addresses, encodes and decodes registry state, replays the card reader rules, builds and assembles transactions, and speaks wRPC to a Kaspa node, so a page can check what it is shown against the chain instead of trusting whoever served it.
import { DotkProtocol } from '@dotk/wasm'
import genesis from './generated/genesis'
const protocol = new DotkProtocol(genesis, 'mainnet')The bundler target means a bundler resolves the .wasm and fetches it: no init() to call and no
URL to configure. Vite, webpack and Rollup all treat it as an ordinary asset.
DotkProtocol
The engine. Everything below is a method on it, most useful first.
Names and prices. normalizeName folds what a person typed into the on-chain form and
validateName says whether it can be one. keyOf is blake3(name), the key the registry is
indexed by, and registrationFee is what a name of that length costs.
Addresses. deedAddressOf(name, ownerAddress) is where a name's deed lives, which is the one
address a reader can probe a node for. ownerOf turns an address into the (ownerType, owner)
pair a deed stores and ownerAddress turns it back. gapAddress and devfundAddress do the same
for the other two things the registry pays to.
Building a transaction. buildSplit, buildActivate, buildTransfer and buildRelease
produce an intent: the protocol seats, with no funding yet. assemble adds coins, the fee and
the change; assembleWithCards does it for a transfer carrying records, and assembleSweep
reclaims cards on their own. newborn names the deed a split will create, so a reveal can be
built on a commit that has not been sent. applySignatures folds a wallet's answer back in.
Cards, the records object a name carries. cardPlan decides what a transfer should mint and
sweep, verifyCard replays the reader rules against a deed and a UTXO, cardRecords decodes a
blob, and cardAddress and cardValue say where a card lives and what it holds.
Subnames, a label a name's owner points at an address. bob.alice.k is the label bob on
the card of alice.k. subnames lists every sub:<label> record a card carries, each with
the payee it names or, under fault, the tag that refused it. subnameOf answers one label's
payee, and throws that tag where the rules refuse the stored value. subnameValue builds such
a record from an address and subnameKey from a label. subnameValue refuses an address for
another network, and it refuses a payee nobody can spend: a zero payload, or a key that is no
point on the curve. splitSubname divides a typed bob.alice.k into its label and its parent,
and validateSubname answers why an input divides into neither. A payee is the parent owner's
claim, and the chain proves none of it.
How a refusal reads. A method here refuses by throwing, and what it throws is a string. A
refusal that the subname rules name opens that string with the fault tag, for example
bad-label: the label part "Bob" breaks the label rule. The tag is the contract. Match on it,
and show the words to a person.
The keyspace. keyspaceOf(keys) derives the whole partition from a set of deed keys and
answers a DotkKeyspace, whose gapCount, gapBounds and gapAddresses enumerate the gaps
between them without asking anyone.
The build itself. templateHashes reports the covenant bytecode this engine compiled against,
and genesisVersion the one manifest shape it reads.
DotkRpc
A Kaspa node client over wRPC. connect and disconnect bracket a session and isConnected and
url describe it; getInfo, feerate and virtualDaaScore ask the node about itself;
fundingUtxos, covenantUtxos and covenantUtxosByAddresses list what an address holds, split by
whether it carries a covenant id; and submitTransaction sends one.
readyMass answers the node's ready mempool mass, or undefined where the node does not report
it. Pass it to an assembler beside feerate. While it fits in one block, the fee is the relay
floor. Past one block, the fee ranks by storage mass too. Without it, the fee is the feerate on the
fee mass.
It carries no deployment
new DotkProtocol(manifest, network) takes the manifest as an argument, and refuses published
bytecode that does not reproduce the template hashes that manifest states. So one build serves
every deployment, and a version of this package says which engine you have rather than which
registry it is for. What you supply is your own manifest, built into your bundle rather than
fetched, so that an indexer cannot hand a page the identity it judges that same indexer by.
The compatibility that does matter is the manifest schema. genesisVersion() says which shape
this build writes; a manifest declaring a newer one carries fields this build does not read,
which is advisory rather than fatal, and construction refuses a manifest on its contents alone:
bytecode that does not reproduce the pinned template hashes, or a genesis binding that does not
reproduce the registry covenant id.
License
MIT.
