# ABI & call data

> The NeuroChain contract call format — JSON call data with function and args, how a contract reads arguments, caller identity through the host, attached value, return data, errors and the standard NRC-20 interface.

Source: https://docs.nro.world/build/abi

A contract call is a transaction to a `.app` address whose `data` field carries the call. The canonical payload is UTF-8 JSON:

```json
{"function":"transfer","args":{"to":"neuro:bob.human","amount":"250"}}
```

In a transaction, `data` holds this JSON **as a string** (a hex-encoded payload is also accepted). The node hands the bytes to the contract's `call(input_ptr, input_len)` export.

## Rules

| Rule | Why |
|------|-----|
| **Use `function`** for the method name. | Older contracts also accepted `method`; new code should not. |
| **Identity comes from the host.** Call `get_caller()`; ignore any `caller` field in the JSON. | Anyone can write any `caller` into JSON. The host value is the verified signer of the transaction (or the calling contract, in a cross-contract call). |
| **Send compact JSON.** No spaces after `:` or `,` — `JSON.stringify` output. | Small `no_std` contracts read arguments with a byte scan for `"key":`; whitespace breaks it. |
| **Amounts as decimal strings** in whole tokens: `"amount":"250"`. | The node converts them (see below); strings avoid precision loss in JavaScript. |
| **Keep argument names unique** across `args`. | A byte-scanning contract finds the first `"key":` anywhere in the payload, so `args` may also be passed flattened at the top level. |

## Amounts are converted by the node

Before a call reaches the contract, the node rewrites one argument for you:

- **Contract calls:** `args.amount` given as a decimal string or number is treated as a **whole-token** amount and converted to the token's smallest unit using the contract's `decimals` (`"250"` at 6 decimals → `250000000`).
- **Deploys:** `init_args.total_supply` is converted the same way using `init_args.decimals`, which must be a JSON **number** (a string is read as 0 decimals).

Every other argument reaches the contract exactly as sent. A contract never sees the human amount.

## Attached value

The transaction's `value` (in uNRO) is credited to the contract's own account **after** the call succeeds. If the call traps or runs out of fuel, the value stays with the sender. There is currently no host function that tells the contract how much was attached; a contract that needs it can compare `get_balance()` before and after, or take the amount as an argument and verify it.

## Return data and errors

A contract returns bytes with `set_return(ptr, len)`. By convention:

```json
{"ok":"<value>"}            // success
{"error":"Unknown function"}  // failure reported by the contract
```

A contract that **traps** (`unreachable`, out of fuel, out-of-bounds memory access) fails the transaction: storage changes are rolled back, the value is not moved, and the fee and nonce are consumed. Status: `failed`.

Read the return value without a transaction:

```bash
curl -s -X POST "$GATEWAY/api/v1/contracts/neuro:<10 hex>.app/call" \
  -H 'Content-Type: application/json' \
  -d '{"function":"balance_of","args":{"address":"neuro:<15 hex>.human"},"dry_run":true}'
```

The response has `success`, `return_data`, `gas_used` and the events the call would emit. Write calls through this endpoint (`dry_run: false`) are refused when the node runs with `CHAIN_ENV=mainnet`; send a transaction instead.

## Constructor and `initialize`

- An `init` export, if present, runs once when the contract is deployed.
- If the deploy carries `init_args`, the contract is then called with `{"function":"initialize", …init_args}` — arguments flattened into the top level. See [Deploy contracts](./deploy#_4-what-every-validator-does).

## Standard interfaces

Interfaces are documented method sets, not extra WASM exports: a contract implements one by answering its function names.

### NRC-20 (fungible token)

Implemented by `neurochain/contracts/nrc20`. Inside the contract every amount is an integer in the token's smallest unit; send `amount` in whole tokens and the node converts it (see above).

| Function | Arguments | Notes |
|----------|-----------|-------|
| `initialize` | `name`, `symbol`, `decimals`, `total_supply` | Once; mints the supply to the caller, who becomes `owner` |
| `name`, `symbol`, `decimals`, `total_supply` | — | Read |
| `balance_of` | `address` | Read |
| `transfer` | `to`, `amount` | From the caller |
| `approve` | `spender`, `amount` | |
| `allowance` | `owner`, `spender` | Read |
| `transfer_from` | `from`, `to`, `amount` | Spends an allowance granted to the caller |
| `mint` | `to`, `amount` | Owner only |
| `burn` | `amount` | From the caller |
| `owner` | — | Read |

camelCase aliases (`balanceOf`, `totalSupply`, `transferFrom`) are accepted. Transfers emit a `Transfer` event.

Other interfaces used in the repository: NRC-721 style certificates (`ncert`) and DAO governance (`dao`, `gov_dao`); their ABI files sit next to the source (`*.abi.json`).

## Cross-contract calls

A contract can call another with the host function `call_contract`, up to **8 levels deep** (`MAX_CALL_DEPTH`). Inside the callee, `get_caller()` returns the calling contract's address. See [Cross-contract](/neurowasm/cross-contract).
