Skip to content

Contract ABI Specification

The Application Binary Interface (ABI) is the standard way to interact with contracts in the ecosystem. It describes the data structures, method signatures, and events exposed by the smart contract to the outside world.

💡 NeoVM Difference: JSON Manifest vs Binary Encoding

Ethereum relies on a tightly-packed binary encoding scheme and 4-byte keccak256 function selectors. Contracts parse this binary payload internally.

Neo uses a structured JSON Manifest ABI and dispatches methods natively by their string names. The NeoVM natively understands arguments like Integer, Hash160, and ByteArray, meaning the contract does not need to manually decode a packed byte payload.

Basic Design

When you compile a contract, Neo DevPack for Solidity generates a .manifest.json file. The abi object inside this manifest dictates exactly how clients and other contracts interact with your code.

Method Dispatch

In EVM, transfer(address,uint256) hashes to the selector 0xa9059cbb.

On Neo, the function name itself ("transfer") is the dispatch mechanism. The NeoVM executes a System.Contract.Call syscall, providing the target contract hash and the exact string "transfer".

Overload Collisions: Because Neo dispatches by name, overloading functions with the same name but different parameters will cause collisions in the manifest unless handled carefully.

solidity
// ⚠️ Both produce "transfer" in Neo manifest — collision
function transfer(address to, uint256 amount) public { }
function transfer(address to, uint256 amount, bytes calldata data) public { }

// ✅ Distinct names — no collision
function transfer(address to, uint256 amount) public { }
function transferWithData(address to, uint256 amount, bytes calldata data) public { }

When a collision occurs, the neo-devpack-solidity compiler retains one canonical method in the ABI and mangles the names of the others, emitting a warning. Downstream tools calling the contract must use the mangled name if they intend to hit the overloaded variant.

Argument Encoding and Types

Because NeoVM execution relies on strongly-typed StackItems rather than a raw byte array, the ABI maps high-level Solidity types into one of the fundamental Neo ABI types.

Solidity TypeNeo ABI TypeNeoVM Representation
boolBooleanNative boolean stack item.
int<M> / uint<M>IntegerArbitrary-precision BigInteger.
addressHash16020-byte ByteArray.
bytes<M>ByteArrayM-byte ByteArray.
bytes32Hash25632-byte ByteArray.
bytesByteArrayDynamic ByteArray.
stringStringUTF-8 encoded ByteString.
T[] (arrays)ArrayOrdered collection of StackItems.
structArrayOrdered collection of StackItems matching struct field order.
mappingN/AMappings cannot be passed as arguments or returned.

The Any Type

Neo DevPack for Solidity introduces a special type, Any, which directly maps to the Neo ABI Any type. This represents a completely unconstrained StackItem. It is strictly used for Neo-native interface compliance, such as the data parameter in NEP-17's transfer method.

Function Selector and Argument Encoding

When interacting with the contract via Neo-Express or an SDK (like neon-js or mamba), you must pass arguments matching the Neo ABI Type, not the raw EVM types.

For example, when calling transfer(address,uint256), the SDK handles packaging the arguments as an Integer and a Hash160. The NeoVM pushes these items onto the execution stack before jumping to your contract's entry point.

Events

Solidity events map directly to Neo's Runtime.Notify syscall. The ABI includes an events array that lists all declared events.

json
"events": [
  {
    "name": "Transfer",
    "parameters": [
      { "name": "from", "type": "Hash160" },
      { "name": "to", "type": "Hash160" },
      { "name": "amount", "type": "Integer" }
    ]
  }
]

Unlike Ethereum, Neo does not use "topics" for indexed parameters. All event parameters, whether marked indexed or not, are appended to the notification's state array sequentially.

The safe Flag

Neo's ABI includes a safe boolean for every method. This indicates whether a method is read-only.

  • view and pure functions in Solidity are compiled with "safe": true.
  • All other functions are compiled with "safe": false.

Methods marked as safe can be called via RPC test invocations without requiring a transaction signature or incurring GAS fees. This is identical in purpose to EVM's eth_call.

MIT Licensed