ABI 与调用数据
合约调用是一笔发往 .app 地址的交易,其 data 字段携带调用内容。规范的载荷格式是 UTF-8 JSON:
{"function":"transfer","args":{"to":"neuro:bob.human","amount":"250"}}在交易中,data 以字符串形式保存这段 JSON(也接受十六进制编码的载荷)。节点把这些字节交给合约的 call(input_ptr, input_len) 导出函数。
规则
| 规则 | 原因 |
|---|---|
方法名放在 function 中。 | 旧合约也接受 method;新代码不应再使用。 |
身份来自宿主。 调用 get_caller();忽略 JSON 中的任何 caller 字段。 | 任何人都可以往 JSON 里写任意 caller。宿主给出的值是经过验证的交易签名者(在跨合约调用中则是发起调用的合约)。 |
发送紧凑 JSON。 : 和 , 之后不留空格——即 JSON.stringify 的输出。 | 小型 no_std 合约通过逐字节扫描 "key": 来读取参数;空白会使其失效。 |
金额用十进制字符串表示,单位为整枚代币:"amount":"250"。 | 节点会进行换算(见下文);字符串可避免 JavaScript 中的精度损失。 |
args 中的参数名保持唯一。 | 逐字节扫描的合约会在载荷中任意位置找到第一个 "key":,因此 args 也可以平铺在顶层传入。 |
金额由节点换算
在调用到达合约之前,节点会替你改写一个参数:
- 合约调用: 以十进制字符串或数字给出的
args.amount被视为整枚代币金额,并按合约的decimals换算为代币的最小单位(6 位小数时"250"→250000000)。 - 部署:
init_args.total_supply以同样方式按init_args.decimals换算,后者必须是 JSON 数字(字符串会被当作 0 位小数)。
其他所有参数都按原样到达合约。合约永远看不到人类可读的金额。
附带金额
交易的 value(单位 uNRO)在调用成功之后记入合约自己的账户。如果调用 trap 或耗尽 fuel,金额留在发送方。目前没有宿主函数能告诉合约附带了多少金额;需要该信息的合约可以比较调用前后的 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
- 如果存在
init导出,它会在合约部署时运行一次。 - 如果部署携带
init_args,随后会以{"function":"initialize", …init_args}调用合约——参数平铺在顶层。参见部署合约。
标准接口
接口是有文档的方法集合,而不是额外的 WASM 导出:合约只要响应这些函数名,就实现了该接口。
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 | 消耗授予调用者的额度 |
mint | to、amount | 仅限 owner |
burn | amount | 从调用者扣除 |
owner | — | 读取 |
也接受 camelCase 别名(balanceOf、totalSupply、transferFrom)。转账会发出 Transfer 事件。
仓库中使用的其他接口:NRC-721 风格的证书(ncert)和 DAO 治理(dao、gov_dao);它们的 ABI 文件与源码放在一起(*.abi.json)。
跨合约调用
合约可以通过宿主函数 call_contract 调用另一个合约,最多嵌套 8 层(MAX_CALL_DEPTH)。在被调用方内部,get_caller() 返回发起调用的合约地址。参见跨合约调用。