NEP: 25 Title: NeoContract ABI Author: Erik Zhang <[email protected]>, Roman Khimov <[email protected]> Type: Standard Status: Accepted Created: 2022-12-08 Replaces: 14
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.
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.
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.
Anywhere below "identifier" is an ASCII string that starts with a letter or underscore and contains letters, numbers or underscore.
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 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 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 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 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. |
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).
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.
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" } ] } } }