Developer kit and API reference
Build on Dznye Chain: the JavaScript developer kit, how transactions are signed, every transaction type, and every API endpoint, with working examples.
Everything on Dznye Chain is plain HTTP and JSON. Every change is a transaction you sign yourself, so there is no account to register with us and no secret key ever leaves your machine. This page covers the developer kit first, then the details underneath it.
Addresses: the node is https://api.dznye.com (also https://chain.dznye.com/api). The chain is named dznye-1, and its genesis file is at /dznye-1.genesis.json.
The developer kit
One file, a few plain calls. It works in browsers and in Node 24, with no installs.
import { connect, newKey } from 'https://developers.dznye.com/js/chain/sdk.js'; // in Node: './chain/src/sdk.ts'
const dz = connect('https://api.dznye.com', { sponsor: 'https://wallet.dznye.com/sponsor' });
const me = await newKey(); // { address, secret }: keep the secret safe
await dz.setName(me, 'my-app'); // people can now send to @my-app
await dz.send(me, '@alex', '1.5'); // 1.5 DZY to whoever is @alex
const gold = await dz.makeToken(me, { symbol: 'GOLD', name: 'Game gold', supply: '1000' });
await dz.send(me, '@alex', '10', { asset: gold }); // any token
await dz.trade(me, { give: [gold, '10'], want: ['DZY', '2'] });
await dz.take(me, offerId, '3'); // take part of an offer
const { secret, hash } = await dz.newSecret(); // a hash lock: swaps with other chains
const lock = await dz.lock(me, '@alex', '100', { hash, until: Date.now() + 864e5 });
dz.solana(me.address); // the same key, as a Solana address
const shop = await dz.deploy(me, programJson); // a contract
await dz.call(me, shop, 'buy', [], { pay: '0.25' }); // call it, sending 0.25 DZY with it
await dz.view(shop, 'sold'); // ask it something, free
await dz.events(shop); // what it announced
All the calls
| Call | What it does |
|---|---|
connect(node, { sponsor }) | Connect to a node. With sponsor, a newcomer's fees are paid by that welcome fund when the account cannot pay. |
newKey() | Make a new account key: { address, secret }. |
info(), balance(who), whoIs(name) | Read the chain, what an account holds (address or @name), who has a name. |
send(key, to, amount, { asset, memo }) | Send DZY or a token to an address or @name. Amounts as text ("1.5") or whole parts. |
setName(key, name) | Take a name for the account. |
makeToken(key, { symbol, name, decimals, supply, cap, fixed }) | Make a token; returns its id. |
trade(key, { give, want }), take(key, offerId, amount?), offers(), trades(a?, b?) | Post offers, take all or part of one, read open offers and completed trades. |
newSecret(), lock(key, to, amount, { hash, until, asset, note }), claim(key, lock, secret), refund(key, lock), swap(lock) | Hash locks: swaps with other chains and pay on delivery. See swap with other chains. |
solana(address), lookup(name), link(key, solAddress, sig), linkMessage(…) | One account, every chain: the Solana form of an address, everything a name points to, linking another address. |
deploy(key, program, gas), call(key, contract, fn, args, { pay, gas }) | Put a contract up and call it. Calls that would fail are tried first and not sent. |
view(contract, fn, args), events(contract) | Ask a contract something for free; read its events. |
simulate(signedTx) | See what a signed transaction would do and cost, without sending it. |
tx(key, type, data) | Send any transaction type, for anything else. |
Paying fees for your users
An app can pay the fee for its own users. The user signs naming the app as payer, and the app adds its signature. Both signatures cover the same transaction, so neither can change it.
import { Client } from './chain/src/client.ts';
const c = new Client('https://api.dznye.com');
const tx = await c.prepare(userKey, 'transfer', { asset: tokenId, to, amount: 5 }, { payer: appKey.address });
await c.submit(await Client.sponsor(appKey, tx));
The public welcome fund does this for everyday actions: GET /sponsor returns its address and limits, and POST /sponsor {"tx": …} pays for a transaction that names it as payer. See fees and the welcome fund.
Simulate before you send
Wallets and apps can check any signed transaction first:
POST /simulate { "tx": { …signed transaction… } }
→ { "ok": true, "fee": 1000, "gasUsed": 240 } it would work
→ { "ok": false, "failed": "only the owner can take it out" } it would run, then fail (and still cost its gas)
→ { "ok": false, "refused": "not enough balance" } it is invalid and would be refused (free)
Nothing is sent and nothing changes. It is rate-limited to 120 a minute per address.
How a transaction is signed
If you are not using the kit, this is all there is:
- Build
{ chain, from, nonce, type, data }.chainisdznye-1;fromis your address;nonceis thenextNoncefromGET /account/<address>. - Make the message:
"dzy-tx:" + canon({ chain, from, nonce, type, data, signer, payer }).canonwrites JSON with keys sorted, no spaces, whole numbers only. Leave out fields that are absent. - Sign the message with Ed25519 and your secret key. Add the result as
sig(hex). POST /tx { "tx": { …, "sig": "…" } }.
The nonce makes every transaction unique, and the chain name inside the signature means a transaction cannot be replayed on another chain. Amounts are whole numbers of the smallest unit (1 DZY = 1,000,000). If a device key (not the first key) signs, add signer with its address; if another account pays the fee, add payer and its signature as payerSig over "dzy-pay:" + message; if the account needs several keys, add their signatures as cosigs.
Transaction types
| Type | data | What it does |
|---|---|---|
transfer | asset, to, amount, memo? | Send DZY or a token. Memo up to 120 characters, public. |
asset.create | symbol, name, decimals?, supply, mintable, cap? | Make a token (1 DZY to the treasury). |
mint | asset, to, amount, reason?, pool? | A token's maker issues more. For DZY: the issuing key, from a named pool. |
burn | asset, amount | Destroy your own units. DZY goes to the treasury instead. |
offer.create | give {asset, amount}, want {asset, amount}, until? | Post an offer, optionally ending at a time. |
offer.take | id, amount? | Take all of an offer, or amount of what it gives, at its price. Records a trade. |
offer.cancel | id | Take back your own offer; anyone may close an offer that has ended (it goes back to its maker). |
swap.lock | to, asset, amount, hash, until, note? | Lock coins for to until a time (at most 30 days), opened by the secret whose SHA-256 is hash. |
swap.claim, swap.refund | id, secret / id | Claim with the secret before the end (coins go to the receiver), or refund after it (back to the locker). Anyone may send either. |
name.link | net ("sol"), address (or null), sig | Link an address on another chain, proven by its own signature of linkMessage. |
name.set, name.release | name | Take or give up a name (0.1 DZY). |
key.add, key.remove | key | Devices on one account (up to 8 extra). |
agent.allow | key, asset, max, until, fees? | A limited key for software. |
agent.revoke | key | Stop an agent key. |
guardian.set | guardian or null | Choose or remove a recovery guardian. |
recover.start, recover.cancel, recover.finish | account, key / (none) / account | Guardian recovery, with a 3-day wait. |
account.multisig | keys, need (or keys: null) | Require several keys to agree. |
stake.bond, stake.unbond, stake.withdraw | amount / amount / (none) | Validators lock, unlock (14 days) and take out DZY. |
validator.unjail | (none) | A benched validator returns after its day out. |
evidence | a, b (two signed votes) | Prove a validator signed two different votes. |
treasury.spend | to, amount, reason | The issuing key pays from the treasury, in public. |
contract.deploy | code, gas? | Put a contract on the chain (1 DZY). |
contract.call | contract, fn, args, pay?, gas? | Call a contract's function. |
channel.open, channel.fund | to, asset, amount / id, amount | Lock coins in a payment channel. |
channel.close, channel.start, channel.update, channel.settle | id, nonce, a, b, sigA, sigB | Close it together, or alone with a one-day window. |
API reference
Reading
| Request | Gives |
|---|---|
GET / | Chain name, block height, validators, how many must sign, the fee, the latest snapshot, this node's role, any alert. |
GET /account/<address> | Balances, nextNonce, nonce, device keys, agent keys, guardian, name, several-key rule, stake. |
GET /name/<name> | Who holds a name: address, the same key as a Solana address (solana), and linked addresses (links). 404 if nobody. |
GET /assets, GET /offers | Every token and every open offer (with until when it ends). |
GET /trades, /trades?a=<id>&b=<id> | Completed trades, newest last (the chain keeps 500): block, time, maker, taker, what was sold and paid. |
GET /swaps, GET /swap/<id> | Open hash locks and recently finished ones; one lock, with its secret once claimed. |
GET /supply, GET /supply/<asset> | Limit, issued, existing, circulating. For DZY: the treasury, staked amount and each pool. |
GET /validators | The validators, each one's say, every stake. |
GET /contracts, GET /contract/<address> | All contracts; one in full: code, storage, balances, events. |
GET /contract/<address>/view?fn=&args= | Ask a view function, free. args is a JSON list. |
GET /channel/<id> | A payment channel (gone once settled). |
GET /genesis, /blocks?from=1&limit=100, /block/<n> | Everything needed to replay and check the whole chain. |
GET /snapshot | The latest kept snapshot: a block and the whole state after it. |
GET /peers | Places known to hold this chain. |
Writing
| Request | What it does |
|---|---|
POST /tx { "tx": … } | Send a signed transaction. Returns { ok, id } or an error message. |
POST /simulate { "tx": … } | Try a signed transaction without sending it. |
POST /peers { "url": … } | Announce a place that holds this chain. It is checked before it is listed. |
GET /sponsor, POST /sponsor { "tx": … } | On the site: the welcome fund's address and limits; pay for a transaction that names it as payer. |
Limits
- Sending transactions: 60 a minute per address. Reading is open.
- A transaction is at most 2,000 characters (a contract deploy at most 14,000). A validator holds at most 64 waiting transactions per account.
- Browsers on any website may read the API (CORS is open).
Errors you will see
nonce must be N | Another transaction came first. Read nextNonce again. |
bad signature | The message was built differently from the rules above, or a field was changed after signing. |
not enough balance | The account holds less than you are sending (plus the fee, for DZY). |
every transaction costs a fee… | The account has no DZY: name a payer, or fund it. |
Slow down a little (429) | Rate limit: wait and retry. |
wrong chain | The chain field is not dznye-1. |
Check the chain yourself
Everything above can be verified: download the blocks and replay them. See run a node.