One transaction, one guarantee: how a Tirio swap settles
A split, multi-hop route settles in a single transaction that either delivers at least your minimum or does nothing. How the Router and Executor make that hold.
A route that splits your order across five pools and three tokens is a lot of moving parts. On Tirio, all of it runs inside one transaction that you sign once. Either the whole route works and you receive at least your minimum, or nothing happens and you pay only gas. There is no state in between where some of your tokens were swapped and the rest are stuck somewhere.
This post explains how the contracts make that hold, and why they are built the way they are.
Atomicity comes from the chain, the guarantee comes from the contract
Every transaction on an EVM chain is atomic. If any step reverts and the revert is not caught, every state change in the transaction is undone. That is the foundation, but it is not enough on its own. A route can complete "successfully" and still pay you badly. The useful guarantee is a stronger one: the transaction succeeds only if you receive at least the minimum you accepted. Tirio's Router enforces exactly that.
Two contracts with separate jobs
Tirio's on-chain side for swaps is two contracts, and the split between them is deliberate.
- The Router is the entry point. It is the contract you approve, it takes the fees, it enforces your minimum and your deadline, and it cannot be upgraded.
- The Executor runs the route the API built. It can be called only by the Router, holds no funds or allowances between transactions, ends every swap with a zero balance, and can be replaced by the owner.
Keeping the trust-critical rules in the Router means the part you approve stays small and fixed, while the part that runs routes can improve without ever asking you for a new approval.
Step by step
When your wallet sends a swap, the Router's swap function receives your parameters (the tokens, the amount, the minimum output, the recipient, the deadline and any partner fee), the route and an optional permit.
- Checks first. A transaction past its deadline reverts. Selling a token for itself reverts. A lock guards against re-entering the Router mid-swap.
- Your allowance stays with the Router. For a token input, the Router never hands your allowance to anyone. It moves only your input token, only up to the amount of this swap and only while this swap runs. For a native BNB input, the amount arrives with the transaction instead.
- The route runs. The Executor carries out every swap, split and wrap of the route and pays each pool what it is owed.
- The output lands. Either straight at your address from the last pools, or at the Router, which takes any fee that applies to the output and forwards the rest to you.
- The minimum is checked against reality. The Router compares how much the recipient's balance actually grew with your minimum. If it grew by less, the whole transaction reverts.
Why measure the balance and not a number
The Router could have trusted the amount the route reports. It does not, because reported numbers can be wrong. A token might take a tax on the way to you. A pool might behave oddly. A route might have a bug. By measuring the recipient's actual balance before and after, the check covers every one of those cases. What reaches you is what counts.
What the Executor can and cannot do
The Executor is the part that touches pools, so its limits matter more than its internals.
- It acts only inside your swap. Only the Router can call it, and the Router calls it only inside a swap you signed.
- It can use only what this swap allows. It never sees your allowance. It can work only with the input of the swap that is running, up to that swap's amount.
- It cannot lower your floor. Whatever the route does, the Router still checks the deadline and measures what reached the recipient against your minimum.
- Replacing it changes none of that. The owner can install a new Executor, and every rule above still applies to it, because the Router enforces them.
A clean finish
A swap should not leave dust or permissions lying around. The contracts are built so that it does not.
- No standing allowances in the Executor. It holds no approvals between transactions.
- Zero balance at the end. Intermediate tokens are passed on in full, so rounding never strands a remainder in the contract.
- Nothing carries over. What a swap uses while it runs is gone when the transaction ends, and two swaps in the same transaction cannot affect each other.
- Native refunds. If you pay with BNB and the route does not use all of it, as can happen in buy mode, the remainder goes back to you in the same transaction.
Fees, said plainly
Settlement is also where fees are charged, so it is worth stating them here. The Router's own protocol fee is 0 today. Swaps on tirio.io carry a 3 bps Tirio fee from the token you pay, charged as a partner fee, and a partner link replaces it with the partner's fee. On sales of an exact amount whose output token has no transfer tax, the output passes through the Router, which keeps anything above the quoted output up to 1 % of it and forwards everything beyond that cap. The contract hard-caps a partner fee at 10 % and the kept surplus at 1 % of the quoted output. The details are in our fee overview.
How we test it
The contracts are covered by fuzz suites that randomise fees, partner settings and permits, invariant tests that drive random sequences of calls and check properties the contracts must always keep, and mainnet-fork tests that run real swaps against real pools with real tokens. Every quote a user signs is also simulated as this exact transaction before it is returned, which our post on quote simulation covers.
What it means for you
- One signature, one transaction, however complex the route.
- A hard floor. You get at least your minimum, measured at your address, or nothing changes.
- A fixed contract to approve. The Router can move only the token you are selling, only up to that swap's amount and only inside a swap you sent.
The contract interfaces, addresses and events are documented on our contracts page.