Skip to content

Latest commit

 

History

History
393 lines (336 loc) · 13.8 KB

nep-25.mediawiki

File metadata and controls

393 lines (336 loc) · 13.8 KB

  NEP: 25
  Title: NeoContract ABI
  Author: Erik Zhang <[email protected]>, Roman Khimov <[email protected]>
  Type: Standard
  Status: Accepted
  Created: 2022-12-08
  Replaces: 14

Table of Contents

Abstract

An Application Binary Interface (ABI) is the interface between two program modules, one of which is often a library and/or operating system and the other one is usually an application created by a regular programmer.

This NEP describes the ABI standards for Neo smart contracts.

Motivation

Neo smart contract system is designed to be mutually invocable between contracts. To achieve this, we need a mechanism for exposing the interface of smart contracts. With NeoContract ABI, developers can easily create programs to invoke smart contracts or write clients that automatically access contract functionalities.

This NEP is a compatible extension of the previous one, NEP-14. Some complex data types required more data for ABI to be useful for automatic SDK/wrapper code generation. For example, parameter of "Array" type could be a structure with three fields of "ByteArray", "Hash160" and "Integer" types or an array of "Integer" values. These cases couldn't be differentiated both for method parameters and return values with NEP-14, while this proposal fixes it.

Rationale

We assume the ABI is strongly typed, known at compilation time and static. No introspection mechanism will be provided. We assert that all contracts will have the interface definitions of any contracts they call available at compile-time.

This specification does not address contracts whose interface is dynamic or otherwise known only at run-time. Should these cases become important they can be adequately handled as facilities built within the Neo ecosystem.

Specification

Anywhere below "identifier" is an ASCII string that starts with a letter or underscore and contains letters, numbers or underscore.

Contract

The NeoContract ABI is defined by JSON format, which has the following basic structure, where some of the top-level objects can have any number of child objects:

{
  "methods": [],
  "events": [],
  "namedtypes": {}
}

methods is an array of Method objects which describe the details of each method in the contract.

events is an array of Event objects which describe the details of each event in the contract.

namedtypes is an object with each member having a name (a string consisting of one or more identifiers joined by dots) and a value of ExtendedType object.

Method

Method object has the following structure:

{
  "name": "transfer",
  "offset": 0,
  "safe": false,
  "parameters": [],
  "returntype": "Boolean",
  "extendedreturntype": {}
}

name is the name of the method, which can be any valid identifier.

offset is the offset of this method in the script.

safe indicates if the method has any side-effects (storage changes or notifications), methods marked this way can only read contract state (usually returning something as a result), modification attempts will result in execution failure.

parameters is an array of Parameter objects which describe the details of each parameter in the method.

returntype indicates the return type of the method. It can have any value of the ParameterType enumeration defined below.

extendedreturntype is an ExtendedType object used to provide additional type data if needed, this field can be omitted.

Event

Event object has the following structure:

{
  "name": "refund",
  "parameters": []
}

name is the name of the event, which can be any valid identifier.

parameters is an array of Parameter objects which describe the details of each parameter in the event.

Parameter

Parameter object has the following structure:

{
  "name": "from",
  "type": "Hash160",
  "extendedtype": {}
}

name is the name of the parameter, which can be any valid identifier.

type indicates the type of the parameter. It can have any value of the ParameterType enumeration defined below, except for Void.

extendedtype is an ExtendedType object used to provide additional type data if needed, this field can be omitted.

ParameterType

ParameterType enum has the following values:

name description
Signature A signature of a transaction or block which is generated by the user.
Boolean A boolean value can be either true or false.
Integer An arbitrarily large integer whose value in theory has no upper or lower bounds.
Hash160 A 160-bits integer.
Hash256 A 256-bits integer.
ByteArray A byte array.
PublicKey An ECC public key which is encoded with compressed mode.
String A string which is encoded in UTF-8.
Array An array of objects. The type of elements can be any value of ParameterType, unless some more specific type is specified with ExtendedType data.
Map A map of objects. The type of elements inside the key/value collection can be any value of ParameterType, unless some more specific types are specified with ExtendedType data.
InteropInterface An interface which is returned by interop services. More specific type can be specified with ExtendedType data.
Any Any means that the method will return a value of uncertain type.
Void Void means that the method has no return value. This value cannot be the type of a method parameter.

ExtendedType

Extended type data is an object can be used for extendedtype and extendedreturntype fields or named types (the object below is not a valid ExtendedType specification, rather it represents all possible fields).

{
  "type": "Integer",
  "namedtype": "name",
  "length": 32,
  "forbidnull": true,
  "interface": "IIterator",
  "key": "Integer",
  "value": {},
  "fields": []
}

type indicates the base type of the return value/parameter. It can have any value of the ParameterType enumeration defined above. This field is mandatory. When ExtendedType is used in extendedtype this field MUST be the same as outer (Parameter's) type, when used in extendedreturntype it MUST be the same as outer (Method's) returntype, when used in one of namedtypes it MUST be same as ExtendedType's type that refers to this named type.

namedtype is used to refer to one of the types defined in the namedtypes object of Contract, so namedtypes MUST contain a field named name . This field is only used for structures (ordered set of named values of diffent types), if used other fields MUST NOT be set, except for the type which MUST be an Array. Value string MUST start with a letter and can contain alphanumeric characters and dots. It MUST NOT be longer than 64 characters.

length is an optional field that can be used for Integer, ByteArray, String or Array types and MUST NOT be used for other types. When used it specifies the maximum possible byte length of an integer/byte array/string or number of array elements. Any of these lengths MUST NOT exceed NeoVM limitations that are relevant for the current version of it. Length 0 means "unlimited".

forbidnull is an optional field that can be used for Hash160, Hash256, ByteArray, String, Array, Map or InteropInterface types and MUST NOT be used for other types. It allows to specify that the method accepts or event emits only non-null values for this field. The default (if not specified) is "false", meaning that null can be used.

interface is only used in conjuction with the InteropInterface type and MUST NOT be used for other types, when used it specifies which interop interface is used. The only valid defined value for it is "IIterator" which means an iterator object. When used it MUST be accompanied with the value object that specifies the type of each individual element returned from the iterator.

key is only used along with the Map type (MUST NOT be used for other types) and can have Signature, Boolean, Integer, Hash160, Hash256, ByteArray, PublicKey or String value, that is all the basic types that can be used as a map key.

value is used for Array, InteropInterface and Map types (type field) and MUST NOT be used with other base types. When used for Array it contains the type of an individual element of an array (ordered set of values of one type). If used for InteropInterface it contains the type of an individual iterator's value. If used for Map it contains map value type. If this field is used, fields MUST NOT be present.

fields is used for Array type and when used it means that the type is a structure (ordered set of named values of diffent types), which has its fields defined directly here (unlike namedtype which is just a reference to namedtypes). It's an array with each member being a Parameter. fields MUST NOT be used in method parameter or return value definitions (these MUST use namedtype referring to a valid type specified in the namedtypes object).

Backwards Compatibility

For the field extension this NEP is completely backwards-compatible with NEP-14 when new fields are ignored, old fields and their meaning remain intact.

This NEP has more strict requirements for identifiers, but these are mostly clarifying what was meant implicitly earlier and practically it's compatible with the old definition.

Test Cases

This is an example of the method definition that takes structure, array and map parameters, returning an iterator with structured element type.

{
   "methods" : [
      {
         "returntype" : "InteropInterface",
         "offset" : 0,
         "safe" : true,
         "extendedreturntype" : {
            "value" : {
               "type" : "Array",
               "namedtype" : "package.Structure"
            },
            "type" : "InteropInterface",
            "forbidnull" : true,
            "interface" : "IIterator"
         },
         "name" : "m",
         "parameters" : [
            {
               "name" : "structParam",
               "type" : "Array",
               "extendedtype" : {
                  "type" : "Array",
                  "namedtype" : "local.Structure"
               }
            },
            {
               "extendedtype" : {
                  "value" : {
                     "type" : "Hash160"
                  },
                  "type" : "Array"
               },
               "name" : "arrayOfHash160",
               "type" : "Array"
            },
            {
               "name" : "mapParam",
               "type" : "Map",
               "extendedtype" : {
                  "value" : {
                     "type" : "Integer"
                  },
                  "type" : "Map",
                  "key" : "Hash160"
               }
            }
         ]
      }
   ],
   "events" : [],
   "namedtypes" : {
      "local.Structure" : {
         "fields" : [
            {
               "name" : "IntField",
               "type" : "Integer"
            },
            {
               "name" : "Hash256Field",
               "type" : "Hash256"
            },
            {
               "name" : "ArrayOfArraysOfBooleans",
               "type" : "Array",
               "extendedtype" : {
                  "type" : "Array",
                  "value" : {
                     "extendedtype" : {
                        "value" : {
                           "type" : "Boolean"
                        },
                        "type" : "Array"
                     },
                     "type" : "Array"
                  }
               }
            },
            {
               "name" : "StructureField",
               "type" : "Array",
               "extendedtype" : {
                  "type" : "Array",
                  "namedtype" : "package.Structure"
               }
            }
         ],
         "type" : "Array"
      },
      "package.Structure" : {
         "type" : "Array",
         "fields" : [
            {
               "name" : "MapHash160ToArrayOfIntegers",
               "type" : "Map",
               "extendedtype" : {
                  "type" : "Map",
                  "key" : "Hash160",
                  "value" : {
                     "extendedtype" : {
                        "value" : {
                           "type" : "Integer"
                        },
                        "type" : "Array"
                     },
                     "type" : "Array"
                  }
               }
            },
            {
               "name" : "Int32Field",
               "type" : "Integer",
               "extendedtype" : {
                  "type" : "Integer",
                  "length" : 4
               }
            },
            {
               "name" : "StringField",
               "type" : "String"
            },
            {
               "name" : "ByteArrayField",
               "type" : "ByteArray"
            }
         ]
      }
   }
}