# ABI와 호출 데이터

> NeuroChain 컨트랙트 호출 형식 — function과 args로 구성된 JSON 호출 데이터, 컨트랙트가 인자를 읽는 방법, 호스트를 통한 호출자 신원, 첨부 금액, 반환 데이터, 오류, 표준 NRC-20 인터페이스.

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

컨트랙트 호출은 `.app` 주소로 보내는 트랜잭션이며, 그 `data` 필드에 호출 내용이 담깁니다. 표준 페이로드는 UTF-8 JSON입니다.

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

트랜잭션에서 `data`는 이 JSON을 **문자열로** 담습니다(hex로 인코딩된 페이로드도 허용됩니다). 노드는 이 바이트를 컨트랙트의 `call(input_ptr, input_len)` export에 전달합니다.

## 규칙

| 규칙 | 이유 |
|------|------|
| 메서드 이름에는 **`function`을 사용하세요.** | 예전 컨트랙트는 `method`도 받았지만, 새 코드에서는 쓰지 않아야 합니다. |
| **신원은 호스트에서 옵니다.** `get_caller()`를 호출하고, JSON의 `caller` 필드는 무시하세요. | 누구나 JSON에 아무 `caller`나 쓸 수 있습니다. 호스트 값은 트랜잭션의 검증된 서명자입니다(컨트랙트 간 호출에서는 호출한 컨트랙트). |
| **압축된 JSON을 보내세요.** `:`와 `,` 뒤에 공백을 넣지 마세요 — `JSON.stringify` 출력 그대로. | 작은 `no_std` 컨트랙트는 `"key":`를 바이트 단위로 탐색해 인자를 읽으며, 공백이 있으면 실패합니다. |
| **금액은 10진수 문자열로**, 토큰 전체 단위로: `"amount":"250"`. | 노드가 변환합니다(아래 참고). 문자열을 쓰면 JavaScript에서 정밀도 손실이 없습니다. |
| `args` 전체에서 **인자 이름이 겹치지 않게 하세요.** | 바이트 탐색 컨트랙트는 페이로드 어디서든 처음 나오는 `"key":`를 찾으므로, `args`는 최상위 수준에 평탄화해 전달될 수도 있습니다. |

## 금액은 노드가 변환합니다

호출이 컨트랙트에 도달하기 전에 노드가 인자 하나를 대신 다시 씁니다.

- **컨트랙트 호출:** 10진수 문자열이나 숫자로 주어진 `args.amount`는 **토큰 전체 단위** 금액으로 간주되어, 컨트랙트의 `decimals`를 이용해 토큰의 최소 단위로 변환됩니다(소수 자릿수 6에서 `"250"` → `250000000`).
- **배포:** `init_args.total_supply`도 `init_args.decimals`를 이용해 같은 방식으로 변환되며, `decimals`는 JSON **숫자**여야 합니다(문자열은 소수 자릿수 0으로 읽힙니다).

그 밖의 모든 인자는 보낸 그대로 컨트랙트에 전달됩니다. 컨트랙트는 사람이 읽는 금액을 절대 보지 않습니다.

## 첨부 금액

트랜잭션의 `value`(uNRO)는 호출이 성공한 **후에** 컨트랙트 자체 계정에 입금됩니다. 호출이 trap되거나 fuel이 소진되면 금액은 보낸 사람에게 남습니다. 현재는 첨부된 금액을 컨트랙트에 알려 주는 host 함수가 없습니다. 이 값이 필요한 컨트랙트는 호출 전후의 `get_balance()`를 비교하거나, 금액을 인자로 받아 검증할 수 있습니다.

## 반환 데이터와 오류

컨트랙트는 `set_return(ptr, len)`으로 바이트를 반환합니다. 관례는 다음과 같습니다.

```json
{"ok":"<value>"}            // 성공
{"error":"Unknown function"}  // 컨트랙트가 보고한 실패
```

**trap**이 발생한 컨트랙트(`unreachable`, fuel 소진, 범위를 벗어난 메모리 접근)는 트랜잭션을 실패시킵니다. 스토리지 변경은 롤백되고, 금액은 이동하지 않으며, 수수료와 nonce는 소비됩니다. 상태: `failed`.

트랜잭션 없이 반환 값을 읽으려면:

```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}'
```

응답에는 `success`, `return_data`, `gas_used`와 호출이 발생시킬 이벤트가 담깁니다. 노드가 `CHAIN_ENV=mainnet`으로 실행 중이면 이 엔드포인트를 통한 쓰기 호출(`dry_run: false`)은 거부됩니다. 대신 트랜잭션을 보내세요.

## 생성자와 `initialize`

- `init` export가 있으면 컨트랙트가 배포될 때 한 번 실행됩니다.
- 배포에 `init_args`가 포함되어 있으면, 그다음 컨트랙트가 `{"function":"initialize", …init_args}`로 호출됩니다 — 인자는 최상위 수준에 평탄화됩니다. [컨트랙트 배포](./deploy#_4-what-every-validator-does)를 참고하세요.

## 표준 인터페이스

인터페이스는 추가 WASM export가 아니라 문서화된 메서드 집합입니다. 컨트랙트는 해당 함수 이름에 응답함으로써 인터페이스를 구현합니다.

### NRC-20 (대체 가능 토큰)

`neurochain/contracts/nrc20`에 구현되어 있습니다. 컨트랙트 내부에서 모든 금액은 토큰 최소 단위의 정수입니다. `amount`는 토큰 전체 단위로 보내면 노드가 변환합니다(위 참고).

| 함수 | 인자 | 비고 |
|------|------|------|
| `initialize` | `name`, `symbol`, `decimals`, `total_supply` | 한 번만; 공급량을 호출자에게 발행하고, 호출자는 `owner`가 됨 |
| `name`, `symbol`, `decimals`, `total_supply` | — | 조회 |
| `balance_of` | `address` | 조회 |
| `transfer` | `to`, `amount` | 호출자로부터 |
| `approve` | `spender`, `amount` | |
| `allowance` | `owner`, `spender` | 조회 |
| `transfer_from` | `from`, `to`, `amount` | 호출자에게 부여된 allowance를 사용 |
| `mint` | `to`, `amount` | owner 전용 |
| `burn` | `amount` | 호출자로부터 |
| `owner` | — | 조회 |

camelCase 별칭(`balanceOf`, `totalSupply`, `transferFrom`)도 허용됩니다. 송금 시 `Transfer` 이벤트가 발생합니다.

저장소에서 사용하는 다른 인터페이스: NRC-721 방식의 인증서(`ncert`)와 DAO 거버넌스(`dao`, `gov_dao`). 해당 ABI 파일은 소스 옆에 있습니다(`*.abi.json`).

## 컨트랙트 간 호출

컨트랙트는 host 함수 `call_contract`로 다른 컨트랙트를 호출할 수 있으며, 최대 **8단계 깊이**(`MAX_CALL_DEPTH`)까지 가능합니다. 호출된 컨트랙트 안에서 `get_caller()`는 호출한 컨트랙트의 주소를 반환합니다. [컨트랙트 간 호출](/ko/neurowasm/cross-contract)을 참고하세요.
