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 |
Limited | Not ideal | Not ideal | Not ideal | Not 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
- V2: Arbitrum, Avalanche, Binance
- V1: Base, Ethereum, Polygon
2. Networks & contract addresses
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
"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)",
]
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: "0xf3353E829A2780770E0bc7006291a3F6503aF2Cf", // V3
avalanche: "0x4A915b60f7ea6D086F14F3A9B059D635c526E375", // V3
bsc: "0xCD69c734Cd207d4b2e3Dd51E6fa1E7E13532eEF7", // V3
base: "0x5333f0ac0Bd4Aa5eb68fbbace840971a2b6AB866", // V3
ethereum: "0x91a6D8c359d0B96Ae14573442C990Aec8e3D45b4", // V3
polygon: "0x0CEb000b9B3866F7B02e1ab47c6D605edDDdD8C6" // 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
ROUTERS = {
"arbitrum": "0xf3353E829A2780770E0bc7006291a3F6503aF2Cf", # V3
"avalanche": "0x4A915b60f7ea6D086F14F3A9B059D635c526E375", # V3
"bsc": "0xCD69c734Cd207d4b2e3Dd51E6fa1E7E13532eEF7", # V3
"base": "0x5333f0ac0Bd4Aa5eb68fbbace840971a2b6AB866", # V3
"ethereum": "0x91a6D8c359d0B96Ae14573442C990Aec8e3D45b4", # V3
"polygon": "0x0CEb000b9B3866F7B02e1ab47c6D605edDDdD8C6", # 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())
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):
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());
9. Deep linking the Swap UI via URL parameters
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
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.