Skip to content

Native Contracts

Neo N3 ships eleven native contracts that are deployed at genesis and provide core platform functionality — token management, governance, cryptography, blockchain queries, and more. Unlike user-deployed contracts, native contracts have deterministic script hashes that are identical across all Neo N3 networks (mainnet, testnet, private chains). The neo-solidity compiler and devpack expose these contracts through the NativeCalls library and Syscalls wrappers, lowering calls to either System.Contract.Call syscalls or optimized CALLT method token instructions.


Overview

NameScript HashPurposeDevpack Wrapper
NEO0xef4073a0f2b305a38ec4050e4d3d28bc40ea63f5Governance token, voting, validatorsNativeCalls.neo*
GAS0xd2a4cff31913016155e38e474a2c06d08be276cfUtility/fee tokenNativeCalls.gas*
ContractManagement0xfffdc93764dbaddd97c48f252a53ea4643faa3fdDeploy, update, destroy contractsNativeCalls.deployContract / updateContract / destroyContract
Policy0xcc5e4edd9f5f8dba8bb65734541df7a1c081c67bNetwork policy parametersNativeCalls.getFeePerByte / getExecFeeFactor / etc.
Oracle0xfe924b7cfe89ddd271abaf7210a80a7e11178758Off-chain data requestsNativeCalls.requestOracleData / OracleService.sol
RoleManagement0x49cf4e5378ffcd4dec034fd98a174c5491e395e2Node role designationNativeCalls.designateAsRole / getDesignatedByRole
Ledger0xda65b600f7124ce6c79950c1772a36403104f2beBlock and transaction queriesNativeCalls.currentIndex / getBlock / getTransaction
CryptoLib0x726cb6e0cd8628a1350a611384688911ab75f51bCryptographic operationsSyscalls.sha256 / neoKeccak256 / verifyWithECDsa
StdLib0xacce6fd80d44e1796aa0c2c625e9e4e0ce39efc0Serialization and encoding utilitiesSyscalls.serialize / base64Encode / itoa / etc.
Notary0xc1e14f19c3e60d0b9244d06dd7ba9b113135ec3bNotary service for multi-party transactionsNativeCalls.notary*
Treasury0x156326f25b1b5d839a4d326aeaa75383c9563ac1Treasury managementNativeCalls.treasury*

INFO

Script hashes shown above are big-endian hex (the format used by Neo RPC and block explorers). The devpack constants in NativeCalls.sol use the same format as Solidity address literals.


NEO Token Contract

The NEO token is the governance token of the Neo N3 network. It is indivisible (0 decimals), has a fixed supply of 100,000,000, and is used for voting, validator election, and GAS generation.

Methods

MethodSignatureReturnSafeDescription
namename()stringReturns "NEO".
symbolsymbol()stringReturns "NEO".
decimalsdecimals()uint8Returns 0 (indivisible).
totalSupplytotalSupply()uint256Returns 100000000.
balanceOfbalanceOf(address)uint256NEO balance of account.
transfertransfer(address,address,uint256,bytes)boolTransfer NEO tokens. Requires witness of from.
votevote(address,bytes)boolVote for a validator candidate. Pass null pubkey to cancel.
getCandidatesgetCandidates()NeoCandidate[]First 256 registered candidates with vote counts.
getAllCandidatesgetAllCandidates()IteratorIterator over all registered candidates.
getCandidateVotegetCandidateVote(bytes)int256Vote count for a public key. Returns -1 if not found.
registerCandidateregisterCandidate(bytes)boolRegister a public key as validator candidate.
unregisterCandidateunregisterCandidate(bytes)boolRemove candidate registration.
getCommitteegetCommittee()bytes[]Current committee member public keys.
getNextBlockValidatorsgetNextBlockValidators()address[]Validators for the next block.
getGasPerBlockgetGasPerBlock()uint256GAS generated per block.
setGasPerBlocksetGasPerBlock(uint256)voidSet GAS per block (committee only).
getRegisterPricegetRegisterPrice()uint256GAS cost to register as candidate.
setRegisterPricesetRegisterPrice(uint256)voidSet registration price (committee only).
getAccountStategetAccountState(address)AccountStateBalance, vote target, and last GAS claim height.
unclaimedGasunclaimedGas(address,uint256)uint256Unclaimed GAS for account at block height.

Code Example

solidity
import "devpack/contracts/NativeCalls.sol";

contract Governance {
    function getMyNeoBalance() public view returns (uint256) {
        return NativeCalls.neoBalanceOf(address(this));
    }

    function voteForCandidate(bytes memory publicKey) public {
        require(Runtime.checkWitness(msg.sender), "unauthorized");
        NativeCalls.vote(msg.sender, publicKey);
    }

    function claimableGas(address account) public view returns (uint256) {
        uint256 height = NativeCalls.currentIndex();
        return NativeCalls.unclaimedGas(account, height);
    }
}

GAS Token Contract

GAS is the utility token used to pay transaction fees on Neo N3. It has 8 decimals and is generated by holding NEO.

Methods

MethodSignatureReturnSafeDescription
namename()stringReturns "GAS".
symbolsymbol()stringReturns "GAS".
decimalsdecimals()uint8Returns 8.
totalSupplytotalSupply()uint256Current GAS supply (increases over time).
balanceOfbalanceOf(address)uint256GAS balance of account (in 10^-8 units).
transfertransfer(address,address,uint256,bytes)boolTransfer GAS. Requires witness of from.

Code Example

solidity
import "devpack/contracts/NativeCalls.sol";

contract Treasury {
    function getGasBalance() public view returns (uint256) {
        return NativeCalls.gasBalanceOf(address(this));
    }

    function withdrawGas(address to, uint256 amount) public {
        require(Runtime.checkWitness(msg.sender), "unauthorized");
        bool success = NativeCalls.gasTransfer(address(this), to, amount, "");
        require(success, "transfer failed");
    }
}

TIP

GAS uses 10^8 decimals, not 10^18 like Ether. When porting EVM contracts, adjust your unit constants: 0.1 GAS = 10_000_000 (not 10^17).


ContractManagement

Manages the lifecycle of all deployed contracts on Neo N3 — deployment, upgrades, destruction, and introspection.

Methods

MethodSignatureReturnSafeDescription
deploydeploy(bytes,bytes)ContractStateDeploy a new contract from NEF + manifest.
deploydeploy(bytes,bytes,bytes)ContractStateDeploy with initialization data passed to _deploy.
updateupdate(bytes,bytes)voidUpdate calling contract's NEF and/or manifest.
updateupdate(bytes,bytes,bytes)voidUpdate with migration data passed to _deploy.
destroydestroy()voidPermanently destroy the calling contract and its storage.
getContractgetContract(address)ContractStateGet contract state by script hash.
getContractByIdgetContractById(int256)ContractStateGet contract state by numeric ID.
getMinimumDeploymentFeegetMinimumDeploymentFee()uint256Minimum GAS required to deploy a contract.
setMinimumDeploymentFeesetMinimumDeploymentFee(uint256)voidSet minimum deployment fee (committee only).
hasMethodhasMethod(address,string,uint8)boolCheck if a contract exposes a specific method.
listContractslistContracts()IteratorIterator over all deployed contracts.

Code Example

solidity
import "devpack/contracts/NativeCalls.sol";

contract Upgradeable {
    address private _owner;

    constructor() {
        _owner = msg.sender;
    }

    /// @dev Upgrade this contract in-place
    function upgrade(bytes memory newNef, bytes memory newManifest) public {
        require(Runtime.checkWitness(_owner), "not owner");
        NativeCalls.updateContract(newNef, newManifest);
        // After update, the new code executes immediately
    }

    /// @dev Permanently destroy this contract
    function kill() public {
        require(Runtime.checkWitness(_owner), "not owner");
        NativeCalls.destroyContract();
    }

    /// @dev Check if another contract exists
    function contractExists(address target) public view returns (bool) {
        return NativeCalls.hasMethod(target, "name", 0);
    }
}

WARNING

destroy() is permanent and irreversible. All contract storage is deleted. There is no refund mechanism like EVM's deprecated selfdestruct. Always gate destruction behind strict authorization.


Policy Contract

Controls network-wide policy parameters. Most setter methods require committee multi-signature authorization.

Methods

MethodSignatureReturnSafeDescription
getFeePerBytegetFeePerByte()uint256Network fee per transaction byte (in GAS fractions).
setFeePerBytesetFeePerByte(uint256)voidSet fee per byte (committee only).
getExecFeeFactorgetExecFeeFactor()uint32Execution fee multiplier for opcode costs.
setExecFeeFactorsetExecFeeFactor(uint32)voidSet execution fee factor (committee only).
getStoragePricegetStoragePrice()uint256GAS cost per byte of contract storage.
setStoragePricesetStoragePrice(uint256)voidSet storage price (committee only).
isBlockedisBlocked(address)boolCheck if an account is blocked from transacting.
blockAccountblockAccount(address)voidBlock an account (committee only).
unblockAccountunblockAccount(address)voidUnblock an account (committee only).

Code Example

solidity
import "devpack/contracts/NativeCalls.sol";

contract FeeEstimator {
    function estimateStorageCost(uint256 bytesCount) public view returns (uint256) {
        uint256 pricePerByte = NativeCalls.getStoragePrice();
        return pricePerByte * bytesCount;
    }

    function getNetworkFeeParams() public view returns (uint256 feePerByte, uint32 execFactor) {
        feePerByte = NativeCalls.getFeePerByte();
        execFactor = NativeCalls.getExecFeeFactor();
    }

    function requireNotBlocked(address account) internal view {
        require(!NativeCalls.isBlocked(account), "account is blocked");
    }
}

Oracle Contract

Provides off-chain data access through a request/callback pattern. Oracle nodes fetch external data and deliver results back to the requesting contract.

Methods

MethodSignatureReturnSafeDescription
requestrequest(string,string,string,bytes,uint256)voidSubmit an oracle data request.
getPricegetPrice()uint256Base GAS cost per oracle request.
setPricesetPrice(uint256)voidSet oracle price (committee only).
finishfinish()voidComplete an oracle response (oracle nodes only).
verifyverify()boolVerify an oracle response transaction.

Callback Pattern

The Oracle native contract uses an asynchronous request/callback model:

  1. Your contract calls Oracle.request(url, filter, callbackMethod, userData, gasForResponse).
  2. Oracle nodes fetch the URL, apply the JSONPath filter, and invoke callbackMethod on your contract.
  3. The callback receives (string url, bytes userData, int code, bytes result).
solidity
import "devpack/contracts/NativeCalls.sol";

contract PriceOracle {
    uint256 public lastPrice;

    function requestPrice() public {
        NativeCalls.requestOracleData(
            "https://api.example.com/price",  // URL
            "$.neo.usd",                       // JSONPath filter
            "onPriceResponse",                 // callback method name
            "",                                // user data
            100_000_000                        // 1 GAS for response
        );
    }

    /// @dev Called by the Oracle native contract
    function onPriceResponse(
        string calldata url,
        bytes calldata userData,
        uint256 code,
        bytes calldata result
    ) external {
        require(msg.sender == NativeCalls.ORACLE_CONTRACT, "unauthorized");
        if (code == 0) { // Success
            lastPrice = abi.decode(result, (uint256));
        }
    }
}

TIP

The devpack includes OracleService.sol — a convenience wrapper that manages request IDs, stores responses, and forwards callbacks through a fixed onOracleResponse method name. This avoids wildcard manifest permissions that a dynamic callback name would require.

WARNING

Oracle requests are not free. Each request costs at least Oracle.getPrice() GAS plus the gasForResponse budget you specify. The callback method name becomes a manifest permission entry — use a fixed name to avoid wildcard permissions.


RoleManagement

Manages designated node roles in the Neo N3 network. Used by committee members to assign oracle nodes, state validators, and other infrastructure roles.

Methods

MethodSignatureReturnSafeDescription
designateAsRoledesignateAsRole(bytes1,bytes[])voidAssign public keys to a role (committee only).
getDesignatedByRolegetDesignatedByRole(bytes1,uint256)bytes[]Get public keys designated for a role at a block index.

Role Types

ValueRoleDescription
0x04StateValidatorState root validation nodes.
0x08OracleOracle service nodes.
0x10NeoFSAlphabetNodeNeoFS alphabet nodes.
0x20P2PNotaryP2P notary service nodes.

Ledger Contract

Provides read-only access to blockchain data — blocks, transactions, and their metadata.

Methods

MethodSignatureReturnSafeDescription
currentIndexcurrentIndex()uint256Current block height. Maps from block.number.
currentHashcurrentHash()bytes32Hash of the current block.
getBlockgetBlock(uint256)BlockGet block by index.
getBlockgetBlock(bytes32)BlockGet block by hash.
getTransactiongetTransaction(bytes32)TransactionGet transaction by hash.
getTransactionHeightgetTransactionHeight(bytes32)int256Block height containing the transaction. Returns -1 if not found.
getTransactionFromBlockgetTransactionFromBlock(uint256,uint256)TransactionGet transaction by block index and tx index.
getTransactionSignersgetTransactionSigners(bytes32)Signer[]Get signers of a transaction.
getTransactionVMStategetTransactionVMState(bytes32)uint8VM execution state of a transaction (HALT, FAULT, etc.).

INFO

The compiler auto-maps block.number to Ledger.currentIndex() and blockhash(n) to Ledger.getBlock(n).hash. See EVM to NeoVM Mapping for the full list of auto-mapped block context values.


CryptoLib

Provides cryptographic hash functions, signature verification, and BLS12-381 curve operations. CryptoLib methods are exposed through Syscalls.sol rather than NativeCalls.sol.

Methods

MethodSignatureReturnSafeDescription
sha256sha256(bytes)bytes32SHA-256 hash.
ripemd160ripemd160(bytes)bytes20RIPEMD-160 hash.
keccak256keccak256(bytes)bytes32Keccak-256 hash (added at Cockatrice hardfork).
murmur32murmur32(bytes,uint32)bytes4Murmur3 32-bit hash with seed.
verifyWithECDsaverifyWithECDsa(bytes32,bytes,bytes,uint8)boolECDSA signature verification.
bls12381Serializebls12381Serialize(bytes)bytesSerialize a BLS12-381 point.
bls12381Deserializebls12381Deserialize(bytes)bytesDeserialize a BLS12-381 point.
bls12381Equalbls12381Equal(bytes,bytes)boolCompare two BLS12-381 points.
bls12381Addbls12381Add(bytes,bytes)bytesAdd two BLS12-381 points.
bls12381Mulbls12381Mul(bytes,bytes,bool)bytesMultiply BLS12-381 point by scalar.
bls12381Pairingbls12381Pairing(bytes,bytes)bytesBLS12-381 pairing check.

Curve Support

The verifyWithECDsa method accepts a curve parameter that selects both the elliptic curve and the hash algorithm:

ValueConstantCurveHashUse Case
22SECP256K1_SHA256secp256k1SHA-256Bitcoin-compatible signatures
23SECP256R1_SHA256secp256r1SHA-256Neo-native signatures
122SECP256K1_KECCAK256secp256k1Keccak-256Ethereum-compatible signatures
123SECP256R1_KECCAK256secp256r1Keccak-256Neo + Keccak signatures

Code Example

solidity
import "devpack/contracts/Syscalls.sol";

contract SignatureVerifier {
    function verifyEthSignature(
        bytes32 messageHash,
        bytes memory publicKey,
        bytes memory signature
    ) public view returns (bool) {
        // secp256k1 + Keccak-256 for Ethereum compatibility
        return Syscalls.verifyWithECDsa(
            messageHash, publicKey, signature,
            Syscalls.SECP256K1_KECCAK256
        );
    }

    function verifyNeoSignature(
        bytes32 messageHash,
        bytes memory publicKey,
        bytes memory signature
    ) public view returns (bool) {
        // secp256r1 + SHA-256 for Neo-native signatures
        return Syscalls.verifyWithECDsa(
            messageHash, publicKey, signature,
            Syscalls.SECP256R1_SHA256
        );
    }

    function hashData(bytes memory data) public view returns (bytes32) {
        return Syscalls.sha256(data);
    }
}

INFO

Solidity's built-in keccak256() and sha256() are automatically lowered to CryptoLib.keccak256 and CryptoLib.sha256 native contract calls by the compiler. The Syscalls.* wrappers are provided for explicit usage when you want to call through the devpack namespace directly.


StdLib

Provides serialization, encoding, and string manipulation utilities. StdLib methods are exposed through Syscalls.sol.

Methods

MethodSignatureReturnSafeDescription
serializeserialize(bytes)bytesSerialize a NeoVM stack item to bytes.
deserializedeserialize(bytes)bytesDeserialize bytes back to a stack item.
jsonSerializejsonSerialize(bytes)bytesSerialize a stack item to JSON.
jsonDeserializejsonDeserialize(bytes)bytesDeserialize JSON to a stack item.
base64Encodebase64Encode(bytes)stringBase64 encode.
base64Decodebase64Decode(string)bytesBase64 decode.
base58Encodebase58Encode(bytes)stringBase58 encode.
base58Decodebase58Decode(string)bytesBase58 decode.
itoaitoa(int256,uint8)stringInteger to string (base 10 or 16).
atoiatoi(string,uint8)int256String to integer (base 10 or 16).
memoryComparememoryCompare(bytes,bytes)int256Lexicographic byte comparison. Returns -1, 0, or 1.
memorySearchmemorySearch(bytes,bytes,int256,bool)int256Search for a byte pattern. Returns index or -1.
stringSplitstringSplit(string,string,bool)string[]Split string by separator.
strLenstrLen(string)uint256String length in text elements (not bytes).

Code Example

solidity
import "devpack/contracts/Syscalls.sol";

contract DataEncoder {
    function encodeForStorage(uint256 value) public view returns (bytes memory) {
        return Syscalls.serialize(abi.encode(value));
    }

    function toBase64(bytes memory data) public view returns (string memory) {
        return Syscalls.base64Encode(data);
    }

    function numberToHexString(int256 value) public view returns (string memory) {
        return Syscalls.itoa(value, 16);
    }

    function splitCsv(string memory csv) public view returns (string[] memory) {
        return Syscalls.stringSplit(csv, ",", true);
    }
}

Method Token Optimization (CALLT)

By default, native contract calls are emitted as System.Contract.Call syscalls with the target contract hash and method name pushed onto the stack. The --callt compiler flag enables an optimization that replaces these with CALLT instructions referencing a method token table embedded in the NEF binary.

bash
neo-solc contract.sol --callt -O3 -o build/contract

How It Works

Without --callt:

PUSHDATA1 <20-byte contract hash>
PUSHDATA1 <method name string>
PUSHINT8 <call flags>
SYSCALL System.Contract.Call

With --callt:

CALLT <2-byte token index>

The NEF header contains a method token table that maps each token index to a (contractHash, method, parametersCount, hasReturnValue, callFlags) tuple. The Neo VM resolves the token at load time.

Benefits

  • Smaller bytecode — eliminates inline contract hash and method name strings per call site
  • Lower GAS cost — fewer opcodes executed per native call
  • Explicit manifest permissions — each method token generates a precise permission entry

INFO

CALLT is a pure optimization. It does not change contract behavior. Contracts compiled with and without --callt are functionally identical. Use --callt in production builds for best efficiency.


Permission Model

Every native contract call generates a permission entry in the compiled manifest's permissions array. The compiler infers these permissions from the IR and emits explicit contract + methods entries.

Fixed vs Wildcard Permissions

Call PatternManifest Permission
NativeCalls.neoBalanceOf(addr){ "contract": "0xef40...", "methods": ["balanceOf"] }
NativeCalls.gasTransfer(...){ "contract": "0xd2a4...", "methods": ["transfer"] }
Syscalls.sha256(data){ "contract": "0x726c...", "methods": ["sha256"] }
Dynamic contract call{ "contract": "*", "methods": "*" }

Using the devpack's fixed wrappers (NativeCalls.*, Syscalls.*) produces precise permission entries. Dynamic calls through Syscalls.contractCall() with runtime-computed targets or method names may force wildcard permissions.

Hardening

Reject wildcard permissions in production builds:

bash
neo-solc contract.sol \
  --callt \
  --deny-wildcard-contracts \
  --deny-wildcard-methods \
  -o build/contract

WARNING

Wildcard permissions ("contract": "*" or "methods": "*") allow the contract to call any contract or method on the network. Always audit the generated manifest before deployment. Use --deny-wildcard-contracts --deny-wildcard-methods to make the compiler reject any code path that would require wildcards.


See Also

MIT Licensed