Neo Oracle Gateway
Neo Oracle Gateway is the integration layer that gives Neo X smart contracts access to the native Oracle infrastructure on Neo N3.
Neo X currently relies mainly on price feeds, which do not cover broader data needs such as external event outcomes, off-chain metrics, and other general-purpose inputs required by many dApps.
With Neo Oracle Gateway, contracts on Neo X send requests through the message bridge, Neo N3 Oracles fetch the external data, and verifiable responses return on-chain to Neo X.
Why It Matters and Use Cases
Decentralized applications require different kinds of off-chain data, including:
Event outcomes
Off-chain metrics
Public APIs and external data providers
This requires a general-purpose oracle path on Neo X. Neo Oracle Gateway provides that path and supports use cases such as:
Prediction markets
Cross-ecosystem data verification
Governance triggers based on external conditions
Any dApp that depends on trusted off-chain information
How It Works
Neo Oracle Gateway is powered by the Message Bridge.
The message bridge enables a request-response flow between Neo X and Neo N3:
A Neo X smart contract sends an oracle request through the Message Bridge.
The request is executed on Neo N3, where the native Oracle fetches external data.
The oracle result is returned through the Message Bridge.
The Neo X contract receives the response and continues execution.
Watchtower Operation
The Watchtower is an off-chain service that monitors bridge-related transactions on both Neo N3 and Neo X chains.
It tracks nonces from bridge events, filters events by recipient address, and can execute transactions automatically in nonce order or run in watch-only mode.
Features
Dual chain monitoring: Monitors both Neo N3 and Neo X chains for bridge events.
Event types: Monitors native deposits and withdrawals, token deposits and withdrawals, and message sends.
Recipient filtering: Processes events only for configured recipient addresses.
Nonce tracking: Tracks nonces per operation type and enforces sequential execution.
Watch-only mode: Monitors events without executing on-chain transactions.
Execution mode: Automatically executes transactions in nonce order.
While the Watchtower infrastructure can operate for any bridged message type, it currently only executes transactions triggered by Neo Oracle Gateway usage.
Watchtower on-chain operations (execution of bridged messages), are subsidized.
While the Neo Oracle Gateway can function independently, the Watchtower adds convenience and agility by handling message executions automatically, so users do not need to execute messages themselves.
Repositories
oracle-proxy-neo: https://github.com/bane-labs/oracle-proxy-neooracle-proxy-evm: https://github.com/bane-labs/oracle-proxy-evm
Deployments
Mainnet and testnet deployment addresses for Neo Oracle Gateway:
Network
oracle-proxy-neo (Neo N3)
oracle-proxy-evm (Neo X)
Mainnet
0x5a0a0f188f2582ad60c1970267df30ec5428100d
0xce6138E61e5727a318D0DebEaD99Aff24B929131
Testnet
0x5a0a0f188f2582ad60c1970267df30ec5428100d
0xce6138E61e5727a318D0DebEaD99Aff24B929131
Integration Guide (How to Use)
Assuming you are building a Neo X smart contract and want to fetch API JSON data through Neo Oracle Gateway, use the flow below.
1) Add the EVM interface
2) Instantiate the proxy contract
Use the oracle-proxy-evm address from the Deployments table (Mainnet or Testnet, depending on your environment):
3) Initiate an oracle call
Parameter reference for initiateOracleCall():
_maxBridgeFee: Maximum fee you accept for bridge withdrawal._serializedOracleCall: Serialized Neo method call bytes for the Oracle request. It must include exactlyurl,filter, andcallbackMethod. The gateway appendsgasForOracle,gasOracleRequestExec,gasOracleResponseReturn,nonce, andrequestIdautomatically. See how to construct the_serializedOracleCallhere and here._gasForOracle: GAS allocated to the Oracle node. Must be> 0.1 GASand<= _gasOracleRequestExec._gasOracleRequestExec: GAS for Oracle request execution on Neo N3 (includes_gasForOracle)._gasOracleResponseReturn: GAS for returning the Oracle response to Neo X._maxMessageFee: Maximum fee you accept for sending the bridge message._storeResult: Whether to persist the Oracle execution result on-chain.
Returns:
messageNonce: Nonce of the message sent through the bridge.requestId: Oracle request ID assigned byoracle-proxy-evm.
3a) Constructing _serializedOracleCall off-chain (TypeScript)
_serializedOracleCall off-chain (TypeScript)To build the _serializedOracleCall parameter, you must serialize a Neo N3 contract call. In other words, _serializedOracleCall should be the serialized bytes for of the call:
Only the three "request" arguments are included here. The gateway contract (oracle-proxy-evm) appends the remaining execution arguments (gas values, withdrawal nonce, and requestId) automatically inside initiateOracleCall().
Serialize using the required fields below:
url: The full request URL as a string.filter: A JSONPath expression to filter the Oracle response data.callbackMethod: The Neo contract method name to call when the Oracle call completes (commonlyonOracleResponse, depending on your Neo contract).
How _serializedOracleCall is constructed (using bridge-sdk)
_serializedOracleCall is constructed (using bridge-sdk)Serialization is done off-chain using the bridge SDK for Neo N3 call serialization:
@bane-labs/bridge-sdk-ts: https://www.npmjs.com/package/@bane-labs/bridge-sdk-ts
You can install in your project:
The goal is to serialize a Neo N3 contract call to the OracleProxy method requestOracleData(url, filter, callbackMethod).
Off-chain steps:
Provide the Neo N3 parameters used for serialization:
neo3RpcUrl: Neo N3 RPC endpointexecutionManagerHash: ExecutionManager contract hash on Neo N3oracleProxyContractN3: OracleProxy contract hash on Neo N3 (target of the call)
Create the 3 method arguments in the exact order:
methodArgs[0]:{ type: 'String', value: url }methodArgs[1]:{ type: 'String', value: filter }(empty string is allowed)methodArgs[2]:{ type: 'String', value: callbackMethod }
Use a throwaway/dummy account for read-only serialization:
The SDK serializer requires an account object, but this step does not broadcast a transaction.
Serialize the call via the ExecutionManager:
Target contract:
oracleProxyContractN3Method:
'requestOracleData'(mandatory)CallFlags:
15(CallFlags.All) (mandatory hardcoded value)Args:
methodArgs
Pass the returned
hexstring (ensure0xprefix) as_serializedOracleCalltooracleProxy.initiateOracleCall(...).
Example (TypeScript):
Important note: what must not be manually appended
Do not include these values in _serializedOracleCall yourself:
gasForOraclegasOracleRequestExecgasOracleResponseReturnnonce/withdrawalNoncerequestId
These are appended automatically on-chain by oracle-proxy-evm during initiateOracleCall() via NeoSerializerLib.appendArgToCall(...).
3b) Constructing _serializedOracleCall on-chain (Solidity)
_serializedOracleCall on-chain (Solidity)As an alternative to building _serializedOracleCall off-chain (Section 3a), you can construct it entirely on-chain inside your own smart contract using the neo-serializer-evm Solidity library.
Install neo-serializer-evm and import NeoSerializerLib:
Then build the serialized call in your contract:
Parameter reference:
oracleProxyN3
The Neo N3 OracleProxy contract hash (bytes20). This is the target contract on N3 that will execute the oracle request. Use the hash from the Deployments table.
"requestOracleData"
Mandatory hardcoded value. The method name on the N3 OracleProxy contract. Must always be exactly "requestOracleData".
CALL_FLAGS_ALL (15)
Mandatory hardcoded value. Maps to Neo's CallFlags.All (ReadStates | WriteStates | AllowCall | AllowNotify). The library exposes this constant as NeoSerializerLib.CALL_FLAGS_ALL.
args
Array of exactly 3 serialized arguments: url, filter, callbackMethod -- each serialized via NeoSerializerLib.serialize(string).
The returned bytes is a valid _serializedOracleCall that can be passed directly to oracleProxy.initiateOracleCall(...).
Note:
serializeCallinternally handles byte-order conversion for the target hash (reverses bytes to match Neo'sUInt160format viaserializeHash160), serializes the method name and call flags, wraps the args into a Neo Array, and combines everything into the outer serialized structure.
4) Check or fetch the result
Check if a result exists:
Get the result directly:
Last updated