# Overview

## What is Neo X?

Neo X is an EVM-compatible sidechain incorporating Neo's distinctive dBFT consensus mechanism. Serving as a bridge between Neo N3 and the widely used EVM network, Neo X will play a crucial role in expanding the Neo ecosystem and offering developers more opportunities for innovation.

## Main Features

### dBFT Governance

Leveraging the dBFT consensus mechanism, Neo X employs a multi-node governance system. Seven consensus nodes collaboratively process transactions on-chain and participate in voting to determine parameters on the Neo X blockchain, such as blacklisted addresses and minimum required `GAS` tip.

For the initial period following Mainnet launch, the Neo X network is going to be driven by StandBy validators to ensure consensus process stability and proper network connectivity. StandBy nodes are implemented to participate in the consensus process when there are not enough candidates elected by the network users, or there are not enough votes collected to start the elected governance management. For more information about the complete Neo X governance system, see [Governance](/governance/governance-in-neo-x).

### Ethereum Virtual Machine compatibility

The Neo X Mainnet node version is based on the v1.15.11 Geth node implementation with the Prague hardfork supported as the latest one from the list of newly-added Ethereum forks. In other words, Neo X node is fully compatible with all Ethereum VM features up to the [Prague](https://github.com/ethereum/execution-specs?tab=readme-ov-file#ethereum-execution-client-specifications) fork.

### **Bridge Between Neo X and Neo N3**

Neo X supports for bidirectional token transfers between Neo X (EVM) and Neo N3 (NeoVM). Key features include:

* **Bidirectional Bridging of Assets**: Seamless movement of `GAS`between networks, improving liquidity and flexibility.
* **Enhanced Stability and Security**: Upgrades to bridge validators and relayers, along with the introduction of a new role management model to fortify security measures in the bridge smart contracts. For example, the “Security Guard” role can pause bridge operations as needed, while the “Governor” role is empowered to resume operations, as well as propose and update bridge parameters.
* **Bridge Upgradability**: Consensus nodes on the Neo X chain can now propose and implement bridge upgrades, ensuring that the bridge evolves in alignment with the community’s needs.
* **Token Support**: We have laid the groundwork to include NEP-17 and ERC-20 tokens, such as `NEO` token, in future versions of the bridge.


# Networks

### Mainnet

<table><thead><tr><th width="200">Property</th><th width="550">Value</th></tr></thead><tbody><tr><td>Network Name</td><td>Neo X Mainnet</td></tr><tr><td>Chain ID</td><td>47763</td></tr><tr><td>RPC Endpoint</td><td><a href="https://mainnet-1.rpc.banelabs.org">https://mainnet-1.rpc.banelabs.org</a><br><a href="https://mainnet-2.rpc.banelabs.org">https://mainnet-2.rpc.banelabs.org</a><br><a href="https://mainnet-3.rpc.banelabs.org">https://mainnet-3.rpc.banelabs.org</a><br><a href="https://mainnet-5.rpc.banelabs.org">https://mainnet-5.rpc.banelabs.org</a> (Only for Anti-MEV usage*)</td></tr><tr><td>WSS Endpoint</td><td>wss://mainnet.wss1.banelabs.org<br>wss://mainnet.wss2.banelabs.org<br>wss://mainnet.wss3.banelabs.org</td></tr><tr><td>Block Explorer</td><td><a href="https://neoxscan.ngd.network">https://neoxscan.ngd.network</a><br><a href="https://xexplorer.neo.org">https://xexplorer.neo.org</a></td></tr><tr><td>Currency Symbol</td><td>GAS</td></tr><tr><td>Governance</td><td><a href="https://xgovernance.neo.org">https://xgovernance.neo.org</a></td></tr></tbody></table>

### Testnet

<table><thead><tr><th width="200">Property</th><th width="550">Value</th></tr></thead><tbody><tr><td>Network Name</td><td>Neo X Testnet T4</td></tr><tr><td>Chain ID</td><td>12227332</td></tr><tr><td>RPC Endpoint</td><td><a href="https://neoxt4seed1.ngd.network">https://neoxt4seed1.ngd.network</a><br><a href="https://neoxt4seed2.ngd.network">https://neoxt4seed2.ngd.network</a><br><a href="https://neoxt4seed3.ngd.network">https://neoxt4seed3.ngd.network</a><br><a href="https://neoxt4seed5.ngd.network">https://neoxt4seed5.ngd.network</a> (Only for Anti-MEV usage*)</td></tr><tr><td>WSS Endpoint</td><td>wss://neoxt4wss1.ngd.network<br>wss://neoxt4wss2.ngd.network<br>wss://neoxt4wss3.ngd.network</td></tr><tr><td>Block Explorer</td><td><a href="https://neoxt4scan.ngd.network">https://neoxt4scan.ngd.network</a><br><a href="https://xt4scan.ngd.network">https://xt4scan.ngd.network</a></td></tr><tr><td>Currency Symbol</td><td>GAS</td></tr><tr><td>Governance</td><td><a href="https://testnet.governance.banelabs.org">https://testnet.governance.banelabs.org</a></td></tr></tbody></table>

\* RPC nodes that enable Anti-MEV support will not broadcast any normal transaction. Please refer [Envelope Transaction](/security/anti-mev-protection/constructing-envelope-transactions) for their proper usage.

### Bridges

<table><thead><tr><th width="150">Name</th><th width="100">Network</th><th width="500">URL</th></tr></thead><tbody><tr><td>Native Bridge</td><td>Mainnet</td><td><a href="https://xbridge.neo.org">https://xbridge.neo.org</a></td></tr><tr><td></td><td>Testnet</td><td><a href="https://testnet.bridge.banelabs.org">https://testnet.bridge.banelabs.org</a></td></tr><tr><td>CCIP Bridge</td><td>Mainnet</td><td><a href="https://app.transporter.io/?to=neox">https://app.transporter.io</a></td></tr><tr><td></td><td>Testnet</td><td><a href="https://test.transporter.io/?to=neox-testnet-t4">https://test.transporter.io</a></td></tr></tbody></table>

### Faucets

<table><thead><tr><th width="150">Name</th><th width="500">URL</th></tr></thead><tbody><tr><td>N3 Faucet</td><td><a href="https://n3t5wish.ngd.network">https://n3t5wish.ngd.network</a></td></tr><tr><td>Chainlink Faucet</td><td><a href="https://faucets.chain.link/neox-testnet-t4">https://faucets.chain.link</a></td></tr><tr><td>Circle Faucet</td><td><a href="https://faucet.circle.com">https://faucet.circle.com</a></td></tr></tbody></table>

\* Bridge N3 Faucet assets to Neo X via Native Bridge, and Circle Faucet assets via CCIP Bridge.

### Environment Compatibility

<table><thead><tr><th width="200">Name</th><th width="550">Supported Version</th></tr></thead><tbody><tr><td>Geth RPC</td><td>v1.16.9</td></tr><tr><td>Solidity Compiler</td><td>Latest</td></tr><tr><td>EVM Version</td><td>Support up to <code>osaka</code></td></tr></tbody></table>

### Deployed Contracts

#### Core Infrastructure

<table><thead><tr><th width="170">Name</th><th width="100">Network</th><th width="480">Address</th></tr></thead><tbody><tr><td>CREATE2 Deployer</td><td>Mainnet</td><td><a href="https://xexplorer.neo.org/address/0x4e59b44847b379578588920ca78fbf26c0b4956c"><code>0x4e59b44847b379578588920cA78FbF26c0B4956C</code></a></td></tr><tr><td></td><td>Testnet</td><td><a href="https://xt4scan.ngd.network/address/0x4e59b44847b379578588920ca78fbf26c0b4956c"><code>0x4e59b44847b379578588920cA78FbF26c0B4956C</code></a></td></tr><tr><td><a href="https://github.com/pcaversaccio/createx/blob/main/src/CreateX.sol">CreateX</a></td><td>Mainnet</td><td><a href="https://xexplorer.neo.org/address/0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed"><code>0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed</code></a></td></tr><tr><td></td><td>Testnet</td><td><a href="https://xt4scan.ngd.network/address/0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed"><code>0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed</code></a></td></tr></tbody></table>

Core infrastructure contracts provide fundamental primitives used across the ecosystem. The CREATE2 Deployer enables deterministic contract deployments via CREATE2 and matches the canonical Ethereum deployer at the same address. CreateX is an extensible deployment factory for CREATE, CREATE2, and CREATE3-based contract creation, including clone and deploy-and-init workflows.

#### Account Abstraction

<table><thead><tr><th width="220">Name</th><th width="100">Network</th><th width="430">Address</th></tr></thead><tbody><tr><td><a href="https://github.com/eth-infinitism/account-abstraction/releases/tag/v0.6.0">EntryPoint v0.6</a></td><td>Mainnet</td><td><a href="https://xexplorer.neo.org/address/0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"><code>0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789</code></a></td></tr><tr><td></td><td>Testnet</td><td><a href="https://xt4scan.ngd.network/address/0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"><code>0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789</code></a></td></tr><tr><td><a href="https://github.com/eth-infinitism/account-abstraction/releases/tag/v0.7.0">EntryPoint v0.7</a></td><td>Mainnet</td><td><a href="https://xexplorer.neo.org/address/0x0000000071727De22E5E9d8BAf0edAc6f37da032"><code>0x0000000071727De22E5E9d8BAf0edAc6f37da032</code></a></td></tr><tr><td></td><td>Testnet</td><td><a href="https://xt4scan.ngd.network/address/0x0000000071727De22E5E9d8BAf0edAc6f37da032"><code>0x0000000071727De22E5E9d8BAf0edAc6f37da032</code></a></td></tr><tr><td><a href="https://github.com/eth-infinitism/account-abstraction/releases/tag/v0.8.0">EntryPoint v0.8</a></td><td>Mainnet</td><td><a href="https://xexplorer.neo.org/address/0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108"><code>0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108</code></a></td></tr><tr><td></td><td>Testnet</td><td><a href="https://xt4scan.ngd.network/address/0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108"><code>0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108</code></a></td></tr><tr><td><a href="https://github.com/eth-infinitism/account-abstraction/releases/tag/v0.9.0">EntryPoint v0.9</a></td><td>Mainnet</td><td><a href="https://xexplorer.neo.org/address/0x433709009B8330FDa32311DF1C2AFA402eD8D009"><code>0x433709009B8330FDa32311DF1C2AFA402eD8D009</code></a></td></tr><tr><td></td><td>Testnet</td><td><a href="https://xt4scan.ngd.network/address/0x433709009B8330FDa32311DF1C2AFA402eD8D009"><code>0x433709009B8330FDa32311DF1C2AFA402eD8D009</code></a></td></tr><tr><td><a href="https://github.com/eth-infinitism/account-abstraction/releases/tag/v0.8.0">Simple7702Account v0.8</a></td><td>Mainnet</td><td><a href="https://xexplorer.neo.org/address/0x4Cd241E8d1510e30b2076397afc7508Ae59C66c9"><code>0x4Cd241E8d1510e30b2076397afc7508Ae59C66c9</code></a></td></tr><tr><td></td><td>Testnet</td><td><a href="https://xt4scan.ngd.network/address/0x4Cd241E8d1510e30b2076397afc7508Ae59C66c9"><code>0x4Cd241E8d1510e30b2076397afc7508Ae59C66c9</code></a></td></tr><tr><td><a href="https://github.com/eth-infinitism/account-abstraction/releases/tag/v0.9.0">Simple7702Account v0.9</a></td><td>Mainnet</td><td><a href="https://xexplorer.neo.org/address/0xa46cc63eBF4Bd77888AA327837d20b23A63a56B5"><code>0xa46cc63eBF4Bd77888AA327837d20b23A63a56B5</code></a></td></tr><tr><td></td><td>Testnet</td><td><a href="https://xt4scan.ngd.network/address/0xa46cc63eBF4Bd77888AA327837d20b23A63a56B5"><code>0xa46cc63eBF4Bd77888AA327837d20b23A63a56B5</code></a></td></tr></tbody></table>

Account abstraction infrastructure provides the canonical ERC-4337 EntryPoint contracts used by smart accounts, bundlers, paymasters, and related account abstraction tooling.

The EntryPoint is a critical singleton contract for ERC-4337. Different wallets and Bundlers may depend on different EntryPoint versions, so Neo X provides deployments for v0.6, v0.7, v0.8, and v0.9. The contracts use the same CREATE2-based deployment scheme and canonical addresses as the corresponding upstream releases, allowing their deployment bytecode and runtime bytecode to be independently checked against those releases.

The governance-sponsored gas abstraction flow using GovPaymaster currently targets EntryPoint v0.9. GovPaymaster is coupled to that EntryPoint version, and the documented Altpool endpoints advertise support for it. The other canonical EntryPoint deployments are available for compatible wallets and independently operated Bundlers; their availability does not by itself imply GovPaymaster sponsorship support.

#### Utilities

<table><thead><tr><th width="150">Name</th><th width="100">Network</th><th width="500">Address</th></tr></thead><tbody><tr><td>Multicall3</td><td>Mainnet</td><td><a href="https://xexplorer.neo.org/address/0xD6010D102015fEa9cB3a9AbFBB51994c0Fd6E672"><code>0xD6010D102015fEa9cB3a9AbFBB51994c0Fd6E672</code></a></td></tr><tr><td></td><td>Testnet</td><td><a href="https://xt4scan.ngd.network/address/0x82096F92248dF7afDdef72E545F06e5be0cf0F99"><code>0x82096F92248dF7afDdef72E545F06e5be0cf0F99</code></a></td></tr><tr><td>Permit2</td><td>Mainnet</td><td>0x000000000022D473030F116dDEE9F6B43aC78BA3</td></tr><tr><td></td><td>Testnet</td><td>0x000000000022D473030F116dDEE9F6B43aC78BA3</td></tr></tbody></table>

Utility contracts provide reusable functionality for interacting with the network. Multicall3 enables batching multiple contract calls into a single request. Permit2 enables signature-based token approvals and transfers.

#### Assets

<table><thead><tr><th width="150">Name</th><th width="100">Network</th><th width="500">Address</th></tr></thead><tbody><tr><td>WGAS10</td><td>Mainnet</td><td><a href="https://xexplorer.neo.org/address/0xdE41591ED1f8ED1484aC2CD8ca0876428de60EfF"><code>0xdE41591ED1f8ED1484aC2CD8ca0876428de60EfF</code></a></td></tr><tr><td></td><td>Testnet</td><td><a href="https://xt4scan.ngd.network/address/0x1CE16390FD09040486221e912B87551E4e44Ab17"><code>0x1CE16390FD09040486221e912B87551E4e44Ab17</code></a></td></tr><tr><td><a href="https://github.com/bane-labs/xgas">xGAS</a></td><td>Mainnet</td><td><a href="https://xexplorer.neo.org/address/0x9a50C8804dC885F118835cD96d3Ea4D4A5131A01"><code>0x9a50C8804dC885F118835cD96d3Ea4D4A5131A01</code></a></td></tr><tr><td></td><td>Testnet</td><td><a href="https://xt4scan.ngd.network/address/0x3eE9da67D85475a250423138cBf56aF511277958"><code>0x3eE9da67D85475a250423138cBf56aF511277958</code></a></td></tr></tbody></table>

Asset contracts represent tokenized value on Neo X.

* WGAS10 wraps native GAS with a WETH9-compatible design and implements ERC-3156 flash loans.
* xGAS is an immutable wrapped native GAS asset that extends standard ERC-20 behavior with explicit permit and transfer-authorization support (EIP-2612, EIP-3009, EIP-712), plus ERC-1271-compatible encoded-signature extensions.

#### Integrations

<table><thead><tr><th width="200">Name</th><th width="100">Network</th><th width="450">Address</th></tr></thead><tbody><tr><td>x402ExactPermit2Proxy</td><td>Mainnet</td><td>0x402085c248EeA27D92E8b30b2C58ed07f9E20001</td></tr><tr><td></td><td>Testnet</td><td>0x402085c248EeA27D92E8b30b2C58ed07f9E20001</td></tr></tbody></table>

Integration contracts enable higher-level workflows built on top of Neo X. The x402ExactPermit2Proxy is a Permit2-based x402 settlement contract for exact-amount, witness-bound payments.

See: [x402 Integration](/integrations/x402)


# Run a Neo X Node

This document contains step-by-step instructions for running a geth node in Neo X.

### Hardware Requirements

The following are the minimum hardware requirements:

#### Seed Node

* CPU with 2+ cores
* 4 GB RAM
* 200GB free storage space for data synchronization
* 8 MBit/sec download Internet service

#### Miner Node

* Fast CPU with 2+ cores
* 16 GB RAM
* 200 GB free storage space for data synchronization
* 8 MBit/sec download Internet service

### 1. Build or Download Geth Binary

#### Build from source

Building `geth` requires both a Go (version 1.24 or later) and a C compiler. Feel free to install them with the package manager of your choice.

Once the dependencies are installed, run

```shell
make geth
```

or, build the full suite of utilities:

```shell
make all
```

#### Download from release

You can download the latest `geth` binary from [Release Page](https://github.com/bane-labs/go-ethereum/releases).

### 2. Initialize Geth Database

Download the latest release version of both binary and configuration file from [Release Page](https://github.com/bane-labs/go-ethereum/releases).

To create a blockchain node that uses this genesis block, first use `geth init` to import and set the canonical genesis block for the new chain. This requires the path to the configuration file to be passed as an argument.

`--datadir` is the target destination for the node database. Here we use `./node`:

Testnet

```shell
./geth init --datadir ./node ./genesis_testnet.json
```

Mainnet

```shell
./geth init --datadir ./node ./genesis_mainnet.json
```

You can then download the [Mainnet archival snapshot](https://package.banelabs.org/), and insert them into your local database with `./geth import --datadir ./node <filename>`, or directly start up your node to synchronize to the latest block.

### 3.a. Start a Seed Node

A seed node is a network member that does not participate in the consensus process. This node can be used to interact with the Neo X network, including: creating accounts, transferring funds, deploying and interacting with contracts, and querying node APIs.

### 3.a.1. Start with Script

Create the `startSeed.sh` file in the same folder of `geth`. You may need to change the `P2P/HTTP/RPC/WS` ports to avoid conflicts. Please note that the port configuration for the JSON-RPC interface should be set to httpport, not rpcport. Additionally, remember to change `extip` to your own IP address if you want other nodes to be able to find yours. You can refer to <https://geth.ethereum.org/docs/fundamentals/command-line-options> for more details about start options.

This script expects node DB directory to be `./node`.

#### Testnet:

```shell
#!/bin/bash
​
# Data directory
node="./node"
​
# Ports for network discovery
port=30303
udpport=30303

# Ports for node APIs
httpport=8551
rpcport=8561
wsport=8571
extip=127.0.0.1
​
# Start the node
nohup ./geth \
--networkid 12227332 \
--nat extip:$extip \
--port $port \
--discovery.port $udpport \
--authrpc.port $rpcport \
--identity $node \
--maxpeers 50 \
--syncmode full \
--gcmode archive \
--datadir $node \
--bootnodes "enode://60603db58ef8c90ed152531425910b0352e9304f04935d0f2b5ce149a8c70fb7a743a39020bb12161e56c17b34d9a6295b378436ac43a09b75bbdc954b48ca5d@34.42.6.58:30304,enode://9d58aaeb46d51ab442cff90613e65e979fbd2084b46b25e46565b289baa007ea50e4abfad4e8655873e7f5a1f51b504df217a0d577fffa8278ad2105c0b8cfa9@34.87.188.162:30304" \
--http.api eth,net,txpool,web3 \
--http --http.addr 0.0.0.0 --http.port $httpport --http.vhosts "*" --http.corsdomain '*' \
--ws --ws.addr 0.0.0.0 --ws.port $wsport --ws.api eth,net,web3 --ws.origins '*'  \
--verbosity 3  >> $node/node.log 2>&1 &
​
sleep 3s;
ps -ef|grep geth|grep mine|grep -v grep;
```

#### Mainnet:

```shell
#!/bin/bash
​
# Data directory
node="./node"
​
# Ports for network discovery
port=30303
udpport=30303

# Ports for node APIs
httpport=8551
rpcport=8561
wsport=8571
extip=127.0.0.1
​
# Start the node
nohup ./geth \
--networkid 47763 \
--nat extip:$extip \
--port $port \
--discovery.port $udpport \
--authrpc.port $rpcport \
--identity $node \
--maxpeers 50 \
--syncmode full \
--gcmode archive \
--datadir $node \
--bootnodes "enode://92eec46dd8b67ea8d8999defe0bf2b43d4c4802ed42a430843fec97dafbdc9128849261bdf1a940d431fc61f06a1317f5fc7c0386e18a9bbf951d0ccd8bf4f98@34.42.6.58:30303,enode://f289fb5c83ed39cf7d7aff2727afe70bf7951222c4a9aaef7bcbceef9fd0b53e4b6c9c0e08a50774dfd50d93e83b977932e4780934d379a6a0ac10cc44c6cfdb@34.87.188.162:30303" \
--http.api eth,net,txpool,web3 \
--http --http.addr 0.0.0.0 --http.port $httpport --http.vhosts "*" --http.corsdomain '*' \
--ws --ws.addr 0.0.0.0 --ws.port $wsport --ws.api eth,net,web3 --ws.origins '*'  \
--verbosity 3  >> $node/node.log 2>&1 &
​
sleep 3s;
ps -ef|grep geth|grep mine|grep -v grep;
```

Then run

```shell
./startSeed.sh
```

### 3.b. Start a Miner Node

A miner node participates in the consensus process. If you want to register as a candidate for the consensus list, you need to run a miner node.

### 3.b.1. Initialize Node Account

You can create a new account or import an existing account for your node operation. Seed nodes don't need node account.

#### Create a new account

Create your node account with the following command. A password is required to be entered during the process. The resulting account is placed in the specified `--datadir` under the `keystore` path.

```shell
./geth --datadir ./node account new
```

#### Import your existing account

Import your existing account with the private key and remember to replace the `./your/privateKey.txt` parameter.

```shell
./geth account import --datadir ./node ./your/privateKey.txt
```

When the inputing node index is set to 1, this script requires the node address to be placed at `node/node_address.txt`, the node password to be placed at `node/password.txt` and the node DB directory to be placed at `./node`.

### 3.b.2. Create an Anti-MEV Keystore

Validators and candidates participating in dBFT consensus must set up an Anti-MEV keystore, or the node will fail to enable the miner functionality.

To create an Anti-MEV keystore for your validator account, run:

```shell
./geth --datadir ./node antimev init <address>
```

You will be prompted to enter a password for the keystore.

### 3.b.3. Download ZK Files

Validators participating in onchain DKG must have three pairs of R1CS files and proving keys for Groth16 proof generation.

You can download these files from [Neo X MPC](https://github.com/bane-labs/mpc) through [NeoFS](https://fs.neo.org/) or cloud URLs.

### 3.b.4. Start with Script

Create the `startMiner.sh` file in the same folder of `geth`. You may need to change the `P2P/RPC` ports to avoid conflicts. Additionally, remember to change `extip` if you want other nodes to be able to find yours. You can refer to <https://geth.ethereum.org/docs/fundamentals/command-line-options> for more details about start options.

#### Testnet:

```shell
#!/bin/bash
​
# Data directory
node="./node"
miner=$(<$node/node_address.txt)
​
# Ports for network discovery
port=30303
udpport=30303

# Ports for node APIs
httpport=8551
rpcport=8561
wsport=8571
extip=127.0.0.1
​
# Start the node
nohup ./geth \
--networkid 12227332 \
--nat extip:$extip \
--port $port \
--discovery.port $udpport \
--mine --miner.pending.feeRecipient $miner \
--unlock $miner \
--password $node/password.txt \
--antimev.password $node/password.txt \
--dkg.one-msg-r1cs ./r1cs/one_message.ccs \
--dkg.two-msg-r1cs ./r1cs/two_message.ccs \
--dkg.seven-msg-r1cs ./r1cs/seven_message.ccs \
--dkg.one-msg-pk ./pk/one_message.pk \
--dkg.two-msg-pk ./pk/two_message.pk \
--dkg.seven-msg-pk ./pk/seven_message.pk \
--authrpc.port $rpcport \
--identity $node \
--maxpeers 50 \
--syncmode full \
--gcmode archive \
--datadir $node \
--bootnodes "enode://60603db58ef8c90ed152531425910b0352e9304f04935d0f2b5ce149a8c70fb7a743a39020bb12161e56c17b34d9a6295b378436ac43a09b75bbdc954b48ca5d@34.42.6.58:30304,enode://9d58aaeb46d51ab442cff90613e65e979fbd2084b46b25e46565b289baa007ea50e4abfad4e8655873e7f5a1f51b504df217a0d577fffa8278ad2105c0b8cfa9@34.87.188.162:30304" \
--verbosity 3  >> $node/node.log 2>&1 &

sleep 3s;
ps -ef|grep geth|grep mine|grep -v grep;
```

#### Mainnet:

```shell
#!/bin/bash
​
# Data directory
node="./node"
miner=$(<$node/node_address.txt)
​
# Ports for network discovery
port=30303
udpport=30303

# Ports for node APIs
httpport=8551
rpcport=8561
wsport=8571
extip=127.0.0.1
​
# Start the node
nohup ./geth \
--networkid 47763 \
--nat extip:$extip \
--port $port \
--discovery.port $udpport \
--mine --miner.pending.feeRecipient $miner \
--unlock $miner \
--password $node/password.txt \
--antimev.password $node/password.txt \
--dkg.one-msg-r1cs ./r1cs/one_message.ccs \
--dkg.two-msg-r1cs ./r1cs/two_message.ccs \
--dkg.seven-msg-r1cs ./r1cs/seven_message.ccs \
--dkg.one-msg-pk ./pk/one_message.pk \
--dkg.two-msg-pk ./pk/two_message.pk \
--dkg.seven-msg-pk ./pk/seven_message.pk \
--authrpc.port $rpcport \
--identity $node \
--maxpeers 50 \
--syncmode full \
--gcmode archive \
--datadir $node \
--bootnodes "enode://92eec46dd8b67ea8d8999defe0bf2b43d4c4802ed42a430843fec97dafbdc9128849261bdf1a940d431fc61f06a1317f5fc7c0386e18a9bbf951d0ccd8bf4f98@34.42.6.58:30303,enode://f289fb5c83ed39cf7d7aff2727afe70bf7951222c4a9aaef7bcbceef9fd0b53e4b6c9c0e08a50774dfd50d93e83b977932e4780934d379a6a0ac10cc44c6cfdb@34.87.188.162:30303" \
--verbosity 3  >> $node/node.log 2>&1 &
​
sleep 3s;
ps -ef|grep geth|grep mine|grep -v grep;
```

Then run

```shell
./startMiner.sh
```

### 3.b.5. Registering as a Candidate

After running a miner node, you can stake 1000 GAS to register as a candidate for the consensus list. If your node receives enough votes (top 7 in GAS), it will become a consensus node, which will mint blocks and share the transaction fee rewards.

#### Attach the node IPC

```shell
./geth attach ./node/geth.ipc
```

#### Call the Governance contract

```javascript
var abi = [{
  "inputs": [
    {
      "internalType": "uint256",
      "name": "shareRate",
      "type": "uint256"
    },
    {
      "internalType": "bytes",
      "name": "pubkey",
      "type": "bytes"
    }
  ],
  "name": "registerCandidate",
  "outputs": [],
  "stateMutability": "payable",
  "payable": "true",
  "type": "function"
}];

var govContract = web3.eth.contract(abi);
var govInstance = GovContract.at('0x1212000000000000000000000000000000000001');

// send 1000 GAS (This value is 20000 in current testnet) and call registerCandidate(shareRate)
// shareRate is the rate share to voters, the rate base is 1000, 100 means 10%
govInstance.registerCandidate(100, ANTIMEV_KEYSTORE_PUBKEY, {value:'1000000000000000000000', from: eth.accounts[0]});
```


# JSON-RPC API

Neo X is in sync with most [Ethereum JSON-RPC](https://ethereum.org/en/developers/docs/apis/json-rpc/) methods, but there are some differences to note:

* `eth_chainId` — returns the chain ID of Neo X.
* `eth_hashrate` — returns `0x0` by default.
* `eth_coinbase` — returns the `GovReward` contract address.
* `eth_gasPrice` — returns the maximum value of the current network GAS price and the lowest allowed GAS price by Neo X Policy.
* `eth_maxPriorityFeePerGas` — returns an estimated value of priority fee to get a transaction allowed by Neo X Policy and in the current block.
* `eth_getUncleByBlockHashAndIndex` — returns `null` by default.
* `eth_getUncleByBlockNumberAndIndex` — returns `null` by default.
* `eth_getUncleCountByBlockHash` — returns `0` by default.
* `eth_getUncleCountByBlockNumber` — returns `0` by default.
* `eth_getCachedTransaction` — returns the cached and signed secret transactions. It requires a valid sender signature in parameters, and only works on nodes configured with `--txpool.amevcache`;
* `eth_envelopeFee` — returns the minimum additional `gastip`/`gasprice` that anti-mev transactions should pay for the service.
* `eth_maxEnvelopeGasLimit` — returns the maximum `gaslimit` that an Envelope can declare for itself.
* `eth_getBlobSidecars` — returns the blob data of a block. It requires a valid block hash or number as the parameter.
* `eth_getBlobSidecarByTxHash` — returns the blob data of a transaction. It requires a valid transaction hash as the parameter.


# Governance-Sponsored Gasless Transactions

Neo X has deployed a native, governance-funded Paymaster (`GovPaymaster`) to sponsor eligible [ERC-4337](https://docs.erc4337.io/) UserOperations and documents a Bundler service known as the **Altpool**.

This is a governance-sponsored Account Abstraction flow. A UserOperation is not a normal transaction: the user signs a structured operation, a Bundler accepts it through the ERC-7769 JSON-RPC API, and the Bundler submits one or more accepted operations to EntryPoint in a normal on-chain transaction.

GovPaymaster is a Neo X system contract exposed through the native-contract proxy infrastructure. Its address is listed in the Mainnet and Testnet tables below.

### What "gasless" means

"Gasless" describes the user experience, not a specific transaction type or a guarantee that no one pays gas. In this service:

* the user signs a UserOperation instead of submitting a normal transaction;
* Altpool submits the resulting on-chain bundle;
* GovPaymaster pays the eligible operation's gas through its EntryPoint deposit;
* the user does not need to hold native GAS for that sponsored operation.

Sponsorship is conditional:

* GovPaymaster may reject an operation, and sponsorship is unavailable when its balance is insufficient;
* ERC-4337 EntryPoint provides and enforces the common on-chain validation, execution, and fee-accounting flow;
* The Bundler may not submit an operation, if the local simulation fails due to the GovPaymaster or EntryPoint validation.

Other Bundlers and Paymasters can implement different gas-abstraction models, including sponsorship policies or payment through a tokenized gas asset, without using GovPaymaster. For example, another Bundler could support a Paymaster that charges users in xGAS, wrapped GAS (wGAS), a stablecoin, or another supported token while still submitting the UserOperation bundle through EntryPoint; the Paymaster would handle the token-based payment while EntryPoint accounts for the underlying network gas.

### Deployments

#### Mainnet

<table><thead><tr><th width="200">Property</th><th width="550">Value</th></tr></thead><tbody><tr><td>GovPaymaster</td><td><code>0x121200000000000000000000000000000000000A</code></td></tr><tr><td>EntryPoint v0.9</td><td><code>0x433709009B8330FDa32311DF1C2AFA402eD8D009</code></td></tr><tr><td>Bundler RPC</td><td><a href="https://mainnet.bundler.banelabs.org">https://mainnet.bundler.banelabs.org</a></td></tr></tbody></table>

#### Testnet

<table><thead><tr><th width="200">Property</th><th width="550">Value</th></tr></thead><tbody><tr><td>GovPaymaster</td><td><code>0x121200000000000000000000000000000000000A</code></td></tr><tr><td>EntryPoint v0.9</td><td><code>0x433709009B8330FDa32311DF1C2AFA402eD8D009</code></td></tr><tr><td>Bundler RPC</td><td><a href="https://neoxt4bundler.banelabs.org">https://neoxt4bundler.banelabs.org</a></td></tr></tbody></table>

### Pay By Governance

For every block in the network, Neo X distributes a fixed ratio of the network reward to the GovPaymaster contract (10% at the time of writing – August 2026).

This contract releases up to 0.4 GAS per block to sponsor UserOperations via EntryPoint v0.9. However, sponsorship is not guaranteed if the balance is insufficient.

GovPaymaster maintains a native-token deposit with EntryPoint. For an accepted sponsored UserOperation, EntryPoint charges the gas cost to that deposit instead of requiring the smart account to pay. The Bundler submits the on-chain bundle and receives the collected UserOperation fees through EntryPoint.

For users, the important point is that the operation is sponsored only when GovPaymaster accepts it and has sufficient funds available.

### Paymaster Rules

GovPaymaster is restricted by the [network policy](/governance/neo-x-system-contracts#policy). It permits a priority fee up to 20% above the network minimum so that Bundlers can be compensated for submitting sponsored operations. This is a fee limit for sponsorship eligibility, not a separate fee that users pay and not a guaranteed Bundler profit.

The contract only sponsors UserOperations that meet the following requirements:

1. The sender is not blacklisted; otherwise it returns a custom error `SenderBlacklisted`;
2. `maxPriorityFeePerGas` is not higher than *`1.2 * minGasTipCap`* according to the network policy; otherwise it returns a custom error `GasTipTooHigh`;
3. `maxFeePerGas` is not higher than *`baseFee + (1.2 * minGasTipCap)`* according to the network policy, otherwise it returns a custom error `MaxFeeTooHigh`.

GovPaymaster sponsorship is not automatic. A sponsored UserOperation must explicitly identify GovPaymaster in its Paymaster field or fields. If no Paymaster is included, the `sender` smart account must provide the required EntryPoint deposit or prefund during account validation. If GovPaymaster has insufficient balance or rejects the operation, the Bundler should reject it before submitting a bundle.

### Bundler Rules

The Altpool Bundler service provides a quick start for using governance sponsorship, but you may also set up your own Bundler with different strategies.

This Bundler operates as follows:

1. Support [ERC-7769](https://eips.ethereum.org/EIPS/eip-7769) standard APIs;
2. Processes UserOperations in FIFO (First-In-First-Out) order, regardless of gas tip priority;
3. Accepts only UserOperations that will not cause a deficit.

### Altpool and other Bundlers

Altpool is the name of the Bundler service documented for Neo X. It accepts UserOperations through the ERC-7769 API and submits accepted bundles to EntryPoint.

GovPaymaster sponsorship is not restricted to Altpool. Any Bundler that supports the required EntryPoint version and UserOperation format can submit an operation that explicitly identifies GovPaymaster, provided the operation passes GovPaymaster's policy checks and sufficient Paymaster funds are available. The Bundler supplies the `beneficiary` address when it calls `EntryPoint.handleOps(...)`; EntryPoint uses that address when transferring the collected fees. Running an independent Bundler still requires the operator to provide the Bundler infrastructure and initially fund the outer on-chain transaction.

The relevant UserOperation RPC methods include:

* `eth_sendUserOperation` — submit a signed UserOperation and EntryPoint address;
* `eth_estimateUserOperationGas` — estimate the operation's gas requirements;
* `eth_getUserOperationByHash` — retrieve a pending or included UserOperation;
* `eth_getUserOperationReceipt` — retrieve the operation result and the underlying bundle transaction receipt;
* `eth_supportedEntryPoints` — list the EntryPoint addresses supported by the Bundler.

These methods are sent to the Bundler RPC endpoint, not to the ordinary chain RPC endpoint. The ordinary chain RPC remains useful for reading chain state and inspecting the resulting transaction.

### Sending a Sponsored UserOperation

It's recommended to start with Altpool and make full use of GovPaymaster's sponsorship. The result is sponsored rather than intrinsically free: execution consumes gas, and GovPaymaster covers the accepted operation's gas through its EntryPoint deposit.

1. Choose a deployed ERC-4337 smart-account implementation and wallet factory, or an EIP-7702 wallet implementation. A traditional ERC-4337 flow uses a smart-contract account; EIP-7702 provides an alternative account-authorization flow;
2. Calculate the account's deterministic `sender` address. For a new account, prepare `initCode` using the selected factory and its initialization calldata. EntryPoint calls that factory during the first UserOperation and deploys the account before validating and executing the operation. The client constructing the UserOperation controls `initCode`; for an account that already exists, it should set `initCode` to `0x`. A Bundler may reject an existing `sender` paired with non-empty account-creation data;
3. Obtain the UserOperation nonce from EntryPoint, normally with `getNonce(sender, key)`;
4. Include GovPaymaster information in `paymasterAndData` (or the equivalent v0.9 RPC fields), and configure `gasFees` within the maximum values it allows;
5. Sign the complete UserOperation using the smart account's authorization scheme and send it to the Altpool Bundler RPC using `eth_sendUserOperation`, together with the supported EntryPoint v0.9 address;
6. Poll `eth_getUserOperationReceipt` until the operation is included or rejected.

If the smart wallet is successfully deployed and initialized, you can begin your gasless Account Abstraction journey.

### UserOperation structure and v0.9 encoding

The UserOperation is a structured object. Its core fields include:

* `sender` and `nonce`;
* account creation data (`factory` and `factoryData` in the RPC representation, or packed into `initCode` for EntryPoint);
* `callData` for the smart account's requested action;
* `callGasLimit`, `verificationGasLimit`, and `preVerificationGas`;
* `maxFeePerGas` and `maxPriorityFeePerGas` (packed as `gasFees` for EntryPoint);
* Paymaster data and Paymaster gas limits, when sponsorship is requested;
* `signature`.

For EntryPoint v0.9, the on-chain interface uses `PackedUserOperation`. The ERC-7769 RPC representation may expose the factory and Paymaster fields separately, while the on-chain `handleOps(...)` call receives packed fields. Client implementations must use the exact schema accepted by the Bundler endpoint.

For the complete RPC schema and request/response examples, see [ERC-7769: JSON-RPC API for ERC-4337](https://eips.ethereum.org/EIPS/eip-7769), especially `eth_estimateUserOperationGas` and `eth_sendUserOperation`. For the protocol-level fields and packed v0.9 representation, see the [ERC-4337 UserOperation specification](https://eips.ethereum.org/EIPS/eip-4337#the-useroperation-structure).

### EntryPoint execution flow

The Bundler does not execute the application call directly. It simulates UserOperations off-chain, groups accepted operations, and submits a normal transaction calling `EntryPoint.handleOps(...)`.

EntryPoint then:

1. deploys the account from `initCode` when necessary;
2. validates the smart account's signature and nonce;
3. validates and prefunds the Paymaster when one is specified;
4. executes the smart account's `callData`;
5. charges the account or Paymaster for the actual gas used; and
6. pays the collected fees to the Bundler's beneficiary.

If the application call reverts, EntryPoint records the UserOperation as unsuccessful and can continue with other operations in the bundle. Gas already consumed is still charged. Validation or sponsorship failures should be caught by Bundler simulation and rejected before submission; an unexpected validation failure can cause the bundle transaction to fail.

### Deposits without a Paymaster

Without a Paymaster, the smart account must fund its EntryPoint deposit, for example through `EntryPoint.depositTo(sender)`, or provide missing funds during `validateUserOp`. A Bundler does not permanently subsidize an operation merely because it submitted the outer transaction.

### EntryPoint versions

Neo X provides the canonical ERC-4337 EntryPoint deployments v0.6, v0.7, v0.8, and v0.9 at the deterministic addresses specified by their corresponding upstream releases. The documented GovPaymaster contract is coupled to EntryPoint v0.9, and the Altpool endpoints described on this page advertise EntryPoint v0.9. Therefore, the native governance-sponsored flow uses EntryPoint v0.9. The other EntryPoint versions remain available for compatible wallets and independently operated Bundlers, but are not covered by the GovPaymaster flow described here.

### Decentralization

The EntryPoint v0.9 is a publicly verifiable contract, while GovPaymaster is managed by Neo X Governance. Both are reliable services to depend on.

Additionally, you are free to set up your own Bundlers or Paymasters for your users. GovPaymaster is fully public, allowing any user or Bundler to request sponsorship.


# Native Bridge


# General

A cross-chain bridge is a software protocol that allows for the smooth transfer of data and/or assets between different blockchain networks. The transfer of data can be regarded as messages moving from one chain to another. These messages may include specific actions that facilitate the transfer of crypto assets, the invocation of contracts or simply writing data to the other chain.

In the context of Neo X, this project aims to bridge:

* From **Neo N3** to **Neo X** (*N3->NeoX*);
* From **Neo X** to **Neo N3** (*NeoX->N3*);

For both directions it supports bridging tokens and arbitrary messages.

In the following sections we will elaborate on the approach to bridging, the architecture, the roles with their responsibilities, and the involved smart contracts.


# Architecture

The bridge is composed of the following key components:

* Smart Contract for Role Management and Verifying Validator Consensus (BridgeManagement)
* Smart Contract for Transferring Assets (TokenBridge)
* Smart Contract for Bridging Messages (MessageBridge)
* Validator Nodes
* One Relayer Node

> Each of the above listed contracts is deployed once per chain.

The smart contracts serve as the foundation for the bridging system. They contain crucial functionality such as role management (BridgeManagement), accepting token transfer requests including locking and unlocking them (BridgeContract) and message sending (MessageBridge).

The validator nodes track incoming bridge requests, validate and sign them off, and then provide the observed request data including their signature to the relayer.

The relayer is a single node that awaits and collects signatures and bridge request data from validator nodes. Once enough signatures have been collected for passing verification on the destination chain's BridgeManagement, it invokes the corresponding bridge contract to finalize the bridge request. Depending on the type and data of the request, the sent message is persisted, or tokens are distributed or are made available for claiming.

The architecture of the bridge is illustrated in the following image:


# Roles and Responsibilities

The bridge involves several distinct roles that are managed in the BridgeManagement contract. Besides the already elaborated Validator and Relayer role, there exist the following additional roles:

* Owner
* Governor
* SecurityGuard

The owner is a multi-sig account consisting of keys stored in cold wallets. Its main responsibility is assigning roles as well as performing contract updates. On Neo X exclusively, the responsibility of updating the contracts lies with the Neo X committee, ultimately reducing the owner's responsibility on the bridge contracts on Neo X to role assigning only.

The governor is responsible for pausing/unpausing, updating parameters, and registering tokens.

Finally, the security guard is allowed to pause contracts with the intention of using this role for emergency intervention.

The table below provides an overview of the main functionalities of the smart contracts and who is allowed to use them.

<table><thead><tr><th width="220">Functionality</th><th width="230">Management</th><th width="150">TokenBridge</th><th width="150">MessageBridge</th></tr></thead><tbody><tr><td>Update Contract (N3/Neo X)</td><td>Owner/Committee</td><td>Owner/Committee</td><td>Owner/Committee</td></tr><tr><td>Assign Roles</td><td>Owner</td><td>-</td><td>-</td></tr><tr><td>Pause</td><td>-</td><td>Governor and SecurityGuard</td><td>Governor and SecurityGuard</td></tr><tr><td>Unpause</td><td>-</td><td>Governor</td><td>Governor</td></tr><tr><td>Update a Parameter (e.g., fee)</td><td>-</td><td>Governor</td><td>Governor</td></tr><tr><td>Register a Token</td><td>-</td><td>Governor</td><td>Governor</td></tr><tr><td>Request Bridging Tokens/Messages</td><td>-</td><td>Anyone</td><td>Anyone</td></tr><tr><td>Relaying Requests</td><td>-</td><td>Relayer (incl. enough Validator signatures)</td><td>Relayer (incl. enough Validator signatures)</td></tr></tbody></table>

> **IMPORTANT:**
>
> Although only the relayer is authorized to use the distribution/relaying functionality, it requires sufficiently enough signatures of validators. The required threshold of validator signatures is set in the BridgeManagement contract.


# Bridging Transparency and Verifiable Relaying

Our bridge uses per-token, per-direction hash chains to make all validator and relayer actions transparent and independently verifiable. This applies to both token bridging and arbitrary message bridging:

* Each registered token pair maintains its own hash chain for:
  * Deposits (N3 → Neo X)
  * Withdrawals (Neo X → N3)
* The message bridge maintains a separate hash chain for each direction.

This means there is *not* a single global hash chain — there are many independent chains, each proving the ordered history of operations of that individual bridge.

> For example, if there are 2 tokens registered, then there are 4 independent hash chains maintained in the TokenBridge contract: token #1 deposits, token #1 withdrawals, token #2 deposits, and token #2 withdrawals. Meanwhile, the MessageBridge maintains 2 hash chains — 1 hash chain per direction.

## How the Hash Chains Work

Each hash chain begins with a fixed root (`0x00...00`, 32 bytes). For every incoming bridge operation — whether token or message — the corresponding bridge contract constructs an operation hash from:

* the operation's nonce
* the operation's context
  * for tokens: token identifiers
  * for messages: message-specific metadata (i.e., type, timestamp, sender)
* the operation's request data:
  * for tokens: amount, recipient
  * for messages: the provided raw bytes

> The token bridge for native GAS on Neo X is managed as a special case as it does not involve any contract address on Neo X. Therefore, the hash chain for this token bridge omits the token identifiers.

The new hash-chain root is then computed as:

`newRoot = keccak256(currentRoot || operationHash)`

where `||` denotes concatenation.

The contract then emits an event containing:

* the operation data: nonce, payload (and metadata),
* the operation hash,
* the new root.

## Source-Chain Processing: The Smart Contract as the Truth-Teller

For each bridge identity (token A, B, message, etc.) the corresponding bridge contract (TokenBridge or MessageBridge) maintains the **authoritative state** for that direction:

* the **current nonce**, and
* the **current hash-chain root**.

### Token Deposit and Withdrawal Handling on the Source Chain

For token operations, the bridge contract applies the underlying token transfer logic **before** updating the hash-chain state:

* **Token deposits (N3 → Neo X)**: The user pays the required **GAS fee**, and the requested tokens are **transferred into and locked within** the TokenBridge contract on Neo N3.
* **Token withdrawals (Neo X → N3)**: The user pays the required **GAS fee** (attached as *`msg.value`*), and the requested tokens are **transferred into and locked within** the TokenBridge contract on Neo X as part of initiating the withdrawal request.

Only after these transfer steps succeed does the contract proceed with:

1. **Incrementing the nonce**,
2. **Computing the new hash-chain root** using the previous root and the operation hash,
3. **Overwriting the stored state** with the new `(nonce, root)` pair,
4. **Emitting an event** containing the operation data, the operation hash, and the new root.

This on-chain computation is the **canonical source of truth**.

Validators do not invent or interpret roots — they only read and verify what the contract already computed.

## Validator Reconstruction and Attestation

Validator nodes monitor the source chain for these events. For each observed operation, a validator:

1. **Reads** the event emitted by the smart contract.
2. **Reconstructs** the operation hash and new root locally using the same deterministic hashing rules.
3. **Compares** its reconstructed root with the value produced by the contract.

Only if the reconstructed root **exactly matches** the on-chain root does the validator proceed.

### Decoupled Validator & Relayer Architecture (Summary)

The bridging system separates responsibilities between **validators** and **a relayer** to minimize trust assumptions, reduce attack surface, and ensure that validators never need to submit transactions on-chain.

* **Validators** independently observe source-chain events, reconstruct the hash-chain state, and sign the new top root only if it matches the value computed by the source-chain contract. They operate autonomously, do not coordinate with one another, and — critically — **never broadcast transactions or interact with blockchains beyond reading events**. Their sole responsibility is to attest to what they have observed.
* The **relayer** collects these signed batches from validators, aggregates enough signatures to meet the threshold, and submits a relay transaction to the destination chain. The relayer does not verify correctness itself; all verification and enforcement happen inside the bridge contracts via deterministic hash-chain reconstruction and threshold signature validation.

This separation ensures that validators cannot influence on-chain execution, and the relayer cannot forge or alter cross-chain state. Together, these roles create a robust, trust-minimized architecture where correctness is guaranteed by the smart contracts, not by assumptions about the behavior of off-chain actors.

### Signed Batches and What Validators Actually Sign

Once a validator has confirmed that its locally reconstructed root matches the root computed and stored by the contract, it does **not** sign each individual operation. Instead, the validator:

1. Continues processing all new bridge operations in order, updating its local view of: a. the current nonce, and b. the current hash-chain root.
2. When it is time to produce a signature (e.g., at the end of a block or after some fixed number of operations), it **signs only the latest/top root**.

Along with this signature, the validator provides the relayer with a **batch of payloads** that led to this top root. This is referred to as a **signed batch**:

* the **signature** is over the top root value
* the **batch** contains all bridge operations that were applied to reach that root (e.g., all 10 deposits in a block, with their nonces and payloads).

In other words, the validators sign the **final state commitment** (top root), and accompany it with the **full ordered list of operations** that explain how they got there.

If at any point a validator's reconstructed root does not match the on-chain root, the validator:

* detects this as a critical inconsistency,
* **stops processing any new incoming bridge events** for that specific bridge direction, and
* refrains from producing any further signatures for that instance to avoid propagating incorrect state.

## Relayer Aggregation and Submission

The relayer receives these signed batches from multiple validators. For a specific token direction or message direction, it:

1. Collects signatures over the same top root (and corresponding nonce),
2. Ensures that it has enough signatures to meet the threshold required by the **BridgeManagement** contract on the destination chain,
3. Constructs a **relay transaction** that includes:
   * the signed top root,
   * the list of all operations in the batch (their nonces, payloads, and any metadata),
   * the aggregated validator signatures.

The relayer's job is strictly for transport and aggregation. It does not need to trust or interpret state — correctness will be fully enforced on-chain.

## What Happens on the Destination Chain

When the relayer submits a signed batch to the destination chain, the bridge contract must determine whether the batch represents a valid continuation of the hash chain for that specific bridge direction. To do this, the contract performs a series of strict checks that ensure ordering, integrity, and validator consensus before any state is updated or any token or message effects are applied.

### 1. Verify Sequential Nonces

the bridge contract reads its currently stored last nonce for the given token direction or message direction and checks that all payloads in the batch are **strictly consecutive**:

```
payload[0].nonce == lastNonce + 1
payload[1].nonce == lastNonce + 2
...
payload[n-1].nonce == lastNonce + n
```

If there is any gap, duplicate, or non-monotonic increment, the entire batch is rejected.

### 2. Recompute the New Top Root

Using the contract's current stored `lastRoot`, the bridge contract iterates through the batch and reconstructs the next root:

```
currentRoot = lastRoot
for each payload:
  operationHash = keccak256(payload)
  currentRoot = keccak256(currentRoot || operationHash)
```

The final `currentRoot` is the expected **new top root**.

### 3. Compare the Recomputed Root With the Provided Top Root

The bridge contract checks:

```
reconstructedRoot == providedRoot
```

If these differ, the batch is rejected immediately.

This ensures the batch exactly reflects the state that validators attested to.

### 4. Verify Validator Signatures (via BridgeManagement)

Only after verifying:

* nonce progression
* root reconstruction
* root consistency

does the bridge contract invoke **BridgeManagement** to verify validator signatures.

The BridgeManagement performs a simple threshold signature check. It does not inspect payloads, roots, or nonces — it only verifies whether enough validators signed the provided message.

The bridge contract defines the exact message that must be signed (the new root). Validators sign this message only after confirming it matches the source-chain contract's result. The relayer forwards these signatures, and the BridgeManagement simply checks whether a sufficient number of validators have signed the expected message. If the threshold is met, signature validation succeeds; otherwise, the batch is rejected.

## Verifying Authenticity Across Chains

This design makes the entire bridging process transparent and independently verifiable. Because each token direction and message direction maintains its own strictly ordered hash chain, an external observer only needs two pieces of information to validate the full bridging history:

* the **top nonce** for that bridge direction, and
* the **top root** stored on each chain.

For any bridge identity (token A deposits, token B withdrawals, message N3 → Neo X, etc.), the source-chain contract emits and stores the definitive (nonce, root) after every operation. The destination-chain bridge contract will only update its own (nonce, root) to match this value if:

* all intermediate payloads were provided,
* nonces progressed strictly one-by-one,
* the reconstructed root matches exactly the validator-signed root, and
* enough validators signed that root according to the threshold.

The result is simple but powerful:

> **If the top nonce and top root for a given bridge direction match on both chains, the entire bridging history is guaranteed to match as well.** Any deviation at any point — skipped operation, tampered payload, reordered event, faulty signature — would cause the roots to diverge permanently.

No trusted off-chain audit is required. Anyone can independently reconstruct the hash chain from on-chain events, recompute the sequence, and verify that both chains reflect the same authenticated history.

This property ensures that correctness, transparency, and integrity are not assumptions — they are cryptographically enforced guarantees rooted in the smart contracts themselves.

### Note on Temporary Root Divergence Between Chains

It is normal and expected that the destination chain may temporarily lag behind the source chain. When a new operation is executed on the source chain, the source-side bridge contract updates its nonce and root immediately. The destination-side bridge contract, however, can only advance once all required payloads with the appropriate validator signatures have been relayed.

During this period, the destination chain’s nonce will be **strictly lower** than the source chain’s nonce, and its root will simply reflect the **earlier** top root associated with that nonce. This does **not** indicate an inconsistency — it only means the latest operation is still in transit. Once the relayer provides the necessary data, the destination chain will advance and both chains’ top (nonce, root) pairs will realign exactly.

### Note on Historical Hash-Chain Changes

Earlier versions of the bridge contracts used **SHA-256** for computing operation hashes and hash-chain roots, because **keccak256 was not yet available on Neo N3** at the time the initial TokenBridge contract was deployed. Since both chains must always use the same hashing algorithm to reproduce the hash chain deterministically, the Neo X contracts used SHA-256 as well.

Once keccak256 became available on N3, the bridge contracts on **both chains** were upgraded and the hashing algorithm was unified to **keccak256**.

This means:

* hash-chain roots before the upgrade were derived using SHA-256,
* and all roots produced after the upgrade use keccak256.

The transition was performed as part of a contract upgrade. From that point onward, both chains have used the same keccak256-based hashing logic. The verification process described in this document is identical for both versions; the only difference is which hash function is applied for a given historical range.


# Node Requirements

The validator–relayer setup is intentionally decoupled to minimize trust assumptions and reduce attack surface.\
Validators are isolated entities that observe events and produce signed state commitments, while the relayer aggregates these signatures and submits relay transactions to the destination chain.

This document specifies the **software architecture** and the **infrastructure requirements** for running validator and relayer nodes.

***

## 1. Software Architecture Overview

### 1.1 Validator Backend

Validators operate as isolated, non-interactive observers. They:

* listen to bridge smart contract events on the source chain,
* reconstruct the hash-chain state and confirm correctness,
* sign the resulting top root using a locally stored private key,
* forward the signed batch (root + payloads) to the relayer through an internal message broker.

**Validators MUST NOT:**

* broadcast transactions on any blockchain,
* expose signing keys or accept inbound external connections,
* coordinate with other validators.

Each validator acts independently and does not communicate with other validators.

***

### 1.2 Relayer Backend

The relayer aggregates validator signatures and constructs the relay transaction. It:

* listens for incoming signed batches from validators,
* collects enough signatures to satisfy the threshold enforced by BridgeManagement on the destination chain,
* assembles a relay transaction containing:
  * the signed top root,
  * all associated batch payloads,
  * the validator signatures,
* submits the transaction to the destination-chain bridge contract.

The relayer **does not verify correctness** of the batch. All verification is performed on-chain through:

* sequential nonce checks,
* hash-chain reconstruction,
* top-root comparison,
* and threshold signature verification via BridgeManagement.

A single relayer instance is sufficient, but redundant failover instances are recommended for availability.

***

## 2. Infrastructure Requirements

### 2.1 Compute Infrastructure

The recommended baseline infrastructure is:

#### Message Broker

* 1 internal message broker (e.g., RabbitMQ, ZeroMQ, Redis Streams)
* Runs on-premise or within a protected network segment
* Serves as the communication channel between validators and relayer

#### Relayer Nodes

* 1 active relayer backend
* 1 optional failover relayer backend
* Each with:
  * 4 GB RAM
  * 2 CPU cores
* Nodes must reside inside the protected VLAN

#### Validator Nodes

* 7 validator backends (or parameterized by governance)
* Each with:
  * minimum 1 GB RAM
  * 1 CPU core
* Each validator must run on an independently controlled machine or VM\
  (no shared IPs, providers, infrastructure)

Validators must be isolated from one another to prevent correlated failures.

***

### 2.2 Network Infrastructure

#### Internal Network

* 1 dedicated VLAN containing:
  * all validator nodes,
  * relayer nodes,
  * the message broker.

#### Security Constraints

* Private IP addresses across the VLAN
* **Deny-all inbound firewall rule** from external networks
* Only outbound access to blockchain RPC endpoints is permitted
* No inbound connectivity allowed to validator nodes
* Validator keys must never be exposed through RPC or remote signing services

This network design ensures validators cannot be externally reached or probed, while allowing only the relayer and message broker to communicate internally.

***

## 3. Summary of Requirements

### Validators

* Observe chain events
* Reconstruct hash-chain state
* Sign the top root only
* Never send transactions on-chain
* Must operate in isolated, secure environments

### Relayer

* Aggregates validator signatures
* Submits relay transactions
* Runs in a protected internal network
* May be deployed with failover redundancy

### Infrastructure

* Dedicated VLAN
* On-premise or protected message broker
* Strict firewall isolation
* Distributed validator nodes on separate machines/providers


# Token Bridge

The TokenBridge is the on-chain component responsible for securely transferring tokens between Neo N3 and Neo X. It processes token deposits and withdrawals, locks or releases assets accordingly, and maintains a per-token, per-direction hash chain that records the ordered history of all token-bridging operations.

Each token direction (N3 → Neo X and Neo X → N3) has its own independent `(nonce, root)` state. This state provides a verifiable cryptographic commitment to all operations processed in that direction. Validators observe these events, reconstruct the hash-chain state, and attest to the new top root, enabling the relayer to submit authenticated batches to the destination chain.

By enforcing deterministic hash-chain reconstruction and requiring validator threshold signatures, the TokenBridge ensures that all token transfers across chains occur transparently, securely, and without relying on any trusted off-chain party.


# Technical Flow

Here is a breakdown of the technical steps involved in transferring GAS between Neo N3 and Neo X.

## **Bridge GAS from Neo N3 to Neo X**

**Neo N3：**

1. Send GAS to Bridge Contract including valid data (recipient address on Neo X).
2. Bridge Contract on-chain:
   1. Validate the data.
   2. Increment nonce.
   3. Calculate the new deposit hash (including `nonce, recipient, amount`).
   4. Calculate the new root of the Hash Chain.
   5. Set the new root.
   6. (Send GAS to treasury)
   7. Emit the event with `nonce, recipient, amount, from, deposit hash, new root.`

**Validators:**

1. Listen and notice new deposit event.
2. Sign new root and send signature to relayer node.

**Relayer:**

1. Receive the transaction hash and signature from validators.
2. Validate the signatures with event data, based on application log of transaction.
3. Collect 5 signatures for this event (5 = threshold of validator multi-sig).
4. Invoke Neo X Bridge Contract with provided validator signatures, deposit data, and root.

**Neo X** (Bridge Contract):

1. Check that relayer is sender.
2. Hash the deposit data and validate the validator signatures.
3. Calculate the new deposit hash.
4. Calculate the new root (based on the current root).
5. Verify with provided root.
6. Transfer GAS for recipient address.
7. Emit a transfer event.

## **Bridge GAS from Neo X to Neo N3**

**Neo X:**

1. Send GAS to Bridge Contract including valid data (recipient address on N3).
2. Bridge Contract on-chain:
   1. Validate the data. (incl. verifying that the provided amount is greater or equal to the sent msg.value)
   2. Increment nonce.
   3. Calculate the new withdrawal hash (including `nonce, recipient, amount`).
   4. Calculate the new root.
   5. Set the new root.
   6. Emit the event with `nonce, recipient, amount, from, withdrawal hash, new root`

**Validators:**

1. Listen and notice new withdrawal event.
2. Sign the new root and send the signature to relayer node.\*

**Relayer:**

1. Receive the transaction hash and signature from validators.
2. Validate the signatures with event data, based on application log of transaction.
3. Collect 5 signatures for this event (5 = threshold of validator multi-sig).
4. Invoke N3 Bridge Contract with provided validator signatures, withdrawal data and root.

**Neo N3** (Bridge Contract):

1. Check that relayer is sender.
2. Hash deposit data and validate validator signatures OR check witness of validator multi-sig (probably unfeasible with current responsibilities).
3. Calculate new withdrawal hash.
4. Calculate new root.
5. Verify with provided root.
6. Transfer GAS to recipient address.

\* The validator node needs a specific rule for when to sign and send signatures to the relay node. The contract will support multiple deposits/withdrawals in a single transaction. If multiple bridge interactions (deposits or withdrawals) occur within a single block, the validator can concatenate their roots (in nonces order) and sign this concatenated value (i.e., the top root). Since a "batched" transaction cannot hold an unlimited size, the configuration on-chain holds a value `maxDeposits` (or `maxWithdrawals`, respectively) that define how many deposits can be sent in a batch. This leads to the current consensus of when and what to sign across validators:

Whenever there's a bridge operation in a block, the validators will create a signature of it. If there are multiple operations in a block, the validators will sign the root of the operation with the highest nonce (the top root). If there are more than the specified `maxDeposits` in a single block, the validators will sign the root of each `maxDeposits`' deposit. That way the validators "reach" consensus and provide signatures of the same root to the relayer.


# Message Bridge

The MessageBridge enables the secure relay of arbitrary data between Neo N3 and Neo X. Instead of transferring tokens, it transports raw message payloads submitted by contracts or users, while preserving ordering, authenticity, and verifiability.

As with the TokenBridge, each message direction (N3 → Neo X and Neo X → N3) maintains its own independent hash chain. Every message extends this chain, producing a new `(nonce, root)` commitment that validators reconstruct and sign. These signed commitments allow the relayer to submit authenticated message batches to the destination chain, where they are verified and persisted.

Through its hash-chain mechanism and validator-attested batches, the MessageBridge provides the same security guarantees for arbitrary data as the TokenBridge provides for token transfers. This ensures that cross-chain messaging remains transparent, ordered, and cryptographically verifiable.

The following sections and [Neo X's bridge SDK](https://github.com/bane-labs/bridge-sdk-ts) will help you to understand and build with this unique infrastructure step by step. For more detailed examples, please refer to the [MessageBridge Examples Repository](https://github.com/AxLabs/bridge-examples-ts).


# EVM to N3

This document details the complete flow for sending messages from Neo X (an EVM blockchain) to N3 using the example scenario of querying a Neo token's balance on N3 from the EVM chain and receiving the result back.

## Overview

The message bridge allows EVM applications to execute operations on N3 and receive results backa.

This is accomplished by serializing a function call and sending the encoded bytes to the EVM message bridge contract. The [decoupled relayer](https://github.com/bane-labs/docs/tree/main/bridge/general/bridging-transparency-and-verifiable-relaying.md#decoupled-validator--relayer-architecture-summary) then ensures safe transfer of the data to N3. Once the data has been bridged, the message can be executed on N3 and its result may be returned.

The EVM to N3 flow allows EVM-based applications to execute operations on the N3 blockchain and optionally receive results back. This is accomplished through a message bridge system that serializes calls, sends them across chains, executes them on the N3 chain, and returns the results.

## Complete Flow Steps

### Step 1: Prepare the Serialized N3 Method Call

First, you prepare the serialized method call on the N3 side using the N3 MessageBridge contract:

```java
Hash160 targetAccount = new Hash160("0xabcdefabcdefabcdefabcdefabcdefabcdefabcd");
// This encodes a call to the NEO token contract's "balanceOf" method for a target contract.
byte[] serializedN3MethodCall = n3MessageBridge.getSerializedN3MethodCall(
    NeoToken.SCRIPT_HASH,          // Target contract (NEO token)
    "balanceOf",                   // Method to call
    CallFlags.READ_ONLY,           // Call flags (read-only)
    List.of(targetAccount)         // Arguments (the account whose balance you want)
);
```

This method returns a serialized byte array that represents the N3 method call.

### Step 2: Send Executable Message from EVM

On the EVM side, you send the serialized method call as an executable message:

```javascript
const storeResult = true;
const sendingFee = ethers.parseEther("0.1"); // The sending fee
evmMessageBridge.sendExecutableMessage{value: sendingFee}(rawMessage, storeResult);
```

* `rawMessage`: The serialized N3 method call, i.e., the output `serializedN3MethodCall` above.
* `storeResult`: Once the message is executed, the result of the execution should be stored on-chain, so that it can be returned to the EVM chain if needed. If set to `false`, the result will not be stored. The result will be included in an event that is fired when executing regardless of this value.
* `sendingFee`: The fee required for sending a message to N3.

This creates an **EXECUTABLE** type message with:

* **Message Type**: `0` (EXECUTABLE)
* **Timestamp**: Current EVM block time
* **Sender**: The message sender (i.e., `msg.sender`) sending the message
* **Store Result Flag**: `true` (result should be stored on-chain on N3)
* **Payload**: The N3 method call data

The message will be assigned a number (a `nonce`). You can get it by checking the events of the transaction for the event `MessageSent`.

### Step 3: Message Relay to N3

In this step, you need to wait until the decoupled relayer has transferred the message to the EVM chain. This should only take a couple of seconds.

You can listen to the `Store` event emitted by the N3 MessageBridge contract. The first argument in the event is the message nonce. Once the event appears, your message has been transferred to N3 and is now ready to be executed.

### Step 4: Message Execution on N3

Once the message has been stored on the EVM chain, the message can be executed by anyone calling `executeMessage(int)` with the message nonce as paramter:

```java
TransactionBuilder b = n3MessageBridge.invokeFunction("executeMessage", integer(nonce));
Transaction transaction = b.signers(AccountSigner.calledByEntry(myAccount)).sign();
NeoSendRawTransaction response = transaction.send();
Await.waitUntilTransactionIsExecuted(response.getSendRawTransaction().getHash(), neow3j);
```

Executing a message will emit the following:

1. `Execute` with parameters `Nonce` and `Metadata` emitted by the MessageBridge contract.
2. Potential events based on the N3 method call. In this example, there's no events emitted as the `balanceOf` method call is a read-only invocation.
3. `ExecutionResult` with parameters `Nonce` and `Result` emitted by the MessageBridge contract.

The result is emitted in deserialized form as it was returned from the method call.

### Step 5: Verify Execution Results

After execution, you can verify the execution results on N3:

```java
List<StackItem> items = n3MessageBridge.callInvokeFunction("getExecutableState", asList(integer(nonce))).getInvocationResult()
                .getFirstStackItem().getList();

boolean executed = items.get(0).getBoolean();
BigInteger expirationTime = items.get(1).getInteger();

// Get the actual result
byte[] serializedResult = n3MessageBridge.callInvokeFunction("getResult", asList(integer(nonce))).getInvocationResult()
                .getFirstStackItem().getByteArray();
```

Note that the result returned from `getResult` is serialized using the native `StdLib` contract's `serialize()` function. You can use its function `deserialize()` to get the deserialized stack items. It is up to the caller to interpret the result accordingly.

### Step 6: Return Result back to EVM

> This and the following steps are only needed if you want to return the result to the EVM chain.

In order to send a result back, you can call the `sendResultMessage(nonce)` function:

```java
TransactionBuilder b = n3MessageBridge.invokeFunction("sendResultMessage", integer(messageNonce), hash160(feePayer), integer(maxFee));
Transaction transaction = b.signers(AccountSigner.calledByEntry(myAccount)).sign();
NeoSendRawTransaction response = transaction.send();
Await.waitUntilTransactionIsExecuted(response.getSendRawTransaction().getHash(), neow3j);
```

This will send the result back to the EVM chain in form of a normal message sent from N3 to EVM. It will get a new nonce. You can check the `MessageSend` event of the transaction to get this message nonce.

### Step 7: Message Relay back to EVM

Now, the decoupled relayer transferres the response message back to the EVM chain. Take the message nonce from the returning message (i.e., the one from the `MessageSend` event in Step 6) and wait for the `MessageDeposit` event on the MessageBridge contract on EVM that has this nonce.

In this step, the message bridge is used in the reverse direction from N3 to the EVM chain. As in Step 3, you will need to wait until the decoupled relayer has transferred the message to the EVM chain.

Once the result is transferred, it can be read on the EVM chain.

## Example Implementation (JavaScript)

```javascript
const {ethers} = require('ethers');

// Define the target contract address and the account address to check the balance for.
const neoTokenContractAddress = "0xef4073a0f2b305a38ec4050e4d3d28bc40ea63f5"; // Neo token address on N3
const targetAddress = "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd"; // Address to check the balance for

async function exampleFunc() {
  // Assume evmMessageBridge and n3MessageBridge are already instantiated contract objects
  
  // Serialize an N3 method call using the N3 MessageBridge
  const rawMessage = await n3MessageBridge.serializeCall(
      neoTokenContractAddress, // Target contract (NEO token)
      'balanceOf', // Method to call
      15, // CallFlags.ALL - can be adjusted as needed
      [targetAddress] // Arguments
  );
  // const rawMessage = "0x400428141418e358c565207768eae8d237241e85d3e9f1cb280573746f72652101024002210101210440a87c68"; // Example serialized message

  const storeResult = true;
  let sendingFee = ethers.parseEther("0.1");
  const nonce = await evmMessageBridge.connect(evmSender)
    .sendExecutableMessage(rawMessage, storeResult, {value: sendingFee, maxFeePerGas, maxPriorityFeePerGas});

  // Wait until the message arrives on N3...

  // Execute message on N3 using Javascript
  await n3MessageBridge.executeMessage(nonce);

  // Send the result back from N3 to EVM
  sendingFee = await n3MessageBridge.sendingFee();
  const params: SendResultMessageParams = {
    nonce: nonce,
    maxFee: sendingFee
  };
  await n3MessageBridge.sendResultMessage(params);
}
```

## Visualization

```markdown
Java (or other N3 SDK) for building the N3 method call
┌────────────────────────────────────────────────────────────────┐
│ Hash160 target = NeoToken.SCRIPT_HASH;                         │
│ String method = "balanceOf";                                   │
│ CallFlags callFlags = CallFlags.READ_ONLY                      │
│ Hash160 account = new Hash160("");                             │
│ ContractParameter args = array(hash160(account));              │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼ n3MessageBridge.serializeN3MethodCall(target, method, callFlags, args)
┌────────────────────────────────────────────────────────────────┐
│ Serialized N3 Message                                          │
│ 0x400428141418e358c565207768ea...0101210440a87c68...           │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼ Send the message on EVM
┌────────────────────────────────────────────────────────────────┐
│ evmMessageBridge.sendExecutableMessage(bytes, bool)            │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼ Cross-chain relay - then execute on N3
┌────────────────────────────────────────────────────────────────┐
│ n3MessageBridge.executeMessage(nonce)                          │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼ Return the result to EVM
┌────────────────────────────────────────────────────────────────┐
│ n3MessageBridge.sendResultMessage(nonce, feePayer, sendingFee) │
└────────────────────────────────────────────────────────────────┘
```

This completes the full EVM to N3 flow showing how to properly prepare the method call data using the message bridge contract, sending it, executing it on N3 and then sending the results back.


# N3 to EVM

This document details the complete flow for sending messages from N3 to Neo X (EVM blockchain) using the example scenario of querying a Neo token's balance on EVM from N3 and receiving the result back.

## Overview

The message bridge allows N3 applications to execute operations on EVM-based blockchains and receive results back.

This is accomplished by encoding an `AMBTypes.Call` struct and sending the encoded bytes to the N3 message bridge contract. The [decoupled relayer](https://github.com/bane-labs/docs/tree/main/bridge/general/bridging-transparency-and-verifiable-relaying.md#decoupled-validator--relayer-architecture-summary) then ensures safe transfer of the data to the EVM chain. Once the data has been bridged, the message can be executed on the EVM chain and its result may be returned.

> Currently, BaneLabs does not provide a service to execute messages. In future versions execution rewards might be added to messages, so that users can attach an incentive for anyone active on the destination network to execute a message for them.

## Complete Flow Steps

In the following we'll use an example call to elaborate on the flow. For simplicity, let's assume we want to get the Neo balance of an account on Neo X.

> As the bridging process is an asynchronous process, fetching a value that can be fluctuent like a Neo balance might not be the most intuitive use case. However, for the purpose of this example it should sufficiently elaborate on the steps required to use the message bridge.

### Step 1: Prepare the EVM Call Structure

First, prepare the EVM call by creating an `AMBTypes.Call` structure on the N3 side using the ethers library for proper ABI encoding:

```javascript
const { ethers } = require('ethers');

// Define the Neo token contract address on EVM and target address
const neoTokenContractAddress = "0xc28736dc83f4fd43d6fb832Fd93c3eE7bB26828f"; // Neo token address on Neo X Testnet
const targetAddress = "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd"; // Address to check the balance for

// Create the interface for ERC20 balanceOf function
const erc20Interface = new ethers.Interface([
    "function balanceOf(address account) view returns (uint256)"
]);

// Encode the balanceOf function call
const callData = erc20Interface.encodeFunctionData("balanceOf", [targetAddress]);
console.log("Encoded balanceOf callData:", callData);
// Output: 0x70a08231000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd

// Create the EVM Call structure (equivalent to AMBTypes.Call)
const evmCall = {
    target: neoTokenContractAddress,    // Target EVM Neo token contract
    allowFailure: false,                // Don't allow failure
    value: 0,                           // No gas value needed for the call
    callData: callData                  // Encoded balanceOf(address) call data
};

// Serialize the entire Call structure using ethers ABI encoder
const callStructAbi = [
    "tuple(address target, bool allowFailure, uint256 value, bytes callData)"
];
const abiCoder = new ethers.AbiCoder();
const serializedMessage = abiCoder.encode(callStructAbi, [evmCall]);

console.log("Serialized Call message:", serializedMessage);
```

### Step 2: Send Executable Message from N3

Send the EVM call as an executable message from N3 (Java example code):

```java
// Get the fee for sending a message across the bridge.
BigInteger sendingFee = n3MessageBridge.callFunctionReturningInt("sendingFee");
// Build the transaction to send the executable message to Neo X using the sendingFee as maximal allowed fee and your account as bridge fee payer.
TransactionBuilder b = n3MessageBridge.invokeFunction("sendExecutableMessage", byteArray(rawMessage), bool(storeResult), hash160(myAccount), integer(sendingFee));
Transaction transaction = b.signers(AccountSigner.calledByEntry(myAccount)).sign();
NeoSendRawTransaction response = transaction.send();
Await.waitUntilTransactionIsExecuted(response.getSendRawTransaction().getHash(), neow3j);
```

**Parameters:**

* `rawMessage`: The encoded EVM contract call data, i.e., the output `serializedMessage` above.
* `true`: Once the message is executed, the result of the execution should be stored on-chain, so that it can be returned to N3 if needed. If set to `false`, the result will not be stored. The result will be included in an event that is fired when executing regardless of this value.

This creates an **EXECUTABLE** type message with:

* **Message Type**: `0` (EXECUTABLE)
* **Timestamp**: Current N3 block time
* **Sender**: The N3 contract/account sending the message
* **Store Result Flag**: `true` (result should be stored on-chain on Neo X)
* **Payload**: The EVM contract call data

The message will be assigned a number (a `nonce`). You can get it by either reading the remaining stack item of the transaction (the nonce is returned by the `sendExecutableMessage()` function), or you can check the events of the transaction for the event `MessageSend`.

```java
ApplicationLog log = transaction.getApplicationLog();
BigInteger messageNonce = log.getFirstExecution().getFirstStackItem().getInteger();
```

### Step 3: Message Relay to the EVM Chain

In this step, you need to wait until the decoupled relayer has transferred the message to the EVM chain. This should only take a couple of seconds.

You can listen to the `MessageDeposit` event emitted by the MessageBridge contract. The first argument in the event is the message nonce. Once the event appears, your message has been transferred to the EVM chain and is now ready to be executed.

### Step 4: Message Execution on EVM

Once the message has been stored on the EVM chain, the message can be executed by anyone calling `executeMessage(uint256)` with the message nonce as parameter:

```javascript
// Anyone can execute a stored message by providing its nonce
await evmMessageBridge.executeMessage(nonce);
```

### Step 5: Verify Execution Results

After execution, you can verify the execution results on EVM:

```javascript
const { success, returnData } = await messageBridge.getResult(nonce);
```

> If the message's `storeResult` was set to `false` when sending it, the result is only accessible in the `MessageExecuted` event emitted when the message was executed.

### Step 6: Return Result back to N3

> This and the following steps are only needed if you want to return the result to N3.

In order to send a result back, you can call the `sendResultMessage(uint256)` function:

```javascript
await evmMessageBridge.sendResultMessage(nonce);
```

This will send the result back to N3 in form of a normal message sent from EVM to N3. It will get a new nonce. You can check the `MessageSent` event of the transaction to get this message nonce.

### Step 7: Message Relay back to N3

Now, the decoupled relayer transferres the response message back to N3. Take the message nonce from the returning message (i.e., the one from the `MessageSent` event in Step 6) and wait for the `Store` event on the MessageBridge contract on N3 that has this nonce.

In this step, the message bridge is used in the reverse direction from the EVM chain to the N3 chain. As in Step 3, you now need to wait until the decoupled relayer has transferred the message to N3. The event emitted when messages are transferred is `Store` and its first state entry is the nonce.

Once the result is transferred, it can be read on-chain on N3.

## Example Implementation (JavaScript)

```javascript
const {ethers} = require('ethers');

// Define the Neo token contract address on EVM and target address
const neoTokenContractAddress = "0xc28736dc83f4fd43d6fb832Fd93c3eE7bB26828f"; // Neo token address on Neo X Testnet
const targetAddress = "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd"; // Address to check the balance for

// Create the interface for ERC20 balanceOf function
const erc20Interface = new ethers.Interface([
  "function balanceOf(address account) view returns (uint256)"
]);

async function exampleFunc() {
  const encodedMessage = getEncodedBalanceOfCall("0xc28736dc83f4fd43d6fb832Fd93c3eE7bB26828f",
      "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd");

  // Send message on N3 using Javascript
  const sendingFee = await messageBridge.sendingFee();
  const params: SendExecutableMessageParams = {
    encodedMessage,
    true, // storeResult
    maxFee: sendingFee
  };
  await messageBridge.sendExecutableMessage(params)

  // Wait until the message arrives on the EVM chain...

  // Once the message has been bridged over to the EVM chain, you can execute it
  await evmMessageBridge.connect(sender).executeMessage(nonce, {maxFeePerGas, maxPriorityFeePerGas});

  // If the result should be stored on-chain, you can return the result now.
  await evmMessageBridge.connect(sender).
      sendResultMessage(nonce, {value: sendingFee, maxFeePerGas, maxPriorityFeePerGas});
}

function getEncodedBalanceOfCall(tokenAddress, targetAddress) {
  // Encode the balanceOf call using ethers
  const erc20Interface = new ethers.Interface(["function balanceOf(address account) view returns (uint256)"]);
  const callData = erc20Interface.encodeFunctionData("balanceOf", [targetAddress]);

  // Create the Call structure
  const evmCall = {
    target: tokenAddress,
    allowFailure: false,
    value: 0,
    callData: callData
  };

  // Serialize the Call structure
  const callStructAbi = ["tuple(address target, bool allowFailure, uint256 value, bytes callData)"];
  const abiCoder = new ethers.AbiCoder();
  const serializedMessage = abiCoder.encode(callStructAbi, [evmCall]);

  return {
    serializedMessage: serializedMessage,
    callData: callData,
    evmCall: evmCall
  };
}

function decodeBalanceResult(resultData) {
  // Decode the uint256 balance result
  const abiCoder = new ethers.AbiCoder();
  const balance = abiCoder.decode(["uint256"], resultData)[0];
  return balance;
}
```

## Visualization

```markdown
JavaScript + ethers for building the EVM call
┌─────────────────────────────────────────────────────────┐
│ const evmCall = {                                       │
│   target: "0x1234...7890",  // Neo token contract       │
│   allowFailure: false,                                  │
│   value: 0,                                             │
│   callData: "0x70a08231000...abcdef"  // balanceOf()    │
│ };                                                      │
└─────────────────────────────────────────────────────────┘
                              │
                              ▼ ethers.AbiCoder.encode()
┌─────────────────────────────────────────────────────────┐
│ Serialized Message (hex string)                         │
│ 0x0000002000000000000000001234...7890000000000000...    │
└─────────────────────────────────────────────────────────┘
                              │
                              ▼ Send the message on N3
┌─────────────────────────────────────────────────────────┐
│ messageBridge.sendExecutableMessage(bytes, bool)        │
└─────────────────────────────────────────────────────────┘
                              │
                              ▼ Cross-chain relay - then execute on EVM
┌─────────────────────────────────────────────────────────┐
│ messageBridge.executeMessage(nonce)                     │
└─────────────────────────────────────────────────────────┘
                              │
                              ▼ Return the result to N3
┌─────────────────────────────────────────────────────────┐
│ messageBridge.sendResultMessage(nonce)                  │
└─────────────────────────────────────────────────────────┘
```

This completes the full N3 to EVM flow showing how to properly prepare the call data using the ethers library for encoding the `AMBTypes.Call` structure and `balanceOf` method call, serializing it, sending it, executing it, and then sending the results back to N3.


# Quick Start: Bridging Assets

This guide helps users quickly move GAS or any NEP-11 tokens from Neo N3 to Neo X, or vice versa, using the Neo X bridge.

We will walk you through the entire process, explaining each step in depth. If you get stuck at any point, feel free to reach out to us on [Discord](https://discord.gg/neosmarteconomy) for assistance.

## Prerequisites

1. To get started quickly, you need to have:
   * A web3 wallet installed, such as [Neoline](https://neoline.io/en/) or [Metamask](https://metamask.io/download/). If you don't have one, visit the link to download.
   * Some GAS on Neo N3. There are several ways to acquire *GAS* :
     * Use a supported centralized exchange like Binance or OKX, which allows you to buy *GAS* and withdraw it to your wallet. Most major centralized exchanges support direct withdrawal from your centralized exchange wallet to Neo N3
     * Request funds from a faucet for [Testnet N3T5](https://n3t5wish.ngd.network/#/), if you are using a testnet
2. Access the appropriate URL based on the network you are connecting to. These will be referenced in the following steps.
   * **Mainnet**
     * Neo X Bridge: <https://xbridge.neo.org/>
     * Neo X's Explorer: <https://xexplorer.neo.org/>
   * **Testnet**
     * Neo X Bridge: <https://testnet.bridge.banelabs.org/>
     * Neo X's Explorer: <https://xt4scan.ngd.network/>

## Depositing GAS (from Neo N3 to Neo X)

### **Step 1: Add the Neo X network to your Metamask**

You'll also need to add the Neo X's RPC endpoint to your wallet. Here we provide two ways for doing this using MetaMask.

* (Recommended) Click the button on the bottom-left of Neo X's Explorer to automatically add Neo X to MetaMask

<div align="left"><figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXe9s3hiBzPOnSMXqkE9cuJlMNMAP8_ntzMM5glMAQOu4EB3PLPzrTF2GdkQlLmZkPQB0noFrelAc5i_p6msxxxrcmRC0zBc9X4pf2vUP1Z1J3f7iSuiJVilC9_72LZ8iEn_4F1MALoMbPlc2JsVQTXaJRXV?key=Y_0tKG4RxtVCtlTsvrBZYw" alt=""><figcaption></figcaption></figure></div>

* On your browser, click on the MetaMask extension.
  1. Click the network selector drop-down on the top-left corner, and then click `Add Network`.
  2. Click `Add a network manually` and then provide the information corresponding to the chain you want to send your assets to.

The information about Neo X is listed as below:

<table><thead><tr><th width="180">Property</th><th width="275">Mainnet</th><th width="275">Testnet</th></tr></thead><tbody><tr><td>Network name</td><td>Neo X Mainnet</td><td>Neo X Testnet T4</td></tr><tr><td>RPC URL</td><td><a href="https://mainnet-1.rpc.banelabs.org">https://mainnet-1.rpc.banelabs.org</a></td><td><a href="https://neoxt4seed1.ngd.network">https://neoxt4seed1.ngd.network</a></td></tr><tr><td>Chain ID</td><td>47763</td><td>12227332</td></tr><tr><td>Currency symbol</td><td>GAS</td><td>GAS</td></tr><tr><td>Block explorer URL</td><td><a href="https://xexplorer.neo.org">https://xexplorer.neo.org</a></td><td><a href="https://xt4scan.ngd.network">https://xt4scan.ngd.network</a></td></tr></tbody></table>

### **Step 2: Initiate the deposit**

1. Go to the Neo X Bridge page.
2. Log in to the bridge with your wallet. Check that you're connected to Neo N3 and Neo X on the page for asset deposits.

   > Note: Neo X currently only supports the bridging of *GAS* .
3. Enter the amount of *GAS* you want to bridge over in the `From` box and then press `Deposit`. Follow the prompts on your Neo N3 wallet. You can also click `MAX` to deposit all *GAS* to Neo X.

   > **ENSURE SUFFICIENT GAS BALANCE** It is important to have enough GAS in your wallet to complete the transaction, or else the web3 wallet will not pop-up. When you click `MAX`, GAS for transaction fee will be remained.

It usually takes around 1-2 minutes (varying based on the chain congestion) for funds to transfer to Neo X after submitting the transaction from your Neo N3 wallet.

## Withdrawing *GAS* (from Neo X to Neo N3)

1. Log in to the Neo X Bridge page with your wallet. Check that you are connected to the source network (e.g., Neo X) and the destination network (e.g., Neo N3) shown at the top of the page.
2. Enter the amount of *GAS* you want to bridge over in the `From` box and then press `Withdraw`. Follow the prompts on your web3 wallet.

   > **ENSURE SUFFICIENT GAS BALANCE** It is important to have enough GAS in your wallet to complete the transaction, or else the web3 wallet will not pop-up.

It usually takes around 1-2 minutes (varying based on the chain congestion) for funds to transfer to Neo N3 after submitting the transaction from your Metamask.


# CCIP Bridge

Neo X has also imported [Chainlink CCIP](https://docs.chain.link/ccip) for bridging, delivering secure and reliable interoperability across [other blockchain networks](https://docs.chain.link/ccip/directory).

By harnessing CCIP’s decentralized messaging and token transfer, the bridge empowers developers to build cross‑chain applications that seamlessly connect with the broader Neo ecosystem.

### Supported Assets

<table><thead><tr><th width="150">Name</th><th width="100">Network</th><th width="500">Address</th></tr></thead><tbody><tr><td>WETH</td><td>Mainnet</td><td><a href="https://xexplorer.neo.org/address/0xCFB6EE7f9E42f4A3406221FA5B5578b026EB08Cf"><code>0xCFB6EE7f9E42f4A3406221FA5B5578b026EB08Cf</code></a></td></tr><tr><td></td><td>Testnet</td><td><a href="https://xt4scan.ngd.network/address/0x15908CEe8CF58E5d04a1854130f405026F26DE56"><code>0x15908CEe8CF58E5d04a1854130f405026F26DE56</code></a></td></tr><tr><td>USDC.e</td><td>Mainnet</td><td><a href="https://xexplorer.neo.org/address/0x028447684F3fFb6d27042D6c3Da7B088332c6576"><code>0x028447684F3fFb6d27042D6c3Da7B088332c6576</code></a></td></tr><tr><td></td><td>Testnet</td><td><a href="https://xt4scan.ngd.network/address/0x6bc037Fa5421d7E53dA211A548d6539CBe12c8f3"><code>0x6bc037Fa5421d7E53dA211A548d6539CBe12c8f3</code></a></td></tr></tbody></table>


# The Graph


# Introduction

Getting historical data on a smart contract can be frustrating when building a dapp. [The Graph](https://thegraph.com/) provides an easy way to query smart contract data through APIs known as subgraphs. The Graph’s infrastructure relies on a decentralized network of indexers, enabling your dapp to become truly decentralized. By supporting The Graph, dApps on Neo X can more easily access and query complex data stored on the blockchain.


# Quick Start

These subgraphs only take a few minutes to set up. To get started, follow these three steps:

1. Initialize your subgraph project
2. Deploy & Publish
3. Query from your dapp

Pricing: **All developers receive 100K free queries per month on the decentralized network**. After these free queries, you only pay based on usage at $4 for every 100K queries.

Here’s a step by step walk through:

### 1. Initialize your subgraph project

#### Create a subgraph on Subgraph Studio⁠

Go to the [Subgraph Studio](https://thegraph.com/studio/) and connect your wallet. Once your wallet is connected, you can begin by clicking “Create a Subgraph”. When choosing a name, it is recommended to use Title Case: “Subgraph Name Chain Name.”

![Create a Subgraph](https://lh7-us.googleusercontent.com/docsz/AD_4nXf8OTdwMxlKQGKzIF_kYR7NPKeh9TmWnZBYxb7ft_YbdOdx_VVtbp6PslN7N1KGUzNpIDCmaXppdrllM1cw_J4L8Na03BXOWzJTK1POCve0nkRjQYgWJ60QHAdtQ4Niy83SMM8m0F0f-N-AJj4PDqDPlA5M?key=fnI6SyFgXU9SZRNX5C5vPQ)

You will then land on your subgraph’s page. All the CLI commands you need will be visible on the right side of the page:

![CLI commands](https://lh7-us.googleusercontent.com/docsz/AD_4nXe3YvCxiOH_LupSWe8zh9AmP-VrV4PlOq3f7Ix6hNlBUYcANUFuLuVIWR74OGiBs0nrugTyT0v3o6RPmTsgHONdv_ZJNWtcDWEkRntXPHlQGFcqmEBa-D6j4aoIPzUKYdOJMVUPu8O3fwjdZ4IaXXZoTzY?key=fnI6SyFgXU9SZRNX5C5vPQ)

#### Install the Graph CLI⁠

On your local machine run the following:

```
npm install -g @graphprotocol/graph-cli
```

#### Initialize your Subgraph⁠

You can copy this directly from your subgraph page to include your specific subgraph slug:

```
graph init --studio <SUBGRAPH_SLUG>
```

You’ll be prompted to provide some info on your subgraph like this:

![cli sample](https://lh7-us.googleusercontent.com/docsz/AD_4nXdTAUsUb5vbs3GtCrhKhuXM1xYoqqooYTxw6lfJfYtLJNP8GKVOhTPmjxlM1b6Qpx-pXNVOzRuc8BL12wZXqy4MIj8ja0tp15znfuJD_Mg84SSNj3JpQ4d31lNTxPYnpba4UOzZx8pmgOIsbI7vCz70v9gC?key=fnI6SyFgXU9SZRNX5C5vPQ)

Simply have your contract verified on the block explorer and the CLI will automatically obtain the ABI and set up your subgraph. The default settings will generate an entity for each event.

### 2. Deploy & Publish

#### Deploy to Subgraph Studio⁠

First run these commands:

```bash
$ graph codegen
$ graph build
```

Then run these to authenticate and deploy your subgraph. You can copy these commands directly from your subgraph’s page in Studio to include your specific deploy key and subgraph slug:

```bash
$ graph auth --studio <DEPLOY_KEY>
$ graph deploy --studio <SUBGRAPH_SLUG>
```

You will be asked for a version label. You can enter something like v0.0.1, but you’re free to choose the format.

#### Test your subgraph⁠

You can test your subgraph by making a sample query in the playground section. The Details tab will show you an API endpoint. You can use that endpoint to test from your dapp.

![Playground](https://lh7-us.googleusercontent.com/docsz/AD_4nXf3afwSins8_eO7BceGPN79VvwolDxmFNUnkPk0zAJCaUA-3-UAAjVvrMzwr7q9vNYWdrEUNgm2De2VfQpWauiT87RkFc-cVfoPSsQbYSgsmwhyY1-tpPdv2J1H4JAMq70nfWBhb8PszZBFjsbDAaJ5eto?key=fnI6SyFgXU9SZRNX5C5vPQ)

#### Publish Your Subgraph to The Graph’s Decentralized Network

Once your subgraph is ready to be put into production, you can publish it to the decentralized network. On your subgraph’s page in Subgraph Studio, click on the Publish button:

![publish button](https://edgeandnode.notion.site/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Fa7d6afae-8784-4b15-a90e-ee8f6ee007ba%2F2f9c4526-123d-4164-8ea8-39959c8babbf%2FUntitled.png?table=block\&id=37005371-76b4-4780-b044-040a570e3af6\&spaceId=a7d6afae-8784-4b15-a90e-ee8f6ee007ba\&width=1420\&userId=\&cache=v2)

Before you can query your subgraph, Indexers need to begin serving queries on it. In order to streamline this process, you can curate your own subgraph using GRT.

When publishing, you’ll see the option to curate your subgraph. As of May 2024, it is recommended that you curate your own subgraph with at least 3,000 GRT to ensure that it is indexed and available for querying as soon as possible.

![Publish screen](https://lh7-us.googleusercontent.com/docsz/AD_4nXerUr-IgWjwBZvp9Idvz5hTq8AFB0n_VlXCzyDtUxKaCTANT4gkk-2O77oW-a0ZWOh3hnqQsY7zcSaLeCQin9XU1NTX1RVYOLFX9MuVxBEqcMryqgnGQKx-MbDnOWKuMoLBhgyVWQereg3cdWtCPcTQKFU?key=fnI6SyFgXU9SZRNX5C5vPQ)

> **Note:** The Graph's smart contracts are all on Arbitrum One, even though your subgraph is indexing data from Ethereum, BSC or any other [supported chain](https://thegraph.com/docs/en/developing/supported-networks/).

### 3. Query your Subgraph

Congratulations! You can now query your subgraph on the decentralized network!

For any subgraph on the decentralized network, you can start querying it by passing a GraphQL query into the subgraph’s query URL which can be found at the top of its Explorer page.

Here’s an example from the [CryptoPunks Ethereum subgraph](https://thegraph.com/explorer/subgraphs/HdVdERFUe8h61vm2fDyycHgxjsde5PbB832NHgJfZNqK) by Messari:

![Query URL](https://lh7-us.googleusercontent.com/docsz/AD_4nXebivsPOUjPHAa3UVtvxoYTFXaGBao9pQOAJvFK0S7Uv0scfL6TcTVjmNCzT4DgsIloAQyrPTCqHjFPtmjyrzoKkfSeV28FjS32F9-aJJm0ILAHey2gqMr7Seu4IqPz2d__QotsWG3OKv2dEghiD74eypzs?key=fnI6SyFgXU9SZRNX5C5vPQ)

The query URL for this subgraph is:

`https://gateway-arbitrum.network.thegraph.com/api/`**\[api-key]**`/subgraphs/id/HdVdERFUe8h61vm2fDyycgxjsde5PbB832NHgJfZNqK`

Now, you simply need to fill in your own API Key to start sending GraphQL queries to this endpoint.

#### Getting your own API Key

![API keys](https://lh7-us.googleusercontent.com/docsz/AD_4nXdz7H8hSRf2XqrU0jN3p3KbmuptHvQJbhRHOJh67nBfwh8RVnhTsCFDGA_JQUFizyMn7psQO0Vgk6Vy7cKYH47OyTq5PqycB0xxLyF4kSPsT7hYdMv2MEzAo433sJT6VlQbUAzgPnSxKI9a5Tn3ShSzaxI?key=fnI6SyFgXU9SZRNX5C5vPQ)

In Subgraph Studio, you’ll see the “API Keys” menu at the top of the page. Here you can create API Keys.

### Appendix

#### Sample Query

This query shows the most expensive CryptoPunks sold.

```graphql
{
  trades(orderBy: priceETH, orderDirection: desc) {
    priceETH
    tokenId
  }
}

```

Passing this into the query URL returns this result:

```
{
  "data": {
    "trades": [
      {
        "priceETH": "124457.067524886018255505",
        "tokenId": "9998"
      },
      {
        "priceETH": "8000",
        "tokenId": "5822"
      },
//      ...
```

💡 Trivia: Looking at the top sales on \[CryptoPunks website]\(<https://cryptopunks.app/cryptopunks/topsales>) it looks like the top sale is Punk #5822, not #9998. Why? Because they censor the flash-loan sale that happened.

#### Sample code

```jsx
const axios = require('axios');

const graphqlQuery = `{
  trades(orderBy: priceETH, orderDirection: desc) {
    priceETH
    tokenId
  }
}`;
const queryUrl = 'https://gateway-arbitrum.network.thegraph.com/api/[api-key]/subgraphs/id/HdVdERFUe8h61vm2fDyycHgxjsde5PbB832NHgJfZNqK'

const graphQLRequest = {
  method: 'post',
  url: queryUrl,
  data: {
    query: graphqlQuery,
  },
};

// Send the GraphQL query
axios(graphQLRequest)
  .then((response) => {
    // Handle the response here
    const data = response.data.data
    console.log(data)

  })
  .catch((error) => {
    // Handle any errors
    console.error(error);
  });
```

#### Additional resources:

* To explore all the ways you can optimize & customize your subgraph for a better performance, read more about [creating a subgraph here](https://thegraph.com/docs/en/developing/creating-a-subgraph/).
* For more information about querying data from your subgraph, read more [here](https://thegraph.com/docs/en/querying/querying-the-graph/).


# Oracles

Oracles are systems that enable smart contracts to access external data or events from outside the blockchain, such as web APIs, price feeds, or real-world information.

Check the available oracles below:

* [Supra](/integrations/oracles/supra)
* [Neo Oracle Gateway](/integrations/oracles/neo-oracle-gateway)


# Supra

[Supra](https://supra.com) is a novel, high-throughput Oracle & IntraLayer: A vertically integrated toolkit of cross-chain solutions (data oracles, asset bridges, automation network, and more) that interlink all blockchains, both public (L1s and L2s) and private (enterprises).

Supra provides decentralized oracle price feeds that can be used for both on-chain and off-chain use cases such as spot and perpetual DEXes, lending protocols, and payment protocols. Supra’s oracle chain and consensus algorithm make it the fastest-to-finality oracle provider, with layer-1 security guarantees. The pull oracle has a sub-second response time. In addition to speed and security, Supra’s rotating node architecture gathers data from 40+ data sources and applies a robust calculation methodology to obtain the most accurate value. The node provenance on the data dashboard also provides a fully transparent historical audit trail. Supra’s Distributed Oracle Agreement (DORA) paper was accepted into ICDCS 2023, the oldest distributed systems conference. Visit the [Supra documentation](https://docs.supra.com) to learn more details.

DORA Pull Oracle has been successfully deployed to Neo X:

<table><thead><tr><th width="150">Name</th><th width="100">Network</th><th width="500">Address</th></tr></thead><tbody><tr><td>Pull Contract</td><td>Mainnet</td><td>0x8B506d2616671b6742b968C18bEFdA1e665A9025</td></tr><tr><td></td><td>Testnet</td><td>0xc99c8510D9FF355CD664F9412bdD645c5e25a7f1</td></tr><tr><td>Storage Contract</td><td>Mainnet</td><td>0x58e158c74DF7Ad6396C0dcbadc4878faC9e93d57</td></tr><tr><td></td><td>Testnet</td><td>0x5df499C9DB456154F81121282c0cB16b59e74C4b</td></tr></tbody></table>

Fresh crypto information is then provided by the following deployed Chainlink AggregatorV3 interfaces:

Mainnet:

<table><thead><tr><th width="150">Data Pair</th><th width="100">Pair ID</th><th width="500">Address</th></tr></thead><tbody><tr><td>wBTC/USDT</td><td>166</td><td>0xBB0f96cede5728D69409340be459A864478e9222</td></tr><tr><td>WETH/USDT</td><td>211</td><td>0xd6869E35e568Aa6BF481Fda57ac38f7353AF596F</td></tr><tr><td>NEO/USDT</td><td>44</td><td>0x8fd2622c2CA0d7f8Bd0e2Ee98B143213dBcF4975</td></tr><tr><td>GAS/USDT</td><td>260</td><td>0xe38231C17771f02fEE44B5275B3625Bf67817120</td></tr></tbody></table>

T4 Testnet:

<table><thead><tr><th width="150">Data Pair</th><th width="100">Pair ID</th><th width="500">Address</th></tr></thead><tbody><tr><td>wBTC/USDT</td><td>166</td><td>0x99f4800f8958Caf403688b988f683188dF36CEaF</td></tr><tr><td>WETH/USDT</td><td>211</td><td>0xB29f673C3bA1657b2F0ef160dD60425deB67BD38</td></tr><tr><td>NEO/USDT</td><td>44</td><td>0xe027fE13ae0a9d302A1338b861de64EBb9c6b1b1</td></tr><tr><td>GAS/USDT</td><td>260</td><td>0xE7d292a336c15ab80A51E9b6959b5Ec9eA870474</td></tr></tbody></table>


# Neo Oracle Gateway

Neo Oracle Gateway is the integration layer that gives [Neo X](https://x.neo.org) smart contracts access to the [native Oracle infrastructure on Neo N3](https://docs.neo.org/docs/n3/Advances/Oracles.html).

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](/bridges/native-bridge/messaging-bridge).

The message bridge enables a request-response flow between Neo X and Neo N3:

1. A Neo X smart contract sends an oracle request through the Message Bridge.
2. The request is executed on Neo N3, where the native Oracle fetches external data.
3. The oracle result is returned through the Message Bridge.
4. 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-neo>
* `oracle-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

```solidity
interface IOracleProxy {
    function initiateOracleCall(
        uint256 _maxBridgeFee,
        bytes calldata _serializedOracleCall,
        uint256 _gasForOracle,
        uint256 _gasOracleRequestExec,
        uint256 _gasOracleResponseReturn,
        uint256 _maxMessageFee,
        bool _storeResult
    ) external payable returns (uint256 messageNonce, uint256 requestId);

    function getOracleResult(uint256 _requestId)
        external
        view
        returns (string memory result, uint256 responseCode, bool exists);

    function hasOracleResult(uint256 _requestId) external view returns (bool);
}
```

### 2) Instantiate the proxy contract

Use the `oracle-proxy-evm` address from the [`Deployments`](#deployments) table (`Mainnet` or `Testnet`, depending on your environment):

```solidity
oracleProxy = IOracleProxy(0xADDRESS);
```

### 3) Initiate an oracle call

```solidity
(messageNonce, requestId) = oracleProxy.initiateOracleCall{value: totalValue}(
    _maxBridgeFee,
    _serializedOracleCall,
    _gasForOracle,
    _gasOracleRequestExec,
    _gasOracleResponseReturn,
    _maxMessageFee,
    _storeResult
);
```

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 exactly `url`, `filter`, and `callbackMethod`. The gateway appends `gasForOracle`, `gasOracleRequestExec`, `gasOracleResponseReturn`, `nonce`, and `requestId` automatically. See how to construct the `_serializedOracleCall` [here](#3a-constructing-_serializedoraclecall) [and here](#3b-constructing-_serializedoraclecall).
* `_gasForOracle`: GAS allocated to the Oracle node. Must be `> 0.1 GAS` and `<= _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 by `oracle-proxy-evm`.

### 3a) Constructing `_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:

```
oracleProxyContractN3.requestOracleData(url, filter, callbackMethod)
```

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 (commonly `onOracleResponse`, depending on your Neo contract).

#### How `_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:

```shell
npm install @bane-labs/bridge-sdk-ts
```

The goal is to serialize a Neo N3 contract call to the OracleProxy method `requestOracleData(url, filter, callbackMethod)`.

Off-chain steps:

1. Provide the Neo N3 parameters used for serialization:
   * `neo3RpcUrl`: Neo N3 RPC endpoint
   * `executionManagerHash`: ExecutionManager contract hash on Neo N3
   * `oracleProxyContractN3`: OracleProxy contract hash on Neo N3 (target of the call)
2. 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 }`
3. Use a throwaway/dummy account for *read-only* serialization:
   * The SDK serializer requires an account object, but this step does not broadcast a transaction.
4. Serialize the call via the ExecutionManager:
   * Target contract: `oracleProxyContractN3`
   * Method: `'requestOracleData'` (mandatory)
   * CallFlags: `15` (`CallFlags.All`) (mandatory hardcoded value)
   * Args: `methodArgs`
5. Pass the returned `hex` string (ensure `0x` prefix) as `_serializedOracleCall` to `oracleProxy.initiateOracleCall(...)`.

Example (TypeScript):

```ts
import { NeoExecutionManager, neonAdapter } from '@bane-labs/bridge-sdk-ts';
import type { ContractParamJson } from '@cityofzion/neon-core/lib/sc/ContractParam';

export async function buildSerializedOracleCall(
  neo3RpcUrl: string,
  executionManagerHash: string,
  oracleProxyContractN3: string,
  url: string,
  filter: string,
  callbackMethod: string
): Promise<string> {

  // Set the method arguments
  const methodArgs: ContractParamJson[] = [
    { type: 'String', value: url || '' },
    { type: 'String', value: (filter || '').toString() },
    { type: 'String', value: callbackMethod || '' },
  ];

  // Dummy account is used only to satisfy the SDK serializer.
  const dummyPrivateKey = neonAdapter.create.privateKey();
  const account = neonAdapter.create.account(dummyPrivateKey);

  const executionManager = new NeoExecutionManager({
    rpcUrl: neo3RpcUrl,
    contractHash: executionManagerHash.replace(/^0x/i, ''),
    account,
  });

  // Call target: OracleProxy (N3), method: requestOracleData, flags: CallFlags.All (15).
  const serialized = await executionManager.serializeCall(
    oracleProxyContractN3.replace(/^0x/i, ''),
    'requestOracleData', // mandatory and cannot be changed, this is the method on the N3 Oracle Gateway contract that is being called
    15, // CallFlags.All (mandatory)
    methodArgs
  );

  return serialized.startsWith('0x') ? serialized : `0x${serialized}`;
}
```

#### Important note: what *must not* be manually appended

Do **not** include these values in `_serializedOracleCall` yourself:

* `gasForOracle`
* `gasOracleRequestExec`
* `gasOracleResponseReturn`
* `nonce` / `withdrawalNonce`
* `requestId`

These are appended automatically on-chain by `oracle-proxy-evm` during `initiateOracleCall()` via `NeoSerializerLib.appendArgToCall(...)`.

### 3b) Constructing `_serializedOracleCall` on-chain (Solidity)

As an alternative to building `_serializedOracleCall` off-chain ([Section 3a](#3a-constructing-_serializedoraclecall-off-chain-typescript)), you can construct it entirely on-chain inside your own smart contract using the [`neo-serializer-evm`](https://github.com/AxLabs/neo-serializer-evm) Solidity library.

Install `neo-serializer-evm` and import `NeoSerializerLib`:

```solidity
import {NeoSerializerLib} from "neo-serializer-evm/contracts/libraries/NeoSerializerLib.sol";
```

Then build the serialized call in your contract:

```solidity
function buildSerializedOracleCall(
    bytes20 oracleProxyN3,
    string calldata url,
    string calldata filter,
    string calldata callbackMethod
) public pure returns (bytes memory) {
    bytes[] memory args = new bytes[](3);
    args[0] = NeoSerializerLib.serialize(url);
    args[1] = NeoSerializerLib.serialize(filter);
    args[2] = NeoSerializerLib.serialize(callbackMethod);

    return NeoSerializerLib.serializeCall(
        oracleProxyN3,                       // Neo N3 OracleProxy contract hash
        "requestOracleData",                 // mandatory: fixed method name
        NeoSerializerLib.CALL_FLAGS_ALL,     // mandatory: CallFlags.All (15)
        args
    );
}
```

Parameter reference:

| Parameter               | Description                                                                                                                                                                                     |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `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](#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:** `serializeCall` internally handles byte-order conversion for the target hash (reverses bytes to match Neo's `UInt160` format via `serializeHash160`), 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:

```solidity
oracleProxy.hasOracleResult(_requestId);
```

Get the result directly:

```solidity
oracleProxy.getOracleResult(_requestId);
```


# x402 (Agent-Driven Payments)

## Overview

x402 enables agent-driven, authorization-based payments on Neo X.

Instead of requiring users to submit and fund transactions directly, x402 allows agents to:

* obtain payment requirements from a service
* collect payment authorizations from users
* submit settlement transactions on-chain

This enables machine-native payment flows where authorization and execution are separated.

## Why x402 on Neo X

Neo X is well-suited for agent-driven payment flows:

* fast finality enables predictable settlement
* EVM compatibility allows reuse of established standards such as Permit2
* native asset support enables efficient value transfer
* low-latency execution fits automated agent systems well

x402 builds on these properties to support:

* off-chain authorization and on-chain settlement
* gas abstraction, where agents submit transactions and pay gas
* programmable payment flows with explicit settlement constraints

## Contracts

The x402 integration relies on the following contracts:

* **Permit2** A signature-based token authorization primitive used for delegated transfers.
* **x402ExactPermit2Proxy** An x402 settlement contract that acts as the authorized spender in Permit2 signatures and enforces x402-specific payment constraints.

See: [Contracts](/integrations/x402/contracts)

## Facilitators

Settlement can be submitted by any agent, relayer, or facilitator that can call the on-chain settlement contract.

[Ax402](https://ax402.io/) provides a facilitator for Neo X. Creating an account gives you an API key with free settlements.

## SDKs and tooling

To implement buyers, sellers, or settlement helpers, start from the open-source x402 client libraries:

* TypeScript: [x402/typescript](https://github.com/x402-foundation/x402/tree/main/typescript)
* Python: [x402/python](https://github.com/x402-foundation/x402/tree/main/python)
* Go: [x402/go](https://github.com/x402-foundation/x402/tree/main/go)

If you use the Ax402 facilitator, additional packages are available for platform management, buyer helpers, agent tooling, and React paywalls:

* SDK: [`@ax402/sdk`](https://www.npmjs.com/package/@ax402/sdk) (includes buyer-side helpers)
* CLI: [`@ax402/cli`](https://www.npmjs.com/package/@ax402/cli)
* MCP server: [`@ax402/mcp-server`](https://www.npmjs.com/package/@ax402/mcp-server)
* React paywall: [`@ax402/react-paywall`](https://www.npmjs.com/package/@ax402/react-paywall)

Source and additional language SDKs (Python, Go) are in the [ax402-sdks](https://github.com/axLabs/ax402-sdks) repository.

## Quick Start

A typical x402 flow looks like this:

1. A service defines payment requirements
2. The user signs an authorization
3. An agent submits settlement on-chain
4. The payment is executed through the x402 contract using Permit2

See: [Quick Start](/integrations/x402/quick-start)

## Network Addresses

Deployed contract addresses are listed in: [Networks](/development/networks)

This page focuses on integration and usage rather than deployment details.


# Quick Start

## Prerequisites

To use x402 on Neo X, you need:

* access to a Neo X RPC endpoint
* a wallet capable of signing the required authorization payloads
* a token supported by the settlement flow
* an agent, relayer, or backend that can submit transactions on-chain

`settleWithPermit(...)` is intended for tokens that support EIP-2612 so approval and settlement can be combined into one transaction path. If the token-side `permit()` attempt fails, settlement can still proceed when the required Permit2 approval already exists.

## Payment Flow

A typical x402 flow consists of four steps.

### 1. Obtain payment requirements

A service defines the payment requirements, such as:

* token
* amount
* recipient
* timing constraints

These parameters are used to construct the authorization payload the user will sign.

### 2. Sign the authorization

The user signs a Permit2-based authorization.

In the exact settlement flow, the signed payload is bound to:

* the token and amount
* the destination address through the witness
* the `validAfter` constraint

This ensures the payment can only be settled under the agreed conditions.

Example EIP-712 signing shape:

```ts
import { createWalletClient, custom } from "viem";

const walletClient = createWalletClient({
  chain,
  transport: custom(window.ethereum),
});

const signature = await walletClient.signTypedData({
  account,
  domain: {
    name: "Permit2",
    chainId,
    verifyingContract: permit2Address,
  },
  types: {
    TokenPermissions: [
      { name: "token", type: "address" },
      { name: "amount", type: "uint256" },
    ],
    ExactPaymentWitness: [
      { name: "to", type: "address" },
      { name: "validAfter", type: "uint256" },
    ],
    PermitWitnessTransferFrom: [
      { name: "permitted", type: "TokenPermissions" },
      { name: "spender", type: "address" },
      { name: "nonce", type: "uint256" },
      { name: "deadline", type: "uint256" },
      { name: "witness", type: "ExactPaymentWitness" },
    ],
  },
  primaryType: "PermitWitnessTransferFrom",
  message: {
    permitted: { token, amount },
    spender: x402ExactPermit2Proxy,
    nonce,
    deadline,
    witness: {
      to: recipient,
      validAfter,
    },
  },
});
```

The exact witness type string and calldata fields must match the deployed contract implementation.

### 3. Submit settlement

An agent or backend submits the settlement transaction to:

* `x402ExactPermit2Proxy`

Depending on the flow, this is either:

* `settle(...)`
* `settleWithPermit(...)`

The submitter pays gas for execution. You can run that yourself, or use a facilitator such as [Ax402](https://ax402.io/), which provides settlement for Neo X; account creation includes an API key with free settlements.

### 4. Execute on-chain

The contract:

* validates the settlement inputs
* checks timing constraints
* uses Permit2 to execute the witness-bound transfer
* emits a settlement event on success

Once confirmed, the payment is settled on-chain.

## When to use `settleWithPermit(...)`

Use `settleWithPermit(...)` when:

* the token supports EIP-2612
* you want to combine approval and settlement into a single on-chain transaction path

This can improve UX by avoiding a separate prior approval step.

However:

* the EIP-2612 amount must match the Permit2 permitted amount exactly
* token-side `permit()` failure does not necessarily prevent settlement if Permit2 approval already exists

## Notes

* users do not need to submit the transaction themselves
* agents can handle execution and gas payment
* the destination is cryptographically bound through the witness
* this contract settles the exact permitted amount, not a partial amount

## Next Steps

* Review [Contracts](/integrations/x402/contracts) for implementation details and trust assumptions
* Check [Networks](/development/networks) for deployed addresses
* See [SDKs and tooling](/integrations/x402#sdks-and-tooling) for x402 client libraries and optional Ax402 packages


# Contracts

## Overview

The x402 integration on Neo X supports authorization-based payments.

For protocol background, see the [x402 website](https://x402.org/) and the [Coinbase x402 documentation](https://docs.cdp.coinbase.com/x402/welcome). This page focuses on the Neo X settlement contracts and the Permit2-based exact-amount path.

Depending on the capabilities of the underlying token, x402 can follow different settlement paths:

* **Permit2-based settlement** for broad ERC-20 compatibility
* **EIP-3009-based settlement** for tokens that natively support authorization-based transfers

This allows Neo X to support both:

* a universal path for existing ERC-20 assets
* a more direct path for tokens designed for agent-driven payments

## Authorization Models

x402 supports multiple authorization models depending on the token standard implemented by the asset being used.

### Permit2-based model

Permit2 provides a general-purpose authorization layer for ERC-20 tokens.

This path:

* works with any ERC-20 token once it has been approved to Permit2
* allows off-chain authorization of transfers
* enables x402 settlement even when the token does not natively support authorization-based transfers

This is the broadest compatibility path and is useful for existing assets such as stablecoins and other standard ERC-20 tokens.

### EIP-3009-based model

If a token implements EIP-3009, x402 can use the token's native authorization flow directly.

This path:

* does not require Permit2
* does not require a prior approval to an external authorization contract
* more closely matches direct authorization-based payment semantics

Compared to Permit2, this model has fewer moving parts because the authorization and transfer model is implemented directly by the token itself.

### Choosing between the models

In practice:

* use **Permit2** for tokens that do not implement EIP-3009
* use **EIP-3009** for tokens that natively support authorization-based transfers

Permit2 provides broad compatibility across existing ERC-20 tokens. EIP-3009 provides a more direct authorization-based model when supported by the token.

## Permit2

Permit2 is the signature-based transfer primitive used by the Permit2 integration path.

It allows users to authorize token transfers off-chain under explicit constraints, such as:

* token
* amount
* nonce
* deadline

In the x402 flow, Permit2 is responsible for validating the signed transfer authorization and executing the token transfer.

Permit2 itself does not enforce x402 payment semantics. It only enforces the signed authorization it receives.

## x402ExactPermit2Proxy

Despite its name, `x402ExactPermit2Proxy` is **not** an upgradeability proxy and does not rely on delegatecall-based forwarding.

It is a standalone settlement contract built on top of Permit2.

### Role

`x402ExactPermit2Proxy` acts as the authorized spender in Permit2 signatures and executes x402 payments using additional contract-level validation.

Its responsibilities include:

* validating settlement inputs
* enforcing non-zero owner, destination, and amount
* enforcing `validAfter`
* binding the destination address into the signed authorization via a witness
* submitting the Permit2 witness transfer
* optionally attempting an EIP-2612 permit before settlement

### Exact-amount settlement

This contract always settles the exact permitted amount.

That makes its behavior closer to `transferWithAuthorization`-style flows, where the signed authorization corresponds directly to the transferred amount, rather than allowing partial settlement.

### Witness-bound destination

A key property of this design is the use of a witness structure containing:

* `to`
* `validAfter`

The witness hash is signed together with the Permit2 authorization and binds the destination address cryptographically.

This prevents a facilitator or relayer from redirecting funds to a different recipient after the user has signed.

<figure><img src="https://3330027150-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fc9RAFpi4yBi3BegaKju7%2Fuploads%2Fgit-blob-1d91a604bfb00e8b84d19a675f5b92a2855ae509%2Fx402-permit2-settlement-flow.svg?alt=media" alt="x402 Permit2 settlement flow showing user signature, relayer submission, witness validation, and exact-amount token transfer"><figcaption><p>x402 Permit2 settlement flow on Neo X</p></figcaption></figure>

## Settlement Paths

### `settle(...)`

This is the standard settlement path.

It assumes Permit2 is already authorized and:

* computes the witness hash
* validates the settlement conditions
* executes the Permit2 witness transfer
* transfers the exact permitted amount

### `settleWithPermit(...)`

This path supports a more gasless integration flow for tokens that support EIP-2612.

It:

* first attempts an EIP-2612 `permit()` call to approve Permit2
* then performs the same Permit2-based settlement flow

Important behavior:

* the EIP-2612 permit attempt does not need to succeed if the required Permit2 approval already exists
* failure of the token `permit()` call is emitted via events rather than forcing settlement failure
* the EIP-2612 amount must exactly match the Permit2 permitted amount

## Trust Model

### What is trustless here

The payment destination is bound into the signed witness data.

This means the settlement contract cannot redirect funds to an arbitrary address without invalidating the signature.

The contract also:

* uses an immutable Permit2 address
* performs direct validation of core settlement fields
* does not expose admin-controlled settlement behavior in the provided implementation

### What integrators should still verify

Integrators should still review:

* the exact witness structure being signed
* which fields are and are not cryptographically bound
* whether exact-amount settlement is appropriate for their use case
* whether the token supports EIP-2612 if using `settleWithPermit(...)`

### Upgradeability clarification

`x402ExactPermit2Proxy` is not an upgradeability proxy.

It is a regular deployed contract that integrates with Permit2 and adds x402-specific settlement logic.

## Canonical Permit2 Address

The base contract stores the Permit2 address as an immutable constructor argument.

Using the same canonical Permit2 address on each EVM chain preserves identical init code and supports deterministic CREATE2 deployment of the x402 settlement contracts across chains.

## Network Addresses

For deployed addresses, see: [Networks](/development/networks)


# Governance in Neo X

This document covers the process of becoming a candidate node, the election process for candidate nodes to become consensus nodes, and the distribution of GAS token rewards in these processes.

## How to Become a Candidate Node on Neo X?

To qualify as a candidate node on Neo X, the applicant should adhere to the following criteria:

* Hardware Requirements: The applicant’s infrastructure must meet the specified [hardware requirements](https://github.com/bane-labs/docs/tree/main/development/running-a-neo-x-node.md#1-hardware-requirements) for Neo X nodes. This includes ensuring compliance with machine maintenance standards and the establishment of a robust technical setup.
* Institutional Recognition: The applicant should represent an established organization or institution recognized within the market ecosystem.

Suitable applicants can proceed with the registration process by staking 20000 GAS (Testnet) or 1000 GAS (Mainnet) through the Neo X Governance contract interface. This deposit serves as a commitment to participation in the governance process.

Upon a normal node exit, the staked GAS tokens will be refunded to the applicant. A tentative locking period of approximately 120,960 blocks is enforced to ensure the stability of the governance ecosystem.

## How to Become a Voter on Neo X?

All GAS token holders are eligible to vote on Neo X.

## The Consensus Node Election Process

Each election period, equivalent to an Epoch, spans approximately 60,480 blocks. From all candidate nodes, a total of seven nodes are elected as consensus nodes.

Any individual possessing GAS tokens on Neo X can participate in the election process by voting for their preferred consensus nodes. Votes are cast by staking any amount of GAS tokens (no less than 1 GAS) for only one candidate. The quantity of GAS tokens staked determines the voting power and influence in the reward amount this voter will receive if the candidate is elected.

Once the voting period concludes, the result will be settled immediately.

## Rewards and Penalties for Nodes

All transaction fees accrued during each Epoch will be accounted into the Governance reward. After the base fee burning and paymaster distribution, left rewards will be evenly split among the seven consensus nodes hosting the period.

<figure><img src="https://miro.medium.com/v2/resize:fit:1225/0*iVSA4MrcuEXWbJXk" alt=""><figcaption></figcaption></figure>

Additionally, rewards obtained by the consensus nodes are distributed between the nodes themselves and the voters who have supported them. The distribution ratio (for instance, 50%) is determined at node registration as a candidate and remains fixed until its node exits.

Furthermore, the portion of rewards allocated to the voters is distributed based on their voting weight, which is determined by the amount of GAS tokens they have staked for voting.

*voterReward=(governanceReward/7)\*distributionRatio\*(voteAmount/totalVote)*

The penalties for non-performing consensus nodes are yet to be determined. Wrong doings may include but are not limited to, being unable to meet dBFT block production conditions or complete the Anti-MEV decryption key distribution. Penalties may include, but are not limited to, being prohibited from becoming a block-producing or witness node for a certain period, or the deduction of deposits upon node exit. Additionally, they may be prohibited from becoming a candidate node again. These measures will be specified in the Neo X Governance contract in the future.

In the early stages of multi-node governance on Neo X, we anticipate a potential shortage of candidate nodes on the Neo X. To ensure network operation, we have designated seven standby consensus nodes to operate during this kick-off phase. Once there are at least seven qualified candidate nodes and the total voted GAS token number exceeds 3 million within one Epoch, the seven standby consensus nodes will be replaced by the seven elected nodes at the conclusion of the Epoch. This transition marks the beginning of full decentralized governance.

If either the number of candidate nodes or the voted GAS token drops below the criteria specified above, or if the result of the governance vote is invalid, the seven standby nodes will temporarily take over to maintain governance stability and network safety.


# Neo X System Contracts

Neo X system contracts are a set of build-in Solidity contracts with predefined addresses. They represent the governance and economic model of Neo X, which is fully decentralized and transparent.

<div align="right" data-full-width="false"><figure><img src="https://3330027150-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fc9RAFpi4yBi3BegaKju7%2Fuploads%2Fgit-blob-0b7d232c9224b9efb52b9973cd8b0f832bc9fe1d%2Farchitecture.png?alt=media" alt=""><figcaption></figcaption></figure></div>

These contracts are not deployed by transactions but allocated in the [genesis file](https://github.com/bane-labs/go-ethereum/blob/bane-main/config). The address setting of existing pre-compiled contracts is listed as below.

<table><thead><tr><th width="450">Address</th><th width="300">Contract</th></tr></thead><tbody><tr><td>0x1212000000000000000000000000000000000000</td><td>GovProxyAdmin</td></tr><tr><td>0x1212000000000000000000000000000000000001</td><td>Governance</td></tr><tr><td>0x1212000000000000000000000000000000000002</td><td>Policy</td></tr><tr><td>0x1212000000000000000000000000000000000003</td><td>GovernanceReward</td></tr><tr><td>0x1212000000000000000000000000000000000004</td><td>Bridge</td></tr><tr><td>0x1212000000000000000000000000000000000005</td><td>BridgeManagement</td></tr><tr><td>0x1212000000000000000000000000000000000006</td><td>Treasury</td></tr><tr><td>0x1212000000000000000000000000000000000007</td><td>CommitteeMultiSig</td></tr><tr><td>0x1212000000000000000000000000000000000008</td><td>KeyManagement</td></tr><tr><td>0x1212000000000000000000000000000000000009</td><td>MessageBridge</td></tr><tr><td>0x121200000000000000000000000000000000000A</td><td>GovPaymaster</td></tr></tbody></table>

## GovernanceVote

[GovernanceVote](https://github.com/bane-labs/go-ethereum/blob/bane-main/contracts/solidity/base/GovernanceVote.sol) is a public "library" that is widely used in system contract management especially upgrade.

Any contract inheriting `GovernanceVote.sol` can set up a consensus vote on method execution, by calling internal `vote(bytes32 methodKey, bytes32 paramKey)`, which requires **more than half** of the **current consensus** votes for **the same method call and the same calling parameters**.

1. More than half — the threshold value is `1/2` instead of `2/3`;
2. Current consensus — if an address is no longer a consensus member, its votes will not be counted;
3. The same method and parameters — it means the majority votes for the same execution result.

## GovProxyAdmin

[GovProxyAdmin](https://github.com/bane-labs/go-ethereum/blob/bane-main/contracts/solidity/GovProxyAdmin.sol) controls the upgrade of other pre-compiled system contracts, since all of their `onlyOwner`/`onlyAdmin` point to `0x1212000000000000000000000000000000000000`.

This contract inherits `GovernanceVote.sol` so that it requires a `50%` majority votes among current consensus to execute `scheduleUpgrade(...)`, which means **more than half** of the **current consensus** votes for **the same contract implementation**.

This contract inherits `TimelockController.sol` to implement a lock period (2 days on both Testnet and Mainnet) after the vote is passed before calling `executeUpgrade(...)` to upgrade the upgradable system contract. Anyone can call \`executeUpgrade(...)\`\` after the lock period is reached.

All of the upgradable Neo X system contracts use [ERC1967Proxy](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v5.0/contracts/proxy/ERC1967/ERC1967Proxy.sol) and [UUPSUpgradeable](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v5.0/contracts/proxy/utils/UUPSUpgradeable.sol).

## Governance

[Governance](https://github.com/bane-labs/go-ethereum/blob/bane-main/contracts/solidity/Governance.sol) is responsible for the election of consensus nodes and related reward distribution.

An election is, **GAS holders** vote for **registered candidates** and the Governance contract selects **top 7 candidates** as consensus nodes for **the next epoch\***.

\*Epoch is a unit of measurement for blocks. Currently, 1 epoch is the equivalent of `60480` blocks on both Testnet and Mainnet, which is the storage value `epochDuration` may be retrieved by contract calls.

### Candidate

An EOA account is allowed to become a candidate only after successful registration via Governance contract with required registration fee deposit staked. The following requirements should be met for successful registration:

1. Registrant invokes `registerCandidate(uint shareRate)` of `0x1212000000000000000000000000000000000001` as message sender;
2. Registrant is an EOA account and not yet a candidate;
3. Put `20000 GAS` (Testnet) or `1000 GAS` (Mainnet) deposit `value` along with the transaction as registration fee;
4. Provide a `shareRate` ranges from `0` to `1000` in parameters, which is a distribution ratio in thousandths. It determines how many rewards of the total that voters can share, and can not be changed until the candidate exits;
5. (optional) Withdraw past deposits if it has registered and exited before.

If all conditions are met, the new candidate will be added to the candidate list. Only registered candidates can receive votes to be elected as a consensus node.

A candidate can exit without any permission, but it requires 2 epochs to pass until the candidate is allowed to withdraw its registeration deposit. During this period, the candidate can't receive any votes or become a consensus node, but voters can revoke their votes and choose other candidates to share rewards. As a prevention of malicious resources occupation, a specific rate of the deposited value will be charged by Governance when a candidate tries to exit and claim back (50% for both Testnet and Mainnet).

### Election

All GAS holders can vote and benefit from Neo X Governance, including EOA accounts and smart contracts. The following requirements should be met for a successful vote:

1. Voter invokes `vote(address candidateTo)` of `0x1212000000000000000000000000000000000001` as message sender;
2. Put at least `1 GAS` vote `value` along with the transaction;
3. The provided `candidateTo` address is listed in the current candidates;
4. (optional) Revoke votes to other candidates if has voted before.

Neo X Governance doesn't allow voting for multiple candidates and doesn't distribute rewards to new voters until a new epoch begins. So be careful to revoke or change your vote target.

If it is necessary to change the vote target (e.g. the current voted candidate exits), invoke `transferVote(address candidateTo)` of `0x1212000000000000000000000000000000000001` to revote your deposited `GAS` to another candidate, and wait for the subsequent epoch to receive reward sharing.

At the end of every election epoch, the 7 candidates with the highest amount of votes will be selected by Governance and become consensus nodes of the next epoch. However, this consensus set recalculation has two prerequisites:

1. The size of candidate list is larger than `7`;
2. The amount of total valid votes is higher than `3,000,000 GAS` (Testnet) or `6,000,000 GAS` (Mainnet).

Otherwise, the consensus nodes of the next epoch will be the following predefined stand-by members.

<div align="right" data-full-width="false"><figure><img src="https://3330027150-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fc9RAFpi4yBi3BegaKju7%2Fuploads%2Fgit-blob-0b7d232c9224b9efb52b9973cd8b0f832bc9fe1d%2Farchitecture.png?alt=media" alt=""><figcaption></figcaption></figure></div>

These contracts are not deployed by transactions but allocated in the [genesis file](https://github.com/bane-labs/go-ethereum/blob/bane-main/config). The address setting of existing pre-compiled contracts is listed as below.

<table><thead><tr><th width="375">Testnet Stand-by Address</th><th width="375">Mainnet Stand-by Address</th></tr></thead><tbody><tr><td>0xcbbeca26e89011e32ba25610520b20741b809007</td><td>0x34a3b2abb99b4c128acf61dcbbd1fcac0b161652</td></tr><tr><td>0x4ea2a4697d40247c8be1f2b9ffa03a0e92dcbacc</td><td>0x641ec1c538fa17e6ad8193c9b580f6850b114280</td></tr><tr><td>0xd10f47396dc6c76ad53546158751582d3e2683ef</td><td>0xe3973f57e8a0aa312c1917ab0e6a05d8b6af6609</td></tr><tr><td>0xa51fe05b0183d01607bf48c1718d1168a1c11171</td><td>0xa61ac4a4f006f4fceeb72ee0012a2d3367168d10</td></tr><tr><td>0x01b517b301bb143476da35bb4a1399500d925514</td><td>0xe6d1a9db6a0893926bd81c0ef93aaaa543c116f0</td></tr><tr><td>0x7976ad987d572377d39fb4bab86c80e08b6f8327</td><td>0x4fe8af0dbb633283d8e9703668142fd130f2818d</td></tr><tr><td>0xd711da2d8c71a801fc351163337656f1321343a0</td><td>0x763452f65353fffe73d46539e51a6ddfc0e2c86a</td></tr></tbody></table>

After enabling DKG-related features and the KeyManagement contract for further antimev usage, there is a short period (currently `360` blocks) for key generations before epoch change. In this period, the **top 7 candidates** get locked in election, so the voted GAS amount can't further affect the result. Related voter operations (e.g. voting and withdrawing) and candidate operations (e.g. registering and exiting) are still open to use, which provides a smooth UX, but they don't change the election result as well.

### Reward

Neo X Governance reward distribution is real-time. Once a candidate is selected as a consensus node, it automatically starts to receive `GAS` rewards via participation in the dBFT consensus.

The governance reward in Neo X is always distributed to two parts, the first part is distributed to consensus nodes and the second is distributed to voters according to the `shareRate` settings.

**Consensus Node Distribution**

Regardless of consensus leader and received vote amount, all of the **transaction priority fees** are **equally divided** among consensus nodes as block rewards. Unlike N3, **other registered candidates receive no reward for the whole epoch**.

blockReward=totalNetworkTips/7

In Neo X dBFT, the block coinbase address is always `0x1212000000000000000000000000000000000003`, which means the rewards are first minted to [GovReward](https://github.com/bane-labs/go-ethereum/blob/bane-main/contracts/solidity/GovReward.sol) contract and then transfered to [Governance](https://github.com/bane-labs/go-ethereum/blob/bane-main/contracts/solidity/Governance.sol) contract during `OnPersist()` system call execution in the start of every subsequent block.

**Voter Distribution**

If the `shareRate` of a consensus node is higher than `0`, then `blockReward` will be split again between the consensus node and its voters.

For the consensus node, <img src="https://3330027150-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fc9RAFpi4yBi3BegaKju7%2Fuploads%2Fgit-blob-3240fd4fca1994ecff7ca66a088617afa6eeadf1%2F1715058039603.png?alt=media" alt="" data-size="line">

For each of its voters, <img src="https://3330027150-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fc9RAFpi4yBi3BegaKju7%2Fuploads%2Fgit-blob-76613984bef6d66d6ae3df8e8abfd00cc1c20493%2F1715057942346.png?alt=media" alt="" data-size="line">

Voter `GAS` reward is proportional to different `shareRate` settings and the voter's weight, i.e. the ratio of voter's votes to the overall number of candidate's votes.

The rewards for consensus nodes will be immediately sent to their addresses, but the reward settlement for voters obeys some other rules:

1. The rewards after first vote but before the next epoch starts are unclaimable, which means a voter can't benefit without participanting and affecting any election;
2. A voter has to send a calling (e.g. `claimReward()`) by itself to `0x1212000000000000000000000000000000000001` to receive claimable rewards;
3. The rewards are claimed and transfered as well when the vote amount changes via `vote(address candidateTo)` or `revokeVote()`.

There are several special cases of reward distribution:

1. When consensus nodes are stand-by validators, they will not share any reward to the network;
2. Voter rewards will not disappear if the voted candidate exits. However, it is possiable that a candidate exits and returns with a different `shareRate` after 2 epochs. It will affect your future benefits so voters are recommended to keep an eye on the voted candidate's activities.

## Policy

[Policy](https://github.com/bane-labs/go-ethereum/blob/bane-main/contracts/solidity/Policy.sol) controls the global settings of Neo X protocol, which are forced on every honest node in the network.

The current Neo X Policy maintains following parameters. All these policies are both checked by honest consensus nodes locally and by dBFT globally.

<table><thead><tr><th width="160">Name</th><th width="185">Parameter</th><th width="100">Value</th><th width="305">Usage</th></tr></thead><tbody><tr><td>Address Blacklist</td><td><code>isBlackListed</code></td><td></td><td>Prevent blacklisted addresses to send transactions or be elected as block validators in Neo X network</td></tr><tr><td>Minimum Transaction Tip Cap</td><td><code>minGasTipCap</code></td><td>20 Gwei</td><td>Force transaction senders to pay a minimum tip to Neo X Governance</td></tr><tr><td>Base Fee</td><td><code>baseFee</code></td><td>20 Gwei</td><td>Burn a fixed part of transaction fees instead of following EIP-1559's dynamic evaluation</td></tr><tr><td>Candidate Limit</td><td><code>candidateLimit</code></td><td>2,000</td><td>Limit the number of candidates in Governance registration and election</td></tr><tr><td>Envelope Fee</td><td><code>envelopeFee</code></td><td>0 Gwei</td><td>Force envelope transaction senders to pay an extra tip to Neo X Governance</td></tr><tr><td>Maximum Envelopes Per Block</td><td><code>maxEnvelopesPerBlock</code></td><td>10</td><td>Limit the number of envelope transactions in each block</td></tr><tr><td>Maximum Envelope Gas Limit</td><td><code>maxEnvelopeGasLimit</code></td><td>2,000,000</td><td>Limit the gas consumption of each envelope transaction</td></tr><tr><td>Sponsor Distribution Rate</td><td><code>sponsorRate</code></td><td>10%</td><td>Distribute part of the governance reward for ERC-4337 sponsorship</td></tr></tbody></table>

Since all the policy setters adopt the `needVote` modifier, any policy change requires more than 1/2 of the current Neo X consensus nodes votes to be collected.

## Bridge / MessageBridge

Refer to the [Bridge Contracts repository](https://github.com/bane-labs/bridge-evm-contracts).

## Treasury

[Treasury](https://github.com/bane-labs/go-ethereum/blob/bane-main/contracts/solidity/Treasury.sol) is a system contract assigned as the Neo X treasury for funding the native Bridge Proxy contract. The contract itself is rather simple and straightforward, its only purpose is to hold most of the initial Bridge funds distributed to this contract in the genesis block allocations. This contract is not upgradeable.

This contract has a single `fundBridge()` method that transfers specified `amount` of GAS to the Bridge Proxy contract. This method requires more than 1/2 of the current Neo X consensus nodes votes to be collected before the invocation.

## CommitteeMultiSig

[CommitteeMultiSig](https://github.com/bane-labs/go-ethereum/blob/bane-main/contracts/solidity/CommitteeMultiSig.sol) is a system contract assigned as an external contract invocation delegator based on Governance vote.

Different from [GovProxyAdmin](https://github.com/bane-labs/go-ethereum/blob/bane-main/contracts/solidity/GovProxyAdmin.sol), this contract can be used as an onchain multisig solution for any other contract management, which is upgradable and extendable.

This contract has a single `execute(...)` method that adopts the `needVote` modifier, so it requires more than 1/2 of the current Neo X consensus nodes votes to be collected. Besides, it has to be mentioned that `execute(...)` is not `payable` and this contract has no `fallback()` or `receive()` function.

## KeyManagement

[KeyManagement](https://github.com/bane-labs/go-ethereum/blob/bane-main/contracts/solidity/KeyManagement.sol) is a system contract assigned as the Neo X Distributed Key Generation (DKG) contract. This contract manages anti-MEV related cryptography operations needed for consensus nodes to participate in the Envelope transactions processing and block signing.

There are three different generation periods to participant:reshare, share, and recover. Before receiving any sharing messages from this contract, it is necessary to register your message encryption key through `registerMessageKey(...)`. The key should be a Secp256k1 public key generated by the antimev module of Neo X node.

### Reshare

The contract method `reshare(bytes calldata pvss, bytes[] calldata messages)` allows a secret sharing from the current consensus members to the upcoming consensus members for the next epoch.

After a successful round of DKG sharing, there are several pieces of secret keys for decryption and signing, and a global public key for encryption and verification.

To allow a smooth switching from an epoch to another, a secret resharing is necessary. It gives the upcoming consensus members an ability to decrypt Envelope transactions which are encrypted with the past global public key.

This contract method checks the newly uploaded `bytes calldata pvss` against the `sharedPubs` in storage, to ensure that reshared secret points to same global public key.

### Recover

The contract method `recover(uint[] calldata idxs, bytes[] calldata messages)` allows a secret recovering from the current consensus members to the upcoming consensus members for the next epoch.

It is hard to guarantee that every consensus node is alive and active in the end of a Governance epoch. If any of the consensus member doesn't perform resharing in time, a proper recovering period is required.

Enough pieces of the personal secret should be delivered to one of the upcoming consensus members with the corresponding index. This process will expose the whole personal secret to the receiver, which may affect the security of DKG, so it should only be executed by Neo X node automatically.

### Share

The contract method `share(bytes calldata pvss, bytes[] calldata messages)` allows a secret sharing among the upcoming consensus members for the next epoch.

A new round of DKG is totally independent with the past one, so the contract only validates `bytes calldata pvss` in its format and crypto commitment.

Different from the DKG resharing, a brand new sharing cannot be recovered before every participant generates its local secret and shares different parts of it to each other. So this period requires a fully participation of the upcoming consensus members for the next epoch, otherwise Governance will deprecate the election result and keep the same members of consensus for the next epoch.

The above processes will be automatically performed by Neo X node when antimev feature is enabled. For more details about the crypto, refer to [crypto/tpke](https://github.com/bane-labs/go-ethereum/tree/bane-main/crypto/tpke) and [core/antimev](https://github.com/bane-labs/go-ethereum/tree/bane-main/core/antimev).

## GovPaymaster

[GovPaymaster](https://github.com/bane-labs/go-ethereum/blob/bane-main/contracts/solidity/GovPaymaster.sol) is a native system contract that serves as the governance-funded Paymaster. It is exposed through the native-contract proxy infrastructure rather than deployed by individual users or application integrators. The contract receives a portion of Neo X Governance rewards and may sponsor eligible UserOperations, subject to Neo X Policy checks applied to the `PackedUserOperation`.

This contract only works with [EntryPoint v0.9](https://github.com/eth-infinitism/account-abstraction/releases/tag/v0.9.0), which should be deployed to `0x433709009B8330FDa32311DF1C2AFA402eD8D009` in the network.


# Anti-MEV Protection

**Maximal Extractable Value (MEV)** refers to the strategies employed by miners or validators to manipulate transaction order—by adding, removing, or reordering transactions—when producing new blocks. This practice has led to significant financial losses across the industry.

To address the adverse effects of malicious MEV on transaction fairness and network efficiency, **Neo X** introduces an advanced **Anti-MEV** mechanism. This solution is designed to mitigate malicious transaction reordering and front-running attacks, ensuring a more secure and equitable transaction process.

The Anti-MEV mechanism in Neo X is built upon:

* **Decentralized Key Generation (DKG)**: Ensures a trustless and distributed key generation process.
* **Threshold Encryption (TPKE)**: Enables secure transaction confidentiality.
* **Enhanced dBFT Consensus Algorithm**: Implements a new pre-commit phase to maintain fair transaction ordering.

By leveraging **Envelope Transactions**, users can encrypt their transactions, ensuring that they are not exposed to MEV attacks during the consensus process.

The following sections and [Neo X's TPKE library](https://github.com/bane-labs/neox-tpke-lib) will help you to understand and build with this unique infrastructure.


# Threshold Encryption

## Decentralized Key Generation (DKG)

The DKG mechanism in Neo X enables a fully decentralized key generation process among consensus members. Before each epoch change, the upcoming consensus group must successfully complete a DKG round to establish a new threshold public-private key pair. This process ensures that no single participant controls the decryption or signing capabilities.

### DKG Process

Each DKG round consists of three key steps:

1. **Share** – The next consensus group generates $$n$$ distributed secret shares and a global public key, where $$n$$ is the number of Neo X consensus nodes.
2. **Reshare** – The current consensus group (if available) transfers the previous round’s secret to the next group.
3. **Recover (Optional)** – If up to $$f$$ secret shares are lost, the remaining $$2f+1$$ shares reconstruct the secret to complete the transition.

Starting from [**v0.3.0**](https://github.com/bane-labs/go-ethereum/releases/tag/v0.3.0), the DKG module automates the entire process, except for setting up the initial Anti-MEV keystore with a secret passphrase.

#### Share **Phase**

Each participant executes the following steps:

1. Take a random polynomial $$f(x) = a\_0 + a\_1x + a\_2x^2 + \ldots + a\_{t-1}x^{t-1}$$ as their local secret, where $$t = 2f+1$$ (the threshold for consensus).
2. Compute $$f\_1,f\_2,...,f\_n$$ where $$f\_i=f(i)$$ and share them with corresponding participants, where $$i$$ is the index of different participants of `Share`.
3. Accept all $$f\_i$$ from other participants as $$f\_1(i),f\_2(i),...,f\_n(i)$$, where $$i$$ is the index of receiver, and compute $$s\_i=\sum f\_i$$ to get the final secret key.

#### **Generating the Global Public Key**

The global public key is generated using Publicly Verifiable Secret Sharing (PVSS):

1. Each participant uploads $$F(x)=f(x)G\_1$$ within his PVSS to the [KeyManagement](/governance/neo-x-system-contracts#keymanagement) contract.
2. The contract verifies each PVSS and computes $$S=\sum\_{i=1}^n F\_i(0)$$ as the global public key.

A well-constructed PVSS includes:

* $$F(x)=f(x)G\_1$$ as the sender’s local secret commitment.
* $$rG\_1,rG\_2$$ as a pair of commitments for a random scalar $$r$$.
* $$F=(F(1),F(2),...,F(n))$$ as the commitment share messages.

The KeyManagement contract validates $$F(1),F(2),...,F(n)$$, and verifies scalar $$r$$. Recipients validate their received shares using $$e(r\_1f(i),g\_2)=e(F(i),r\_2)$$.

{% hint style="info" %}
**Future Enhancement:** Zero-Knowledge Proofs (ZKPs) will be integrated to enhance encryption verification.
{% endhint %}

#### **Reshare Phase**

Each participant executes the following steps:

1. Regenerate his local secret $$f'(x)=a\_0+a'\_1 x+a'*2 x^2+ \ldots +a'*{t-1}x^{t-1}$$ while preserving the constant term $$a\_0$$.
2. Follow the step 2 and 3 in the **Share** phase, but send the shares to the next consensus group.

The KeyManagement contract ensures $$F(0)=F'(0)$$, preserving the global public key unchanged and preventing leakage of the original secret shares.

#### **Recover Phase (Optional)**

If some secret shares are lost, the remaining consensus members help restore them:

1. The current consensus group forwards all received shares $$f\_i$$ from the lost index $$i$$ to its successor.
2. The recipient reconstructs the original local secrets using [**Lagrange interpolation**](https://en.wikipedia.org/wiki/Lagrange_polynomial).

> **Security Note**: `Recover` exposes at most $$f$$ of the original secrets, so it is only allowed when the index $$i$$ is confirmed absent from `Reshare`.

## Threshold Public Key Encryption (TPKE)

Neo X's DKG enables a Threshold Public Key Encryption (TPKE) scheme, ensuring that encrypted transactions can only be decrypted if at least $$2f+1$$ consensus nodes cooperate. This mechanism is crucial for preventing premature exposure of transaction details.

Neo X TPKE utilizes the BLS12-381 curve, encoding any secret to $$G\_1$$ for encryption and any message to $$G\_2$$ for signature generation.

### Encryption

For a given secret message $$msg$$, the encryption process follows these steps:

1. A random point $$G\_1$$ point $$P$$ is chosen as a seed to generate an AES key. The encrypted ciphertext is computed as $$C\_1=AES(Hash(P), msg)$$.
2. To ensure security, a random scalar $$r$$ is selected to encrypt $$P$$ as $$C\_2=P+rS$$

   where:

   * $$r$$ is a random scalar,
   * $$S$$ is the global public key.
3. The final encrypted message $$C$$, which is broadcasted across the network, consists of $$C=(C\_1,C\_2)$$.

### **Decryption**

To recover the original $$msg$$, the Neo X consensus network must decrypt $$C\_1$$ to recover $$P$$. The decryption process follows:

1. Each CN computes and shares $$s\_iR$$, where:
   * $$R$$ is the commitment of the random scalar $$r$$,
   * $$s\_i$$ is the local secret key.
2. Since validator indices (DKG indices) are publicly known within Neo X Governance, these shares can be aggregated and solved using a [**Vandermonde matrix**](https://en.wikipedia.org/wiki/Vandermonde_matrix).
3. Once the seed $$P$$ is recovered, the original message $$msg$$ can be decrypted using AES.

### Signature

For a given message $$msg$$, Neo X generates a signature through the following process:

1. The message is encoded to $$G\_2$$ as $$Q=HashToG2(msg)$$
2. A signature share is computed as $$s\_iH$$ where $$s\_i$$ is the local secret key.
3. After collecting enough broadcasted shares, CNs aggregate and get the final signature with [Vandermonde matrix](https://en.wikipedia.org/wiki/Vandermonde_matrix) in the same way as TPKE decryption.


# Envelope Transaction

To prevent MEV attacks, Neo X users can submit transactions within Envelope Transactions, ensuring their transactions remain encrypted until confirmed within the consensus process.

We've deployed a [LIVE Demo](https://neox-tpke-examples.pages.dev/examples/transfer) for Neo X Testnet T4. Have a try to send GAS or ERC-20 tokens with Envelope transactions and your Metamask.

## Envelope Structure

A valid Envelope transaction must meet the following criteria:

* The recipient address `to` must be `Neo X GovReward Contract (0x1212000000000000000000000000000000000003)`.
* The sender address `from` must match the inner secret transaction sender.
* The `nonce` must be identical to that of the inner secret transactions.
* The `gas tip` must exceed the network's `minGasTipCap` plus `envelopeFee`.
* The `data` field of the Envelope transaction must be formatted as follows:
  * A 4-byte prefix (`0xffffffff`).
  * A 4-byte DKG epoch index (big-endian).
  * A 4-byte inner secret transaction `gaslimit` (big-endian).
  * A 32-byte hash of the inner secret transaction.
  * A TPKE-encrypted ciphertext.

Here is an example of the `data` field of an Envelope transaction:

```
|  prefix  | epoch  | gaslimit |  inner secret transaction hash  |   TPKE ciphertext   |
|  4-byte  | 4-byte |  4-byte  |             32-byte             |        bytes        |
|0xffffffff|00000001| 00005208 |    777bbe0bb1e4c3...eff6fd15a   | 80f8c8c2...fa6a1810 |
```

In a nutshell, Envelopes are always calling the `fallback()` method of the Neo X GovReward contract. This method burns gas based on the declared `gaslimit` in `data` to allocate block space in Envelope execution, and it works with `eth_estimateGas` automatically.

## Steps to Send an Envelope Transaction

To send a secret transaction wrapped with an Envelope, we recommend the following steps which should be compatible with most of popular wallets (e.g. Metamask):

1. Construct a secret transaction;
2. Request the wallet to sign this transaction and send it to nodes configured with `--txpool.amevcache`;
3. Request the wallet to sign the `nonce` of the secret transaction as a message;
4. Use this signature to fetch the signed transaction through `eth_getCachedTransaction`;
5. Encrypt the signed transaction with Neo X TPKE;
6. Construct an Envelope transaction with the encrypted data and send it through wallet with the same `nonce`.

> **Note**: The node in step 2 always returns an RPC error to prevent the wallet nonce from increasing, so that we keep compatible with popular wallets e.g. Metamask. This is the expected behavior, so please follow steps 3 and 4 to verify the final result.

## **Envelope Transaction Verification**

In Neo X, Envelope transactions must first pass mempool, otherwise they cannot be decrypted or executed in the dBFT consensus process.

### **Verification Criteria**

* The sender has sufficient balance to cover the required gas fees.
* The `nonce` used in both the Envelope and its enclosed transaction is valid.
* The Envelope `gaslimit` does not exceed the `maxEnvelopeGasLimit` policy.

### **Execution Behavior**

* If the Envelope transaction passes verification, its encrypted contents will be decrypted and executed. Regardless of success or failure, the inner transaction will replace the Envelope transaction in the block space.
* If the Envelope transaction is invalid, fails decryption, or contains an invalid inner transaction:
  * It will either be rejected by the mempool or included in the next block without execution.
  * If included in a block, the designated gas for execution will be **burned**, ensuring users pay for the allocated block space even if the transaction is not processed.

### **Network Constraints**

Neo X enforces limits on both the number of Envelope transactions per block and their total gas consumption, as defined by the `maxEnvelopesPerBlock` and `maxEnvelopeGasLimit` policies. During periods of high network traffic, Envelope transactions may experience delays.

## RPC APIs

Neo X provides several new RPC APIs to facilitate the Envelpe construction. For more details, refer to [JSON-RPC API](/development/json-rpc-api).


# dBFT Enhancement

Neo X's enhanced Delegated Byzantine Fault Tolerance (dBFT) introduces a `PreCommit` phase to enforce fair transaction ordering and eliminate MEV risks.

## Consensus Flow with Envelopes

1. Proposal and ordering phase
   * Envelope transactions are proposed as same as normal transactions in `PrepareRequest`.
   * Transactions are ordered based on their gas price, thus Envelope transactions often be placed at the front due to additional decryption fees.
   * By the end of `PrepareResponse`, a `PreBlock` for the next block height is confirmed, finalizing the transaction order before decryption occurs. This prevents malicious reordering based on MEV insights.
2. Decryption phase
   * During the new `PreCommit` period, consensus nodes (CNs) identify Envelope transactions and broadcast decryption shares for them.
   * Once at least $$2f+1$$ decryption shares are collected, the Envelope transactions are replaced with their decrypted inner transactions in the proposed block.
   * No view changes occur after this stage, ensuring decrypted transactions remain protected from MEV-based manipulation.
3. Commitment phase
   * CNs compute and broadcast signature shares for the finalized block proposal.
   * The block is committed and acknowledged by the network only when at least $$2f+1$$ signature shares are collected.
   * The final block includes decrypted transactions instead of Envelopes, ensuring a transparent and MEV-resistant execution.

## Conclusion

Neo X's Anti-MEV solution provides a robust mechanism to protect users from MEV attacks. By integrating threshold encryption, decentralized key generation, and enhanced dBFT consensus, it ensures fair transaction ordering and confidentiality.


# Audits

Independent security reviews help validate the design and implementation of Neo X before it handles user funds or consensus-critical operations. This page lists **publicly released audit reports** for Neo X–related codebases.

Reports are listed below in reverse chronological order. Each link opens the full PDF stored in this repository.

| Title                                                                                                                                                                                 | Scope                                                                                                                                                                                                                                                                                                                                                       | Finalized  | Report                                                                                                                       |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------- |
| [xGAS — Security Audit (Red4Sec)](https://github.com/bane-labs/docs/tree/main/security/audits/reports/red4sec-xgas-audit-report.pdf)                                                  | Wrapped native asset on Neo X: ERC-20 deposit/withdraw, ERC-2612 permits, and EIP-3009 transfer authorizations (EOA and ERC-1271 paths). Repository: [bane-labs/xgas](https://github.com/bane-labs/xgas).                                                                                                                                                   | 2026-05-20 | [PDF](https://github.com/bane-labs/docs/tree/main/security/audits/reports/red4sec-xgas-audit-report.pdf)                     |
| [Arbitrary Message Bridge — Security Audit (Red4Sec)](https://github.com/bane-labs/docs/tree/main/security/audits/reports/red4sec-arbitrary-message-bridge-audit-report.pdf)          | N3↔Neo X message bridge smart contracts: NeoVM and Solidity contracts for arbitrary data messages, cross-chain contract calls, and execution result propagation. Repositories: [bane-labs/bridge-neo-contracts](https://github.com/bane-labs/bridge-neo-contracts) and [bane-labs/bridge-evm-contracts](https://github.com/bane-labs/bridge-evm-contracts). | 2025-10-13 | [PDF](https://github.com/bane-labs/docs/tree/main/security/audits/reports/red4sec-arbitrary-message-bridge-audit-report.pdf) |
| [Neo X zk-DKG — Blockchain Protocol Security Analysis (Hacken)](https://github.com/bane-labs/docs/tree/main/security/audits/reports/hacken-zk-dkg-audit-report.pdf)                   | Zero-knowledge Distributed Key Generation for Anti-MEV: multi-curve threshold key generation, Gnark circuits, and related Go implementation. Repository: [bane-labs/zk-dkg](https://github.com/bane-labs/zk-dkg).                                                                                                                                           | 2025-08-04 | [PDF](https://github.com/bane-labs/docs/tree/main/security/audits/reports/hacken-zk-dkg-audit-report.pdf)                    |
| [NeoX Bridge Contract — Competitive Security Assessment (Secure3)](https://github.com/bane-labs/docs/tree/main/security/audits/reports/secure3-bridge-evm-contracts-audit-report.pdf) | Solidity bridge on Neo X: deposit/withdraw flows, token registration, validator signature verification, and bridge management contracts. Repository: [bane-labs/bridge-evm-contracts](https://github.com/bane-labs/bridge-evm-contracts).                                                                                                                   | 2024-08-08 | [PDF](https://github.com/bane-labs/docs/tree/main/security/audits/reports/secure3-bridge-evm-contracts-audit-report.pdf)     |
| [NeoX NeoVM Bridge Contracts — Security Audit (Red4Sec)](https://github.com/bane-labs/docs/tree/main/security/audits/reports/red4sec-neovm-bridge-audit-report.pdf)                   | Neo N3 (NeoVM) side of the N3↔Neo X bridge: native contracts for deposits, fees, and bridge management (Neow3j). Repository: [bane-labs/bridge-neo-contracts](https://github.com/bane-labs/bridge-neo-contracts).                                                                                                                                           | 2024-08-07 | [PDF](https://github.com/bane-labs/docs/tree/main/security/audits/reports/red4sec-neovm-bridge-audit-report.pdf)             |
| [NeoX EVM Bridge Contracts — Security Audit (Red4Sec)](https://github.com/bane-labs/docs/tree/main/security/audits/reports/red4sec-evm-bridge-audit-report.pdf)                       | EVM-side N3↔Neo X bridge smart contracts (Solidity): asset transfer logic, configuration, and validator deposit verification. Includes follow-up re-audit of remediated scope. Repository: [bane-labs/bridge-evm-contracts](https://github.com/bane-labs/bridge-evm-contracts).                                                                             | 2024-07-22 | [PDF](https://github.com/bane-labs/docs/tree/main/security/audits/reports/red4sec-evm-bridge-audit-report.pdf)               |
| [Neo X — Security Assessment (BlockSec)](https://github.com/bane-labs/docs/tree/main/security/audits/reports/blocksec-neo-x-core-audit-report.pdf)                                    | Neo X full-node fork vs. Geth: validator/governance Solidity contracts and selected Go changes (dBFT-related consensus code explicitly out of scope). Repository: [bane-labs/go-ethereum](https://github.com/bane-labs/go-ethereum).                                                                                                                        | 2024-07-09 | [PDF](https://github.com/bane-labs/docs/tree/main/security/audits/reports/blocksec-neo-x-core-audit-report.pdf)              |
| [NeoX Governance — Security Audit (Red4Sec)](https://github.com/bane-labs/docs/tree/main/security/audits/reports/red4sec-governance-audit-report.pdf)                                 | Built-in governance system contracts: consensus node election, voting, rewards, and candidate registration (genesis-allocated Solidity). Repository: [bane-labs/go-ethereum](https://github.com/bane-labs/go-ethereum/tree/bane-main/contracts).                                                                                                            | 2024-06-07 | [PDF](https://github.com/bane-labs/docs/tree/main/security/audits/reports/red4sec-governance-audit-report.pdf)               |

## Notes

* **Scope vs. calendar date** — Some Red4Sec reports list both an engagement window (e.g. April–June 2024) and a report publication date on the cover. The **Finalized** column uses the date printed on the published report.
* **Follow-up work** — Several reports document remediation or re-audit cycles (for example, Secure3 contest findings and Red4Sec re-reviews). Refer to each PDF for finding severity and resolution status.
* **Missing reports** — If you believe a Neo X audit is absent from this list, please open an issue or contact the maintainers with the report title and auditor so it can be added.

Maintainers: see [Adding audit reports](https://github.com/bane-labs/docs/tree/main/security/audits/ADDING-AUDITS.md) for filename conventions and how to update this page.


# Transaction Underpriced Error

This error usually happens when the transaction's specified fee does not satisfy the minimum network requirements for execution.

On Neo X, transaction fees are composed of two parts: the **base fee**, which is burned, and the **gas tip**, which serves as an incentive distributed to governance nodes and voters. The **base fee** is fixed and independent of transaction volume. The **gas tip** is user-defined and can be adjusted. However, the Neo X network policy mandates a minimum value (20 gwei) for the gas tip. Transactions that do not meet the minimum gas tip requirement will be rejected.

According to EIP-1559, users determine their desired gas tip (`gasTipCap`) and the total fee they are willing to pay (`gasFeeCap`). The gas fee cap must cover both the **base fee** and the **gas tip**.

If the `gasTipCap` is too low, the transaction will be flagged as underpriced. Similarly, if the `gasFeeCap` is insufficient, the transaction will fail.

#### Error Context

A typical error message looks like this:

{% code overflow="wrap" %}

```
- server returned an error response: error code -32000: transaction underpriced: policy minGasTipCap needed 20000000000, baseFee needed 20000000000, gasTipCap 1, gasFeeCap 40000000001
```

{% endcode %}

* `minGasTipCap`: The minimum gas tip (priority fee) required by the network.
* `baseFee`: The network base fee. Currently it is 20 gwei for Neo X.
* `gasTipCap`: The user-specified priority fee offered to incentivize miners or validators.
* `gasFeeCap`: The total fee the user is willing to pay, which covers both the base fee and gas tip.

#### Solution

To resolve this issue, ensure that the transaction fees meet the following conditions:

* `gasTipCap` >= `minGasTipCap` (e.g., 20 gwei for Neo X).
* `gasFeeCap` >= `baseFee` (e.g., 20 gwei) + `minGasTipCap`.


