Skip to content

JavaScript SDK ​

There are two client libraries, both in the repository:

LibraryWhereUse it when
dApp SDK (NeuroChain)neurochain-web/src/sdk/neurochain.jsYour page holds the user's key (or you are scripting against your own wallet)
Signer SDK (NeuroSigner)packages/neurochain-signer-sdkYour dApp runs on another site and the user signs in their NeuroChain wallet, in a pop-up

Neither is published to npm yet; copy the module or build the package from the repository.

dApp SDK ​

A single ES module with no dependencies. Reads are plain fetch (browser or Node 18+); writes sign with ML-DSA-65 using the same crypto WASM as the wallet, so the node accepts the signatures.

js
import { NeuroChain, OP_TARGETS, toRaw } from './neurochain.js'

const nc = new NeuroChain({ gateway: 'http://localhost:3000' })
OptionDefaultMeaning
gatewayhttp://localhost:3000Gateway base URL
crypto—An already-initialised crypto WASM module
cryptoLoaderloads ../wasm/neuro_wasm_crypto.jsAsync function returning the initialised module

Amounts ​

Every value and amount you pass is human NRO ('1.5', 2, '0.000021'). The SDK converts to integer uNRO with toRaw(), so the amount you sign and the amount you send are always the same. For display, use the *_human fields the API returns.

Reads ​

MethodCallsReturns
networkStatus()GET /api/v1/network/statusHeight, shards, validators
shards()GET /api/v1/shardsPer-shard heights
account(addr)GET /api/v1/accounts/:addrbalance, balance_human, nonce, …
balance(addr)via account{ raw, human, nonce }
nextNonce(addr)via accountConfirmed nonce + 1
validators()GET /api/v1/validatorsValidator list with stake and metrics
blocks({ limit, offset })GET /api/v1/blocksLatest blocks
block(height)GET /api/v1/blocks/:heightOne block
tx(hash)GET /api/v1/transactions/:hashOne transaction
contract(addr) / contracts({ limit, offset })GET /api/v1/contracts…Contract metadata
gasEstimate()GET /api/v1/gas/estimatebase_fee and estimates
contractQuery(addr, fn, args)POST /api/v1/contracts/:addr/call with dry_run: trueParsed return value; no transaction, no gas

Wallet ​

js
const wallet = await nc.walletFromMnemonic('<24 words>')
wallet.address    // neuro:<15 hex>.human
wallet.publicKey  // ML-DSA-65 public key, hex

The private seed stays inside the wallet object; it is never exposed as a property.

Writes ​

js
// Transfer
await nc.transfer({ wallet, to: 'neuro:<address>.human', value: '1.5', gasPrice })

// Any transaction, optionally with call data
await nc.sendTransaction({ wallet, to, value, data, gasPrice })

// Contract call — JSON call data { function, args }
await nc.contractCall({ wallet, address: 'neuro:<10 hex>.app', fn: 'transfer', args: { … }, value, gasPrice })

// Deploy — a transaction to neuro:system.deploy
await nc.deployContract({ wallet, bytecodeHex, name, description, template, initArgs, gasPrice })

Each write reads the next nonce, signs nc-tx-v2|from|to|value|nonce, and posts to POST /api/v1/transactions.

Set the gas price

The SDK defaults to gasPrice: 1 (deploys: 5). The node refuses a transaction priced below the current base fee, which rises under load. Read it first and pass gasPrice explicitly:

js
const { base_fee } = await nc.gasEstimate()
const gasPrice = Math.ceil(base_fee * 1.5)

Signed operations ​

Staking, name registration and other system operations sign against a system target with a millisecond-timestamp nonce (see Wallet → Signed operations):

js
const op = nc.signOp(wallet, OP_TARGETS.name, 0)   // { signature, public_key, nonce }
// merge op into the endpoint's request body

OP_TARGETS has stake (neuro:system.stake) and name (neuro:system.name).

Known issues ​

Known issues in the current SDK

  • Transfers with a non-zero value fail. sendTransaction / transfer send value as a JSON string; the node reads only a number and refuses the request with Missing from/to/value. Calls and deploys with value 0 are not affected. Workaround — sign and post with a numeric value:
    js
    const nonce = await nc.nextNonce(wallet.address)
    const value = Number(toRaw('1.5'))               // uNRO as a number
    const sig = wallet.sign(to, value, nonce)
    await fetch(GATEWAY + '/api/v1/transactions', { method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ from: wallet.address, to, value, nonce, gas_price, ...sig }) })
  • contractQuery returns the raw string when the contract's reply is not clean JSON — NRC-20 replies end with a NUL byte, so you get '{"ok":true,"value":…}' as a string; strip \u0000 and parse.
  • stake() signs the amount converted to uNRO twice, so the node rejects the signature. Until it is fixed, build the request yourself: { address, amount: toRaw(amount), ...nc.signOp(wallet, OP_TARGETS.stake, amount) } posted to /api/v1/staking/stake.
  • staking(addr) requests /api/v1/staking/:addr, which the gateway does not serve; use GET /api/v1/staking/info/:address.
  • contractCall adds a caller field to the call JSON. Contracts ignore it — identity comes from the host — so it is harmless.

Crypto module ​

Signing needs neuro_wasm_crypto — the wallet's WASM build (neurochain-web/src/wasm/neuro_wasm_crypto.js and neuro_wasm_crypto_bg.wasm). It must export nc_keypair_from_words, nc_tx_message and nc_sign. If your page serves it elsewhere, pass a loader:

js
const nc = new NeuroChain({
  gateway: 'http://localhost:3000',
  cryptoLoader: async () => {
    const mod = await import('/wasm/neuro_wasm_crypto.js')
    await mod.default()
    return mod
  },
})

Without the module, reads work and every write throws.

Signer SDK ​

For a dApp on another origin (an exchange, a game) that must not see the user's phrase. The user's NeuroChain web app opens in a pop-up, the user approves, and the signature comes back over postMessage.

ts
import { NeuroSigner } from 'neurochain-signer-sdk'

const signer = new NeuroSigner({
  signerUrl: 'http://localhost:8080/signer',      // the wallet app's /signer page
  allowedOrigins: ['http://localhost:8080'],
})

// Must run directly inside a click handler, or the browser blocks the pop-up
button.onclick = async () => {
  const { address, publicKey } = await signer.connect()
  const { signature, nonce } = await signer.signOperation({
    to: 'neuro:system.dex',
    value: 1000000,          // uNRO
  })
}
MethodReturns
connect(){ address, publicKey }
signOperation({ to, value, actor? }){ signature, publicKey, nonce } — a signed operation for actor (default: the connected address)
isConnected(), getAddress(), getPublicKey()Connection state
close()Closes the pop-up and disconnects

Errors carry a code: POPUP_BLOCKED, CONNECTION_TIMEOUT, SIGNATURE_REJECTED, INVALID_ORIGIN, NOT_CONNECTED. On POPUP_BLOCKED, show the user a direct link to the signer page.

Messages are accepted only from allowedOrigins; set it to your wallet app's origin.