NeuyRouter Developer Docs

Updated Feb 9, 2026 - Versioned cross-chain DEX router

NeuyRouter is an aggregated DEX router that searches across multiple pools and routes on each supported chain to find efficient swaps. This page shows how to integrate it from JavaScript and Python on Arbitrum, Avalanche, Binance, Base, Ethereum, Polygon and Monad.

0. Why Use NeuyRouter?

NeuyRouter occupies a unique place in the DEX aggregator landscape. Traditional aggregators rely heavily on centralized off-chain APIs to compute routes, while pure Web3 DEXs offer permissionless access but no multi-DEX price optimization. NeuyRouter delivers the best of both: the routing power of an aggregator with the transparency and determinism of fully on-chain logic.

This makes NeuyRouter ideal for developers, arbitrage systems, automation frameworks, and any application requiring predictable, verifiable smart-contract routing without depending on external servers, API keys, or proprietary infrastructure.

Attribute Uniswap 1inch ParaSwap Matcha/0x Odos NeuyRouter
Fully on-chain routing
No API dependency
Multi-DEX aggregation
Split-route support
Native token routing
Calls usable directly by smart contracts LimitedNot idealNot idealNot idealNot ideal Ideal
Deterministic, transparent routing logic
Fee model 0-0.15% ~0% + slippage capture 0% Variable ~0% 0.1% only on surplus

NeuyRouter is the only Web3-native aggregator built entirely on-chain-no servers, no APIs, no rate limits. This makes it a transparent, permissionless routing primitive that developers can rely on across Arbitrum, Binance, Base, Ethereum, and Polygon.

1. Overview

NeuyRouter is a smart-contract router that aggregates liquidity across multiple DEXs and routes to find competitive pricing. It exposes a single interface for:

  • Getting quotes for ERC20 > ERC20 swaps
  • Executing swaps via NeuyRouter instead of talking to DEXs directly
  • Swapping Native gas token <> ERC20

There are currently three versions deployed:

  • V3: Arbitrum, Avalanche, Base, Binance, Ethereum, Polygon and Monad
  • V2: Arbitrum, Avalanche, Binance
  • V1: Base, Ethereum, Polygon

2. Networks & contract addresses

Chain Version Router address
Arbitrum V3 beta 5 0x3104a21d0026EAf5727bDe6973c6dcF5a65Bd411
Avalanche V3 beta 5 0x62ff08D146b0E15A80874C01fD7b09Ea6bA63146
Base V3 beta 5 0x24499124C499188bC647ef7CB3F83c973cAa6E22
Binance (BSC) V3 beta 5 0x54c4f517e4B14907Ff3fEa93Ce971383f4cE9b9A
Ethereum V3 beta 5 0x09D1a8011dBe6de62F1cE064543EB666bBb4fe16
Polygon (POS) V3 beta 5 0x04d8417a7Ea48530e218Cf48BbB3e0ae1cb69119
Monad V3 beta 5 0x22Ae0F0b58d86F96dB6a343495C9b9cC067189d4
Chain Version Router address
Arbitrum V3 beta 4 0xC05174188d5Cf5512C3D27306398F141E46E149E
Avalanche V3 beta 4 0x263221D26B7052F8b9aFaC0a33c4f12bacd87144
Binance (BSC) V3 beta 4 0xa46BDE63Dc41225E5a9c6547BF31DAF06464Bbff
Base V3 beta 4 0x85D1CDBf53E8882314A8aF3499f0eCeE6945975f
Ethereum V3 beta 4 0xD3E73c2563fFCE65401DfdEcf66b699D4ce41fB9
Polygon (POS) V3 beta 4 0x682828Ae2A130993f528C1410C8f4f90CD9cAC5F
Monad V3 beta 4 0x5e0b4920e2E8D4D82342FB82ABDc27602ABba31f
Chain Version Router address
Arbitrum V2 0x0BA133CbfdAE0b431c35459B0b5f9Fe627c48cac
Avalanche V2 0x1252b87BAd75AEfaCE59B594239F439EFF67cEF0
Binance (BSC) V2 0x600df1F1d2EAb5f81B7Acfe1319AD7B283525C88
Chain Version Router address
Base V1 0x4A0FA0A6d728F985Fe2c478265BB04e57BCD01C2
Ethereum V1 0x5276921361F9AC4E39b58a5c5D8555AbF797F6cB
Polygon (POS) V1 0xcc9F06616208A9a02870D464ee1fBe71BCEABdf6

Native swap endpoints (dexV2NativeSwapETHToToken or dexV2NativeSwapBNBToToken, dexV2NativeSwapTokenToETH or dexV2NativeSwapTokenToBNB) are available on V2 chains only (Arbitrum, Binance).

3. Router ABI (shared subset)

The core ABI used across all deployments:

[
  "function balanceOf(address account) external view returns (uint256)",
  "function getV3Quote(address tkIn, address tkOut, uint256 amountIn) external returns (uint256,uint256)",
  "function dexV3Swap(uint256 route, uint256 amountIn, uint256 amountOut, address tkIn, address tkOut) external returns (uint256)",
  "function getV2Quote(address tkIn, address tkOut, uint256 amountIn) external view returns (uint256,uint256)",
  "function dexV2Swap(uint256 route, uint256 amountIn, uint256 amountOut, address tkIn, address tkOut) external returns (uint256)",
  "function getSplitV2Quote(address tkIn, address tkOut, uint256 amountIn) external view returns (uint256,uint256,uint256)",
  "function dexSplitV2Swap(uint256 route1, uint256 route2, uint256 amountIn, uint256 amountOut, address tkIn, address tkOut) external returns (uint256)",

  // Arbitrim Base Ethereum Polygon Monad
  "function dexV2NativeSwapETHToToken(uint256 route, uint256 amountOutMin, address tkOut) external payable returns (uint256)",
  "function dexV2NativeSwapTokenToETH(uint256 route, uint256 amountIn, uint256 amountOutMin, address tkIn) external returns (uint256)"

  // Binance Only
  "function dexV2NativeSwapBNBToToken(uint256 route, uint256 amountOutMin, address tkOut) external payable returns (uint256)",
  "function dexV2NativeSwapTokenToBNB(uint256 route, uint256 amountIn, uint256 amountOutMin, address tkIn) external returns (uint256)"

  // Avalanche Only
  "function dexV2NativeSwapAVAXToToken(uint256 route, uint256 amountOutMin, address tkOut) external payable returns (uint256)",
  "function dexV2NativeSwapTokenToAVAX(uint256 route, uint256 amountIn, uint256 amountOutMin, address tkIn) external returns (uint256)",

  // All Supported Chain but V3 Only
  "function dexV3NativeSwap(uint256 route, uint256 amountOut, address tkOut) external payable returns (uint256)",
  "function dexV3ToNativeSwap(uint256 route, uint256 amountIn, uint256 amountOut, address tkIn) external returns (uint256)",
]

4. Quick start

Below is a minimal example of connecting to NeuyRouter, getting a quote, and performing a swap. Use the tabs to switch between JavaScript (ethers.js) and Python (web3.py).

// JavaScript (browser + ethers v5)
// Assumes window.ethereum is injected (MetaMask, etc.)

const ROUTERS = {
  arbitrum: "0xC05174188d5Cf5512C3D27306398F141E46E149E",  // V3
  avalanche: "0x263221D26B7052F8b9aFaC0a33c4f12bacd87144",  // V3
  bsc:      "0xa46BDE63Dc41225E5a9c6547BF31DAF06464Bbff",  // V3
  base:     "0x85D1CDBf53E8882314A8aF3499f0eCeE6945975f",  // V3
  ethereum: "0xD3E73c2563fFCE65401DfdEcf66b699D4ce41fB9",  // V3
  polygon:  "0x682828Ae2A130993f528C1410C8f4f90CD9cAC5F"   // V3
  monad:  "0x5e0b4920e2E8D4D82342FB82ABDc27602ABba31f"   // V3
};

const routerAbi = [ /* ABI from section above */ ];

async function initNeuyRouter() {
  await window.ethereum.request({ method: "eth_requestAccounts" });

  const provider = new ethers.providers.Web3Provider(window.ethereum, "any");
  const signer = provider.getSigner();

  // Example: Arbitrum V2 router
  const router = new ethers.Contract(
    ROUTERS.arbitrum,
    routerAbi,
    signer
  );

  return { provider, signer, router };
}

// Example: get a +V2 quote & perform a swap (ERC20 > ERC20)
async function swapExample() {
  const { router } = await initNeuyRouter();

  const tkIn  = "0x...";   // ERC20 in
  const tkOut = "0x...";   // ERC20 out
  const amountIn = ethers.utils.parseUnits("1.0", 18); // 1 token (18 decimals)

  // 1) Get +V2 quote (amountOut, route)
  const [amountOut, route] = await router.getV2Quote(tkIn, tkOut, amountIn);

  // 2) Apply slippage protection
  const slippage = 0.98; // 2% slippage
  const minOut = amountOut.mul(98).div(100);

  // 3) Make sure tkIn is approved for the router before calling dexV2Swap.
  //    (approve done on the token contract: token.approve(router.address, ...))

  const tx = await router.dexV2Swap(
    route,
    amountIn,
    minOut,
    tkIn,
    tkOut
  );
  const receipt = await tx.wait();
  console.log("Swap completed:", receipt.transactionHash);
}
# Python (web3.py)
from web3 import Web3

const ROUTERS = {
  arbitrum: "0xC05174188d5Cf5512C3D27306398F141E46E149E",  // V3
  avalanche: "0x263221D26B7052F8b9aFaC0a33c4f12bacd87144",  // V3
  bsc:      "0xa46BDE63Dc41225E5a9c6547BF31DAF06464Bbff",  // V3
  base:     "0x85D1CDBf53E8882314A8aF3499f0eCeE6945975f",  // V3
  ethereum: "0xD3E73c2563fFCE65401DfdEcf66b699D4ce41fB9",  // V3
  polygon:  "0x682828Ae2A130993f528C1410C8f4f90CD9cAC5F"   // V3
  monad:  "0x5e0b4920e2E8D4D82342FB82ABDc27602ABba31f"   // V3
};

router_abi = [  # same ABI as above, truncated here for brevity
    "function getV2Quote(address,address,uint256) view returns (uint256,uint256)",
    "function dexV2Swap(uint256,uint256,uint256,address,address) returns (uint256)"
]

# 1) Connect to a node (example: Arbitrum)
w3 = Web3(Web3.HTTPProvider("YOUR_ARB_RPC_URL"))
router_addr = Web3.to_checksum_address(ROUTERS["arbitrum"])
router = w3.eth.contract(address=router_addr, abi=router_abi)

tk_in  = Web3.to_checksum_address("0x...")
tk_out = Web3.to_checksum_address("0x...")
amount_in = 1 * 10**18  # 1 token with 18 decimals

# 2) Get quote
amount_out, route = router.functions.getV2Quote(
    tk_in, tk_out, amount_in
).call()

# 3) Slippage protection
min_out = amount_out * 98 // 100  # 2% slippage

# 4) Build transaction (from an EOA you control)
from_addr = Web3.to_checksum_address("0xYourEOA...")
nonce = w3.eth.get_transaction_count(from_addr)

tx = router.functions.dexV2Swap(
    route,
    amount_in,
    min_out,
    tk_in,
    tk_out,
).build_transaction({
    "from": from_addr,
    "nonce": nonce,
    "gas": 600000,
    "gasPrice": w3.to_wei("0.1", "gwei"),
})

# 5) Sign & send
signed = w3.eth.account.sign_transaction(tx, private_key="YOUR_PRIVATE_KEY")
tx_hash = w3.eth.send_raw_transaction(signed.rawTransaction)
print("Swap submitted:", tx_hash.hex())
// Solidity (contract-to-contract usage)
// Note: On-chain swaps require this contract to hold/receive tkIn and to approve NeuyRouter.
// Quotes: if your router's quote is non-view on some deployments, you can't "read" it on-chain without a tx.
// Common pattern: quote off-chain, then pass route + minOut into your contract call.

pragma solidity ^0.8.20;

interface IERC20 {
  function approve(address spender, uint256 amount) external returns (bool);
  function transferFrom(address from, address to, uint256 amount) external returns (bool);
}

interface INeuyRouter {
  function getV2Quote(address tkIn, address tkOut, uint256 amountIn)
    external
    view
    returns (uint256 amountOut, uint256 route);

  function dexV2Swap(uint256 route, uint256 amountIn, uint256 amountOutMin, address tkIn, address tkOut)
    external
    returns (uint256 amountOut);
}

contract NeuyRouterSwapExample {
  INeuyRouter public immutable router;

  constructor(address routerAddress) {
    router = INeuyRouter(routerAddress);
  }

  // User must approve THIS contract for tkIn first.
  function swapV2(
    address tkIn,
    address tkOut,
    uint256 amountIn,
    uint256 slippageBps // e.g. 200 = 2%
  ) external returns (uint256 amountOut) {
    // Pull tkIn from user
    IERC20(tkIn).transferFrom(msg.sender, address(this), amountIn);

    // Get quote (only works if getV2Quote is view on your deployment)
    (uint256 quotedOut, uint256 route) = router.getV2Quote(tkIn, tkOut, amountIn);

    // Apply slippage protection
    uint256 minOut = (quotedOut * (10_000 - slippageBps)) / 10_000;

    // Approve router to spend tkIn
    IERC20(tkIn).approve(address(router), amountIn);

    // Execute swap
    amountOut = router.dexV2Swap(route, amountIn, minOut, tkIn, tkOut);

    // (Optional) send tkOut to user if tkOut ends up in this contract
    // IERC20(tkOut).transfer(msg.sender, amountOut);
  }
}

5. Getting quotes

NeuyRouter exposes multiple quote functions. All quote endpoints are read-only and can be called from a public or private RPC.

5.1 getV2Quote

Returns the best V2-style route and amountOut for a given ERC20 > ERC20 input.

  • tkIn: input token address
  • tkOut: output token address
  • amountIn: input amount (uint256)
  • returns: (amountOut, routeId)
// JS example
const [amountOut, route] = await router.getV2Quote(tkIn, tkOut, amountIn);

5.2 getV3Quote

Returns a V3-style quote when available on the underlying chain / pools. Usage mirrors getV2Quote:

const [amountOutV3, routeV3] = await router.getV3Quote(tkIn, tkOut, amountIn);

5.3 getSplitV2Quote

Returns a split-route quote across two V2 paths: (amountOut, route1, route2).

const [amountOutSplit, route1, route2] =
  await router.getSplitV2Quote(tkIn, tkOut, amountIn);

6. ERC20 <> ERC20 swaps

For ERC20 <> ERC20, approve NeuyRouter to spend your input token, then call one of the swap functions with a route obtained from the quote functions.

6.1 dexV2Swap

  • route: route id from getV2Quote
  • amountIn: exact input amount
  • amountOut: minimum output (slippage protected)
  • tkIn: input token
  • tkOut: output token
const [amountOut, route] = await router.getV2Quote(tkIn, tkOut, amountIn);
const minOut = amountOut.mul(98).div(100); // 2% slippage

const tx = await router.dexV2Swap(
  route,
  amountIn,
  minOut,
  tkIn,
  tkOut
);
await tx.wait();

6.2 dexV3Swap

Similar to dexV2Swap, but uses V3 routing if supported by the router on that chain.

const [amountOutV3, routeV3] = await router.getV3Quote(tkIn, tkOut, amountIn);
const minOutV3 = amountOutV3.mul(98).div(100);

const tx = await router.dexV3Swap(
  routeV3,
  amountIn,
  minOutV3,
  tkIn,
  tkOut
);
await tx.wait();

6.3 dexSplitV2Swap

Executes a split V2 swap using two routes returned by getSplitV2Quote.

const [amountOutSplit, route1, route2] =
  await router.getSplitV2Quote(tkIn, tkOut, amountIn);

const minOutSplit = amountOutSplit.mul(98).div(100);

const tx = await router.dexSplitV2Swap(
  route1,
  route2,
  amountIn,
  minOutSplit,
  tkIn,
  tkOut
);
await tx.wait();

7. Native <> token swaps (V2 chains only)

On V2 chains only (Arbitrum, Avalance, Binance), NeuyRouter exposes dedicated endpoints for native gas token <> ERC20 swaps. On other chains (V1), wrap/unwrap native assets yourself and then use ERC20 routes.

7.1 dexV2NativeSwapETHToToken or dexV2NativeSwapBNBToToken or dexV2NativeSwapAVAXToToken

  • route: route id from getV2Quote (using wrapped native)
  • amountOutMin: minimum ERC20 out
  • tkOut: ERC20 token to receive
  • msg.value: native amount in
// Example: on Arbitrum (ETH > token)
// 1) Quote using wrapped native (e.g. WETH) for tkIn
const [amountOut, route] = await router.getV2Quote(
  WETH_ADDRESS,
  tkOut,
  amountIn
);
const minOut = amountOut.mul(98).div(100);

const tx = await router.dexV2NativeSwapETHToToken(
  route,
  minOut,
  tkOut,
  { value: amountIn }
);
await tx.wait();

7.2 dexV2NativeSwapTokenToETH or dexV2NativeSwapTokenToBNB or dexV2NativeSwapTokenToAVAX

  • route: route id from getV2Quote (tkIn > wrapped native)
  • amountIn: ERC20 amount in
  • amountOutMin: minimum native out
  • tkIn: ERC20 token you’re selling
const [amountOut, route] = await router.getV2Quote(
  tkIn,
  WETH_ADDRESS,
  amountIn
);
const minOut = amountOut.mul(98).div(100);

// tkIn must be approved for router.address
const tx = await router.dexV2NativeSwapTokenToETH(
  route,
  amountIn,
  minOut,
  tkIn
);
await tx.wait();

7B. Native > token swaps (V3)

On some chains we support native gas token swaps through a dedicated Uniswap V3 endpoint. This allows users to buy tokens like NEUY using native gas (ETH / MATIC / BNB / AVAX) while still executing against V3 pools.

7B.1 dexV3NativeSwap

  • route: V3 fee tier selector (0..2)
  • amountOut: minimum output amount (slippage protected)
  • tkOut: ERC20 token to receive
  • msg.value: native input amount

Routes (V3 fee tiers):

Route Pool fee Notes
0 1.00% (10000) Default / wider-liquidity pools
1 0.30% (3000) Common V3 tier
2 0.05% (500) Tight spread pools

Native sentinel address: In NeuyRouter integrations, the native gas token may be represented by: 0x0000000000000000000000000000000000001010. For quotes, you should always substitute the wrapped token address (WETH/WMATIC/etc.). For native swaps, call dexV3NativeSwap and pass native via msg.value.

JavaScript example (ethers.js)


// Example: Native (ETH/MATIC/etc) -> NEUY using V3 pools
// 1) Quote using WRAPPED native token as tkIn (WETH/WMATIC/etc)
// 2) Execute dexV3NativeSwap with msg.value = amountIn

const amountIn = ethers.utils.parseEther("0.05"); // native amount in

// Use wrapped token for quotes (example shown with WETH)
const tkInForQuote = WETH_ADDRESS;
const tkOut = NEUY_ADDRESS;

// Get best V3/V4 quote (this returns an amountOut and a route)
// Note: dexV3NativeSwap supports V3 routes 0..2 only.
const [amountOutQuoted, route] = await router.getV3Quote(tkInForQuote, tkOut, amountIn);

// Apply slippage (example: 2%)
const minOut = amountOutQuoted.mul(98).div(100);

// Ensure route is in 0..2 for V3 native swap
if (route.gt(2)) {
throw new Error("Best route was not V3 (0..2). Use dexV3Swap with wrapped native instead.");
}

// Execute native swap (msg.value sends native gas token)
const tx = await router.dexV3NativeSwap(
route,
minOut,
tkOut,
{ value: amountIn }
);

const receipt = await tx.wait();
console.log("dexV3NativeSwap tx:", receipt.transactionHash);

Notes: (1) This endpoint is specifically for native > ERC20 via V3 pools. (2) Quotes should be performed using the wrapped native token address even if your UI uses the native sentinel.

8. balanceOf

The router contract also exposes a simple balanceOf view, which can be used for tracking balances where appropriate.

const bal = await router.balanceOf("0xYourAddress");
console.log("Balance:", bal.toString());

The NeuyRouter Swap UI supports optional URL parameters that pre-select the From and/or To token. This is useful for linking from docs, dashboards, or token pages so users land directly on the correct pair without clicking dropdowns.

Parameters are validated in JavaScript before being applied. If a token block is incomplete or invalid, it is ignored (the user can still pick tokens manually).

Supported parameters

Parameter Description Validation rules
fromtoken From token address Must be a 42-character hex address (0x + 40 hex chars)
fromsymbol From token symbol 1-7 characters (longer symbols are trimmed)
fromdecimals From token decimals Integer 0-18
totoken To token address Must be a 42-character hex address (0x + 40 hex chars)
tosymbol To token symbol 1-7 characters (longer symbols are trimmed)
todecimals To token decimals Integer 0-18

Behavior

  • If totoken, tosymbol, and todecimals are valid, the page calls: setToToken(totoken, todecimals, tosymbol)
  • If fromtoken, fromsymbol, and fromdecimals are valid, the page calls: setFromToken(fromtoken, fromdecimals, fromsymbol)
  • The From and To blocks are independent—either one may be provided on its own.

Example

This example pre-selects USDC > NEUY (addresses shown as examples):

swap.aspx?fromtoken=0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174&fromsymbol=USDC&fromdecimals=6&totoken=0xa80505c408C4DEFD9522981cD77e026f5a49FE63&tosymbol=NEUY&todecimals=18

Tip: If you generate these links programmatically, always URL-encode values and keep decimals accurate (0-18). Invalid or partial parameter sets are safely ignored.

10. Fees, routing, and best practices

  • A small protocol fee (max ~0.1%) may be applied only on positive surplus and routed back into NEUY buybacks / staking pools.
  • Always apply your own slippage guard by reducing the quoted amountOut (for example, multiply by 0.98 for 2% slippage).
  • Low-liquidity routes or highly volatile pairs may revert; catch and handle reverts in your integration.
  • Use a dedicated read-only RPC endpoint for quote spam if you are building automated arbitrage or routing bots.

For more examples (including front-end integrations and arbitrage scripts), see the public repository: github.com/NEUYTeam/NeuyAI .

11. Risk Disclosure

The NeuyRouter contracts operate autonomously on public blockchain networks and are not monitored, controlled, or upgraded by NeuyAI once deployed. By choosing to interact with these contracts, you assume full responsibility for all associated risks, including but not limited to smart-contract bugs, market volatility, failed transactions, slippage, and loss of funds. NeuyAI provides no warranties and disclaims all liability for any damages arising from the use of this protocol.