INDEXon docs
INDEXon keeps a portfolio of Ondo tokenized stocks and ETFs at the weights you choose, and trades it back to target through Uniswap when prices pull it off.
What you get
- Ondo stocks and ETFs on Ethereum. Any Ondo token with a Uniswap USDC pool (NVDAon, SPYon, TSLAon, QQQon, AAPLon and more), plus USDC as cash. Most Ondo tokens have no Uniswap pool yet; more become available as liquidity is added.
- Your weights, your band. Whole-percent weights that add up to 100, and a drift band of 3%, 5% or 10%.
- Hands-off or hands-on. Let the keeper rebalance when a holding leaves its band, or press Rebalance yourself, for free.
- Custody stays with your wallet. Only your wallet can deposit, change the mix or withdraw, any time, without the keeper.
The parts
| Part | What it does |
|---|---|
IndexonVault | One contract holding every portfolio, with per-portfolio balances, weights and band. |
| Uniswap v4 and v3 | Each trade routes to the deepest USDC pool for that asset. v4 legs share one PoolManager unlock. |
| Chainlink | Ondo price feeds bound fills onchain for the assets that have one. |
| Keeper | A bot that checks drift every 5 minutes, around the clock, and rebalances opted-in portfolios. Anyone can run one. |
Who it's for
Ondo tokenized stocks are offered only outside the United States. INDEXon is not available to US persons, and you need to be allowed to hold Ondo tokens where you live.
Start with How it works.
How it works
A portfolio is a set of target weights, a drift band, and the tokens that currently fill it.
- 01CreateWeights, band, keeper on or off
- 02DepositUSDC in, the mix bought in one tx
- 03DriftPrices pull weights off target
- 04RebalanceSells, then buys, back to target
- 05WithdrawAs tokens or USDC, any time
1. Create a portfolio
Pick up to 24 Ondo assets and give each a whole-percent weight. You can keep part of the portfolio in USDC as cash; cash is never traded away. Weights must add up to 100%.
Choose a drift band: how far a holding may move away from its target, in percentage points of the portfolio, before a rebalance is due. With a 5% band, a holding targeted at 30% can range from 25% to 35%.
Decide whether the keeper may rebalance for you. You can change this later.
2. Deposit
Deposit USDC and INDEXon buys the mix in the same transaction: the app splits your deposit by weight, quotes every leg on Uniswap, and sends the trades with a minimum output on each. You can also keep the deposit as cash, or move in Ondo tokens you already hold.
3. Drift
Prices move every trading day, so the actual weights drift from the targets. The app shows this as the level line: each holding's distance from its target, with its band shaded. A bar past the band turns red.
4. Rebalance
When any holding leaves its band, a rebalance:
- sells what is overweight into USDC,
- then buys what is underweight with that USDC,
in a single transaction. Sells always come before buys, which the contract enforces. Trades smaller than $5 are skipped as dust.
One transactionrebalance(portfolio, trades)
1 Sell what is over
- NVDAonUSDC$1,008
2 Buy what is under
- USDCSPYon$353
- USDCTSLAon$202
- USDCAAPLon$121
- QQQon$3, under $5: skipped
The keeper rebalances opted-in portfolios at most once an hour. You can rebalance your own portfolio at any time; it costs only gas and pool fees.
5. Withdraw
Withdraw 25%, 50% or 100%:
- As tokens: you receive that share of every holding.
- As USDC: the app sells that share of each holding and sends you USDC. Any holding with no usable pool is sent to you as the token.
Withdrawals never need the keeper, and they work even while the vault is paused for new activity.
Assets and routing
The vault can list every Ondo tokenized stock and ETF on Ethereum, but a portfolio can only buy what trades on Uniswap. Only some Ondo tokens have a usable USDC pool, and fewer can fill a $250 trade within 3% price impact; the rest have no USDC pool, or only junk pools with 10–90% fees that the vault refuses. As liquidity is added, more tokens qualify.
Where the liquidity is
Ondo tokens trade against USDC on both Uniswap v3 and v4. For many assets the deepest pool is on v3 (for example NVDAon, SPYon and TSLAon at the time of writing); for others it is on v4 (QQQon's 0.65% pool). When you pick assets for a portfolio, the app rates each one:
| Rating | Meaning |
|---|---|
| Deep | A $1,000 buy moves the price less than 0.5%. |
| Fair | Less than 2%. |
| Thin | More than 2%, or the quote failed. Size weights carefully. |
| No route | No USDC pool can fill $250 within 3%. Can't be added. |
How a trade is routed
For each leg, the app quotes every eligible USDC pool for that asset (all v3 fee tiers and every v4 pool) and picks the one that returns the most. The vault then checks the route itself:
Buy NVDAon with $1,000 USDC
- v30.3%canonical pool4.3121 NVDAon best
- v40.65%no hook4.2967 NVDAon
- v31%canonical pool4.2825 NVDAon
- v30.05%no liquidity–
- v490%fee over the 1% cap– refused
- v4: the PoolKey must pair the asset with USDC, use a static fee of at most 1%, and either have no hook or a hook the vault has approved. This refuses the junk pools charging 80–90% fees that exist for some Ondo tokens.
- v3: the pool must be the canonical Uniswap v3 pool for that pair and fee tier.
One unlock for every v4 leg
When a rebalance includes v4 legs, the vault opens a single PoolManager.unlock, runs every swap inside it, and settles each token once at the end (v4 flash accounting). v3 legs in the same rebalance swap inside that call too. The result: one transaction, one settlement per currency, however many v4 legs there are.
Prices
The app values holdings at the Chainlink Ondo feed when one exists and is fresh, and otherwise at the mid price of the asset's best pool. Chainlink publishes Ondo feeds on Ethereum for SPYon, QQQon, TSLAon, IAUon, SGOVon, BILon, USFRon, FLHYon and STRCon. For keeper trades the vault needs an onchain price for every holding: the Chainlink feed when fresh, otherwise the asset's 30-minute Uniswap v3 average price, and every keeper fill must land within 2% of it.
Fees
| Action | INDEXon fee |
|---|---|
| Create a portfolio, change the mix, deposit, withdraw | None (gas only) |
| Rebalance yourself | None (gas only) |
| Keeper rebalance | 0.1% of the traded amount + 0.50 USDC |
Every trade also pays the Uniswap pool's fee (typically 0.3%–1% for Ondo pairs), and some price impact in thin pools.
- Uniswap pool fees0.3% of $1,000$3.00
- Keeper fee0.1% of $1,000$1.00
- Keeper gasflat$0.50
- Rebalance yourselfpool fees only, plus gas$3.00
Hard caps
The contract owner can change the keeper fees, but never above limits written into the contract:
- at most 0.5% of the traded amount, and
- at most 5 USDC flat per keeper rebalance.
Keeper fees are taken from the portfolio's USDC after the trades. The 0.50 USDC goes to the keeper to cover gas; the percentage goes to the INDEXon treasury.
Keeper and trust
What the keeper does
The keeper is a bot that runs every 5 minutes, around the clock. For each portfolio that opted in, it:
- values every holding the same way the vault will (Chainlink where fresh, else the asset's 30-minute Uniswap v3 average price), and cross-checks against an independent off-chain price,
- skips the portfolio if nothing is past its band, if it was rebalanced in the last hour, or if any holding has no onchain price reference,
- plans sells and buys back to target and quotes each leg, using only routes the vault has approved,
- simulates the transaction, then sends it privately through Flashbots Protect so it can't be sandwiched.
What the contract enforces on the keeper
The keeper is not a custodian, and the vault doesn't simply trust it. A keeper rebalance:
- trades only inside the portfolio it names, and only if that portfolio opted in, at most once per cooldown (1 hour minimum, written into the contract),
- only through approved routes: specific Uniswap pools the vault lists, never a pool the keeper creates,
- only when the portfolio is actually past its band, valued onchain (Chainlink or a 30-minute v3 average price for every holding), and only if the trades end inside the band or at least halve the excess drift,
- with every fill within 2% of that onchain price.
It can't deposit, withdraw, change your mix or move tokens out of the vault.
- Opted in, and cooled downThe portfolio allows the keeper, and an hour has passed since its last keeper run.
- Approved pools onlyEvery leg uses a Uniswap pool the vault lists; never one the keeper made.
- Actually past its bandValued onchain; the trades must end in band or halve the excess drift.
- Fills within 2%Each fill lands within 2% of the onchain price (Chainlink, or a 30-minute v3 average).
All pass: the trades run
Any fails: reverts
The keeper can never deposit, withdraw, change your mix or move tokens out.
What you are still trusting
Within those limits, the keeper chooses when to trade and the minimum outputs. The worst a faulty keeper can do is trade a portfolio up to about 2% away from the reference price, once an hour, on trades that must reduce drift. If you'd rather not, switch the keeper off and rebalance yourself.
When a Chainlink feed pauses (for example around a stock split), the vault falls back to the asset's 30-minute Uniswap v3 average price. An asset with neither reference can't be keeper-rebalanced until one is available; you can always rebalance it yourself.
The contract owner
The owner can list assets, approve routes and price sources, change the keeper and treasury, set fees within hard caps, and pause new deposits and rebalances. Every change that could loosen the keeper's limits (new keeper, new routes, price sources, higher fees or slippage, shorter cooldown) waits behind a 48-hour public timelock, announced onchain with the exact call, so you have time to withdraw first. Tightening changes and pausing apply at once. There is no function that moves your holdings, and pausing never blocks withdrawals.
If the keeper stops
Rebalancing pauses. Everything else keeps working: you can rebalance and withdraw yourself.
Risks
Read this before depositing.
- Market risk. Ondo tokens track real share prices and can fall. Rebalancing keeps your mix; it does not protect its value.
- Smart contract risk. INDEXon's vault is tested against forks of Ethereum mainnet, but bugs are possible. Only deposit what you can afford to lose.
- Liquidity risk. Many Ondo tokens trade in thin pools. Trades may cost more than expected, be skipped, or fail; withdrawing as USDC may not be possible for every holding at every moment (you can always withdraw as tokens).
- Issuer risk. Ondo tokens are issued by Ondo Global Markets. The token contracts are upgradeable, can be paused, run a compliance check on every transfer, and let Ondo burn tokens from any address. A pause or compliance change could block trades or withdrawals of that token.
- Oracle risk. Chainlink Ondo feeds pause around corporate actions such as splits and update less often when the underlying market is shut. The vault refuses keeper trades on a stale feed; prices shown in the app can lag.
- Keeper risk. The contract bounds keeper trades to approved pools and to within 2% of an onchain price, but within that the keeper decides when and how to trade (see Keeper and trust).
- Regulatory risk. Ondo tokenized stocks are not offered to US persons and are restricted elsewhere. Make sure you're allowed to hold them.
Nothing here is investment, legal or tax advice.
Contracts
Key functions
function createPortfolio(bytes32 name, address[] tokens, uint16[] weights, uint16 bandBps, bool keeperEnabled) returns (uint256 id);
function deposit(uint256 id, uint256 usdcAmount, Trade[] buys);
function rebalance(uint256 id, Trade[] trades); // owner (free) or keeper (opted in, cooldown, fees)
function withdraw(uint256 id, uint16 shareBps, Trade[] sells, address to);
function setMix(uint256 id, address[] tokens, uint16[] weights);
function getPortfolio(uint256 id) view returns (Portfolio, address[] assets, uint16[] weights, uint256[] balances);
A Trade names the token, direction, exact input, minimum output and route:
struct Trade {
address token; // the Ondo token
bool sell; // true: token -> USDC
uint256 amountIn;
uint256 minOut; // must be > 0
Venue venue; // V3 or V4
uint24 fee; // <= 1%
int24 tickSpacing; // v4 only
address hooks; // v4 only: zero or an approved hook
}
Limits written into the contract
| Limit | Value |
|---|---|
| Assets per portfolio | 24 |
| Pool fee | at most 1% |
| Keeper fee | at most 0.5% + 5 USDC per rebalance |
| Keeper cooldown | 1 hour to 1 day |
| Keeper fill vs. onchain price | at most 5% (set to 2%) |
| Drift band | 1% to 20% |
| Timelock on loosening admin changes | 48 hours |
The vault deploys a small stateless helper, IndexonPricer, that reads Chainlink and Uniswap v3 average prices.
Source and tests live in the contracts/ folder of the repository.
Deployed contracts
On Ethereum mainnet, with source verified on Etherscan:
| Contract | Address |
|---|---|
| IndexonVault | 0xF49E9F6820652d2a9b7c9867edD81BEaEDa070E4 |
| IndexonPricer | 0xaf2F868E0a8e82194f6AEDB3D5D9b9D0dD212fcF |
| IndexonLaunch (deployment helper) | 0xDdD1ce8de04da0578E2a7B891F980d4129d5e9e2 |
A local mainnet fork writes its addresses to contracts/deployments/fork.json instead.