ABI와 호출 데이터
컨트랙트 호출은 .app 주소로 보내는 트랜잭션이며, 그 data 필드에 호출 내용이 담깁니다. 표준 페이로드는 UTF-8 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)으로 바이트를 반환합니다. 관례는 다음과 같습니다.
{"ok":"<value>"} // 성공
{"error":"Unknown function"} // 컨트랙트가 보고한 실패trap이 발생한 컨트랙트(unreachable, fuel 소진, 범위를 벗어난 메모리 접근)는 트랜잭션을 실패시킵니다. 스토리지 변경은 롤백되고, 금액은 이동하지 않으며, 수수료와 nonce는 소비됩니다. 상태: failed.
트랜잭션 없이 반환 값을 읽으려면:
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
initexport가 있으면 컨트랙트가 배포될 때 한 번 실행됩니다.- 배포에
init_args가 포함되어 있으면, 그다음 컨트랙트가{"function":"initialize", …init_args}로 호출됩니다 — 인자는 최상위 수준에 평탄화됩니다. 컨트랙트 배포를 참고하세요.
표준 인터페이스
인터페이스는 추가 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()는 호출한 컨트랙트의 주소를 반환합니다. 컨트랙트 간 호출을 참고하세요.