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'] });
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), offers() | Post, take and read market offers. |
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} | Post a swap. |
offer.take, offer.cancel | id | Take a swap in full; take back your own. |
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> | The address that holds a name, or 404. |
GET /assets, GET /offers | Every token and every open offer. |
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.