1inch
A OneInch exchange object connects to the 1inch aggregator: quotes and transaction data come from the 1inch Swap API v6.0 (which splits and routes orders across 1inch's many liquidity sources), and the docker signs them with the configured private key and sends them to 1inch's router contract AggregationRouterV6 (0x111111125421cA6dc452d289314280a0f8842A65). One exchange object covers one chain: Ethereum, Arbitrum, Base, BNB Chain, Unichain, Polygon or OP Mainnet. An API key from the 1inch developer portal is required in the exchange configuration.
It is the aggregator version of the same implementation as the Uniswap exchange object: the token table, balances, approvals, orders, cancels, transfers and wrapping work the same way; the difference is that the swap route comes from 1inch.
Names and Configuration
exchange.GetName(): OneInch (Spot).
| Field | Required | Default | Description |
|---|---|---|---|
| Chain | Yes | Ethereum | Options: Ethereum, Arbitrum, Base, BNB Chain, Unichain, Polygon, OP Mainnet |
| Private Key | Yes | — | Wallet private key (hex). |
| Rpc Address | No | https://ethereum-rpc.publicnode.com,https://eth.drpc.org | RPC node URL; several nodes separated by commas fail over to each other when one errors or lacks data; when empty, each chain's built-in default (a primary node plus a backup, comma-separated) is used. (more below the table) |
| 1inch Api Key | Yes | — | API key from the 1inch developer portal (required), sent as Authorization: Bearer <key>. |
The rest of the longer descriptions in the table:
- Rpc Address: Order states need a node that returns receipts of mined transactions; the publicnode public nodes for Base, BNB Chain and Arbitrum cannot (archive access is required), so do not use them alone. RPC nodes are used without authentication.
Trading Pairs and Contract Codes
Pair examples: ETH_USDC, WETH_USDC, POL_USDT0
Pairs are written as ETH_USDC; the native coin (ETH, BNB, POL) and its wrapped token (WETH, WBNB, WPOL) are different assets. The native coin of Polygon is POL; USDT on Unichain and Polygon is written as USDT0.
The token table is the one of the Uniswap exchange object on the same chain; other tokens can be used in pairs after registering them with exchange.IO("token", name, address), and exchange.GetMarkets() lists the pairs of the token table that have a Uniswap pool on the chain.
Exchange-specific IO Commands
| Command | Arguments | Description | Returns |
|---|---|---|---|
transfer | to, amount[, token] | Transfer the native coin or an ERC20 token out of the configured wallet (token is a token name or contract address, the native coin when omitted); amount may be all (the native coin keeps the fee). Waits for the broadcast only, not for confirmation. See the sub-page exchange.IO("transfer", ...). | {txHash, from, to, token, tokenAddress, amount, raw} |
receipt | txHash[, waitMs] | Query the receipt of any transaction on this chain (not only those sent by this exchange object), optionally waiting for confirmation (up to 10 minutes). For an order, pass the transaction hash after the comma in the order ID. See the sub-page exchange.IO("receipt", ...). | {txHash, status, blockNumber, gasUsed, fee} once mined (status is success or reverted), {txHash, pending: true, known} otherwise. |
route | symbol, side, qty | Quote only, no order. The aggregator has a single candidate route (such as 1inch:ETH-USDC); buy quotes receiving qty base (approximated with several exact-input quotes), sell quotes selling qty base. See the sub-page exchange.IO("route", ...). | {symbol, side, qty, best, quote, price, candidates} |
simulate | symbol, side, qty[, price[, stateOverride]] | Build the swap transaction with the order logic (quoting, price protection, building the transaction with 1inch) and only simulate it with eth_call; nothing is signed, broadcast or paid. See the sub-page exchange.IO("simulate", ...). | {route, exactIn, amountIn, amountOut, quoted, executed, value, calls}, plus allowanceOverride when an allowance was supplied. |
token | [name, address] | Register a token so it can be used in pairs; without arguments, list the token table. See the sub-page exchange.IO("token", ...). | {symbol, address, decimals} when registering, an array of {symbol, address, decimals, native} when listing. |
wrap | amount | Wrap the native coin into its wrapped token (e.g. ETH→WETH), 1:1 without slippage, gas only; all is not accepted (gas must remain). See the sub-page exchange.IO("wrap", ...). | {txHash, action, from, to, amount, raw} |
unwrap | amount | Unwrap the wrapped token into the native coin (e.g. WETH→ETH); amount may be all. See the sub-page exchange.IO("unwrap", ...). | {txHash, action, from, to, amount, raw} |
approve | ["exact" | "max"] | Token approval mode (tokens are approved directly to the 1inch router contract, not through Permit2): exact (default) approves only what the swap needs, max grants an unlimited allowance. Queries when called without an argument. See the sub-page exchange.IO("approve", ...). | The current mode. |
slippage | [ratio] | Slippage protection of market orders, range [0, 0.5), default 0.005 (0.5%). Queries when called without an argument. See the sub-page exchange.IO("slippage", ...). | The current slippage ratio. |
deadline | [seconds] | Transaction deadline in seconds, 10 to 86400, default 120. Queries when called without an argument. Transactions built by 1inch carry no deadline, so the setting has no effect on swaps of a OneInch exchange object. See the sub-page exchange.IO("deadline", ...). | The current deadline (seconds). |
cancelWait | [seconds] | How long a cancel waits for the result, in seconds, 0 to 600, default 30; 0 returns right after the cancel transaction is sent. Queries when called without an argument. See the sub-page exchange.IO("cancelWait", ...). | The current wait time (seconds). |
gasMultiplier | [x] | Gas limit multiplier, 1 to 5, default 1.2; a transaction's gasLimit is the node's gas estimate times this value. The gasLimit is only a cap; the gas actually used is what is charged. Queries when called without an argument. See the sub-page exchange.IO("gasMultiplier", ...). | The current multiplier. |
base | [url] | Without an argument, returns the current node address; with an address, switches the node. Several nodes are written as one comma-separated string (with an array only the first address is used). After a switch, the first request checks which chain the node is on and fails if it is not the configured chain. | The previous address. |
sendBase | url | Set a node used only to broadcast transactions (a private transaction channel). Unlike Web3, it does not return the previous address, does not query when called without an argument, and an empty string does not clear the setting. | true |
address | — | The wallet address of the configured private key (lowercase, starting with 0x). | — |
contracts | — | The deployment on this chain, with the same fields as the Uniswap exchange object: dex is 1inch and router is the 1inch router contract; quoterV2, v3Factory, v4 and the like are the chain's Uniswap deployment (used to list markets and estimate USD prices), and aerodrome is null; tokenList gives the generation time of the built-in token table and its token count on this chain. | — |
bridge.chains | — | Chains supported by the bridge (LI.FI): EVM chains and Solana, cached for an hour. See the sub-page exchange.IO("bridge.*", ...). | An array of {id, key, name, chainType, nativeToken}, chainType being EVM or SVM. |
bridge.tokens | [chain] | Tokens LI.FI knows on a chain (this chain by default), cached for an hour. See the sub-page exchange.IO("bridge.*", ...). | An array of {symbol, address, decimals, name, priceUSD}. |
bridge.quote | params | A bridge quote (read-only) from this exchange object's chain. See the sub-page exchange.IO("bridge.*", ...). | {tool, toolName, fromChain, toChain, toChainName, fromToken, toToken, fromAmount, toAmount, toAmountMin, fromAmountRaw, toAmountRaw, toAmountMinRaw, fromAmountUSD, toAmountUSD, slippage, toAddress, feeCosts, gasCosts, executionDuration, approvalAddress, steps, transactionId, request}: amounts are in token units (*Raw in the smallest unit); toAmountMin is the amount guaranteed after slippage; feeCosts is [{name, amount, token, amountUSD, percentage, included}] (fees with included false are paid on top); gasCosts estimates source-chain gas; executionDuration is the expected time in seconds; approvalAddress is the contract to approve (null for the native coin and on Solana); steps lists the steps (cross bridges, swap swaps); request echoes the parameters. |
bridge.simulate | params|quote[, stateOverride] | Re-quotes and runs LI.FI's transaction with eth_call: nothing is signed, broadcast or paid. See the sub-page exchange.IO("bridge.*", ...). | The bridge.quote result plus simulated (true), to, value and walletBalance, and allowanceOverride when an allowance was supplied. |
bridge.send | params|quote | Bridges out: re-quotes → checks the balance → approves LI.FI's approvalAddress when the token allowance is short (following exchange.IO("approve") exact/max, resetting USDT-like tokens to zero first, waiting for the approval to be mined and re-quoting after it) → simulates with eth_call → signs and broadcasts, with a gas limit of the larger of the eth_estimateGas estimate × gasMultiplier and LI.FI's suggested gasLimit (bridge contracts call into other contracts, so the estimate can fall short; only the gas used is charged). See the sub-page exchange.IO("bridge.*", ...). | {txHash, tool, fromChain, toChain, toChainName, fromToken, toToken, fromAmount, toAmount, toAmountMin, toAddress, value, transactionId}; txHash is the source-chain transaction, whose receipt receipt returns. |
bridge.status | txHash[, options] | Bridge progress (LI.FI /status) for the source-chain transaction hash returned by bridge.send; options may give {toChain, bridge} to speed up the lookup. See the sub-page exchange.IO("bridge.*", ...). | {status, substatus, substatusMessage, tool, sending, receiving, fromAddress, toAddress, explorer, bridgeExplorer}: status is NOT_FOUND, INVALID, PENDING, DONE or FAILED; when DONE, substatus is COMPLETED (delivered as quoted), PARTIAL (a different token arrived) or REFUNDED; sending and receiving are {txHash, txLink, chainId, amount, amountRaw, token, timestamp}, with receiving.amount and receiving.token being what actually arrived. |
bridge.apiKey | [key] | Sets the LI.FI API key (header x-lifi-api-key, for this exchange object only, never echoed); "" clears it and no argument just queries. Without a key requests are rate-limited per outgoing IP, see below. See the sub-page exchange.IO("bridge.*", ...). | Whether a key is set (a boolean). |
For the common command currency see exchange.IO.
The common command api is not supported (the call fails with an error and returns null).
Function Support
Not supported (the call fails with an error and returns null): exchange.GetTickers, exchange.GetHistoryOrders, exchange.ModifyOrder, exchange.CreateConditionOrder, exchange.ModifyConditionOrder, exchange.CancelConditionOrder, exchange.GetConditionOrder, exchange.GetConditionOrders, exchange.GetHistoryConditionOrders, exchange.GetTrades.
Served through a fallback:
exchange.GetRecords: Native periods are 1m, 5m, 15m, 1h, 4h, 12h, 1d (GeckoTerminal's timeframes); other periods of a minute or longer are synthesized by the docker, while second-level periods are unavailable (there is no trade feed to build them from).
Notes
| Function | Behavior on 1inch |
|---|---|
| exchange.GetTicker() | Bid and ask are 1inch quotes for about $1000; there are no 24h statistics. The two sides are quoted separately and their best sources can differ (such as different market-maker quotes on Base), so two individually executable quotes occasionally cross (bid above ask); both sides then report the mid price and Info.crossed gives how far they crossed |
| exchange.GetDepth() | Derived from 1inch quotes at increasing sizes (one quote per level and side, queued with back-off and retries when rate-limited, one per second on the free plan, so 10 levels take about 25 seconds); if a quote fails midway, the levels already obtained are returned (none are made up) with the reason in Info.partial, and it fails only when no level was obtained; when the two sides' best sources differ and cross, crossed prices are reported at the mid price with quantities unchanged, and Info.crossed gives the mid price and how far it crossed |
| exchange.GetRecords() | K-lines come from GeckoTerminal's pool-level data: an aggregator has no pools of its own, so the pair's pool (on any DEX) with the largest USD liquidity on GeckoTerminal is used (searched among the top 20 pools of each of the two tokens for one holding exactly this pair; the chosen pool is cached for an hour). Prices are that pool's trade prices (including the pool fee, so they may differ from the mid price of exchange.GetTicker() by about one pool fee) in quote per base, and Volume is in the base token; periods without trades repeat the previous close with zero volume, and the last bar may still be open. GeckoTerminal data lags by tens of seconds up to a minute and its public API allows about 10 requests per minute: bars of the same period are cached for a minute, requests queue inside the docker and wait and retry when rate-limited, and fail if that still does not succeed. Fails when GeckoTerminal has no pool of the pair |
| exchange.GetAssets() | Wallet balances of the native coin and of the tokens in the token table |
| exchange.CreateOrder() | Swaps on chain immediately: a limit price is the worst acceptable fill, market orders are protected by the slippage setting; a market buy is sized in the quote currency. 1inch supports exact input only: a limit buy is executed as "spend at most amount × price and receive at least amount", so the amount actually bought may be slightly more than the order amount. The order extra parameter slippage overrides the slippage for that order; route does not apply to an aggregator and fails with route is not applicable to the 1inch aggregator |
| exchange.GetOrder() | The order ID looks like ETH_USDC,0x… (the pair, a comma, then the transaction hash); the state comes from the transaction receipt, and the order is reported as canceled once the nonce of the original transaction has been taken by the cancel transaction (or another transaction). The 1inch router has no unified fill event: tokens are counted from the wallet's incoming and outgoing transfers in the transaction receipt; when the native coin is received, the amount is the wallet's balance difference between the transaction's block and the previous block plus the fee (inaccurate if the wallet has other transactions in the same block) |
| exchange.GetOrders() | Lists only the swap transactions sent by this exchange object during the current run that are not yet mined |
| exchange.CancelOrder() | Sends a replacement transaction with the same nonce (a zero-amount transfer to itself) and waits for the result (at most 30 seconds by default, see exchange.IO("cancelWait", ...)): returns true if the cancel transaction lands first; if the original order is already mined or lands first, it returns false (the cancel did not happen, but this is not a call error), with the reason in exchange.GetLastError(); returns true on timeout, meaning the cancel has been submitted, and exchange.GetOrder() gives the final state |
The 1inch free tier allows 1 request per second; the connector queues requests automatically and waits and retries when rate-limited (HTTP 429).
Complete runnable strategies (DEX-CEX arbitrage, dollar-cost averaging) are in DEX Strategy Examples.
Cross-chain bridge
exchange.IO("bridge.*", ...) bridges tokens from this exchange object's chain to another chain through the bridges LI.FI aggregates (Across, Stargate, CCTP, deBridge, Mayan, Relay, NEAR Intents and more), between EVM chains and between EVM and Solana (from this exchange object's chain). LI.FI supplies the quote and transaction, and the docker approves, simulates with eth_call, signs and broadcasts. Requests carry the integrator tag integrator=fmz and add no fee; fees in a quote such as LIFI Fixed Fee are LI.FI's and the bridges' own and are already deducted from toAmount.
Typical flow: bridge.quote for a quote → bridge.simulate to simulate → bridge.send to send → bridge.status every 10 to 30 seconds until DONE or FAILED.
- Bridging is asynchronous: when
bridge.sendreturns, only the source-chain transaction has been broadcast; delivery takes seconds to tens of minutes (seeexecutionDurationin the quote) and must be confirmed by pollingbridge.status;PARTIALmeans a different token arrived on the destination chain andREFUNDEDthat the funds went back to the source chain. - Cross-VM transfers (EVM↔Solana) require
toAddress, checked against the destination chain's address format; funds sent to a wrong address cannot be recovered. - Risks: the security of bridge contracts and cross-chain messaging rests with each bridge; quotes move, and
bridge.sendre-quotes before sending; the destination wallet needs gas to use what arrives. Test with a small amount first. - Rate limits: without an API key LI.FI limits by outgoing IP,
/quoteto 75 requests per 2 hours (bridge.quote,bridge.simulateandbridge.senduse one each, plus one more when re-quoting after an approval) and other endpoints to 100 per minute; strategies on the same docker share the quota. With a key set throughexchange.IO("bridge.apiKey", key)the limit is 100 per minute. A rate-limited call fails withrate limited (HTTP 429 …).