# JavaScript SDK

> JavaScript SDK для NeuroChain — dApp SDK для читання, підписаних переказів, викликів контрактів, розгортання і стейкінгу та Signer SDK, через який сторонній dApp просить гаманець користувача підписати операцію.

Source: https://docs.nro.world/uk/build/sdk

У репозиторії є дві клієнтські бібліотеки:

| Бібліотека | Де | Коли використовувати |
|------------|----|----------------------|
| **dApp SDK** (`NeuroChain`) | `neurochain-web/src/sdk/neurochain.js` | Ваша сторінка тримає ключ користувача (або скрипт працює з вашим власним гаманцем) |
| **Signer SDK** (`NeuroSigner`) | `packages/neurochain-signer-sdk` | Ваш dApp працює на іншому сайті, а користувач підписує у своєму гаманці NeuroChain у спливному вікні |

Жодна з них ще не опублікована в npm; скопіюйте модуль або зберіть пакет з репозиторію.

## dApp SDK

Один ES-модуль без залежностей. Читання — звичайний `fetch` (браузер або Node 18+); запис підписується ML-DSA-65 тим самим криптомодулем WASM, що й гаманець, тож нода приймає підписи.

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

const nc = new NeuroChain({ gateway: 'http://localhost:3000' })
```

| Опція | За замовчуванням | Значення |
|-------|------------------|----------|
| `gateway` | `http://localhost:3000` | Базова адреса gateway |
| `crypto` | — | Уже ініціалізований криптомодуль WASM |
| `cryptoLoader` | завантажує `../wasm/neuro_wasm_crypto.js` | Асинхронна функція, що повертає ініціалізований модуль |

### Суми

Кожне `value` і `amount`, які ви передаєте, — це **людські NRO** (`'1.5'`, `2`, `'0.000021'`). SDK переводить їх у ціле число uNRO через `toRaw()`, тож підписана й надіслана суми завжди однакові. Для показу використовуйте поля `*_human` з відповідей API.

### Читання

| Метод | Звертається до | Повертає |
|-------|----------------|----------|
| `networkStatus()` | `GET /api/v1/network/status` | Висоту, шарди, валідаторів |
| `shards()` | `GET /api/v1/shards` | Висоти шардів |
| `account(addr)` | `GET /api/v1/accounts/:addr` | `balance`, `balance_human`, `nonce`, … |
| `balance(addr)` | через `account` | `{ raw, human, nonce }` |
| `nextNonce(addr)` | через `account` | Підтверджений nonce + 1 |
| `validators()` | `GET /api/v1/validators` | Валідаторів зі стейком і метриками |
| `blocks({ limit, offset })` | `GET /api/v1/blocks` | Останні блоки |
| `block(height)` | `GET /api/v1/blocks/:height` | Один блок |
| `tx(hash)` | `GET /api/v1/transactions/:hash` | Одну транзакцію |
| `contract(addr)` / `contracts({ limit, offset })` | `GET /api/v1/contracts…` | Метадані контрактів |
| `gasEstimate()` | `GET /api/v1/gas/estimate` | `base_fee` і оцінки |
| `contractQuery(addr, fn, args)` | `POST /api/v1/contracts/:addr/call` з `dry_run: true` | Розібраний результат; без транзакції і без газу |

### Гаманець

```js
const wallet = await nc.walletFromMnemonic('<24 слова>')
wallet.address    // neuro:<15 hex>.human
wallet.publicKey  // публічний ключ ML-DSA-65, hex
```

Приватний seed лишається всередині об'єкта гаманця й ніколи не доступний як властивість.

### Запис

```js
// Переказ
await nc.transfer({ wallet, to: 'neuro:<адреса>.human', value: '1.5', gasPrice })

// Будь-яка транзакція, за потреби з даними виклику
await nc.sendTransaction({ wallet, to, value, data, gasPrice })

// Виклик контракту — дані виклику JSON { function, args }
await nc.contractCall({ wallet, address: 'neuro:<10 hex>.app', fn: 'transfer', args: { … }, value, gasPrice })

// Розгортання — транзакція на neuro:system.deploy
await nc.deployContract({ wallet, bytecodeHex, name, description, template, initArgs, gasPrice })
```

Кожен запис читає наступний nonce, підписує `nc-tx-v2|from|to|value|nonce` і надсилає на `POST /api/v1/transactions`.

::: warning Задавайте ціну газу
За замовчуванням SDK ставить `gasPrice: 1` (для розгортання — 5). Нода відхиляє транзакцію з ціною нижче поточної базової комісії, а вона під навантаженням зростає. Спершу прочитайте її й передайте `gasPrice` явно:

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

### Підписані операції

Стейкінг, реєстрація імені та інші системні операції підписуються на системну ціль з nonce — позначкою часу в мілісекундах (див. [Гаманець → Підписані операції](/uk/learn/wallet#signed-operations)):

```js
const op = nc.signOp(wallet, OP_TARGETS.name, 0)   // { signature, public_key, nonce }
// додайте op до тіла запиту ендпоінта
```

`OP_TARGETS` містить `stake` (`neuro:system.stake`) і `name` (`neuro:system.name`).

### Відомі проблеми {#known-issues}

::: danger Відомі проблеми поточного SDK
- **Перекази з ненульовою сумою не проходять.** `sendTransaction` / `transfer` надсилають `value` рядком JSON; нода читає лише число й відхиляє запит з `Missing from/to/value`. Виклики й розгортання з сумою 0 це не зачіпає. Обхід — підписати й надіслати числове значення:
  ```js
  const nonce = await nc.nextNonce(wallet.address)
  const value = Number(toRaw('1.5'))               // uNRO числом
  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` повертає сирий рядок, якщо відповідь контракту — не чистий JSON. Відповіді NRC-20 закінчуються нульовим байтом, тож ви отримаєте рядок `'{"ok":true,"value":…}'`; приберіть `\u0000` і розберіть.
- `stake()` двічі переводить суму в uNRO перед підписом, тож нода відхиляє підпис. Доки не виправлено, складайте запит самі: `{ address, amount: toRaw(amount), ...nc.signOp(wallet, OP_TARGETS.stake, amount) }` на `/api/v1/staking/stake`.
- `staking(addr)` звертається до `/api/v1/staking/:addr`, якого gateway не обслуговує; використовуйте `GET /api/v1/staking/info/:address`.
- `contractCall` додає до JSON виклику поле `caller`. Контракти його ігнорують — ідентичність дає хост, — тож це нешкідливо.
:::

### Криптомодуль {#crypto-module}

Для підпису потрібен `neuro_wasm_crypto` — WASM-збірка гаманця (`neurochain-web/src/wasm/neuro_wasm_crypto.js` і `neuro_wasm_crypto_bg.wasm`). Він має експортувати `nc_keypair_from_words`, `nc_tx_message` і `nc_sign`. Якщо ваша сторінка віддає його з іншого місця, передайте завантажувач:

```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
  },
})
```

Без модуля читання працює, а кожен запис кидає помилку.

## Signer SDK {#signer-sdk}

Для dApp на іншому домені (біржа, гра), який не повинен бачити фразу користувача. Вебзастосунок NeuroChain користувача відкривається у спливному вікні, користувач підтверджує, і підпис повертається через `postMessage`.

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

const signer = new NeuroSigner({
  signerUrl: 'http://localhost:8080/signer',      // сторінка /signer вебгаманця
  allowedOrigins: ['http://localhost:8080'],
})

// Має виконуватися безпосередньо в обробнику кліку, інакше браузер заблокує вікно
button.onclick = async () => {
  const { address, publicKey } = await signer.connect()
  const { signature, nonce } = await signer.signOperation({
    to: 'neuro:system.dex',
    value: 1000000,          // uNRO
  })
}
```

| Метод | Повертає |
|-------|----------|
| `connect()` | `{ address, publicKey }` |
| `signOperation({ to, value, actor? })` | `{ signature, publicKey, nonce }` — підписана операція для `actor` (за замовчуванням — підключена адреса) |
| `isConnected()`, `getAddress()`, `getPublicKey()` | Стан підключення |
| `close()` | Закриває вікно і від'єднується |

Помилки мають `code`: `POPUP_BLOCKED`, `CONNECTION_TIMEOUT`, `SIGNATURE_REJECTED`, `INVALID_ORIGIN`, `NOT_CONNECTED`. При `POPUP_BLOCKED` покажіть користувачу пряме посилання на сторінку підпису.

Повідомлення приймаються лише з `allowedOrigins`; вкажіть там домен свого вебгаманця.
