Odosswap token approvals: direct vs Permit2 in Odos Router V2
Odos Router V2 defines two authorization paths for ERC-20 inputs: an allowance granted directly to the router or a Permit2 signature backed by a separate token allowance to Permit2. The chosen swap function determines which permission applies.
UpdatedOdos's hosted trading and API services have shut down. Its July 23, 2026 wind-down announcement set July 27 for the app's read-only switch and July 30 for all company-operated services to end.
Direct allowances and Permit2
| Authorization detail | Direct allowance | Permit2 SignatureTransfer |
|---|---|---|
| Spender approved at the token contract | The Router V2 deployment on the selected network | The selected Permit2 contract |
| Permission needed for the input | Sufficient token allowance to the router | Sufficient token allowance to Permit2 plus a valid signed permit authorizing the router |
| V2 entry points |
swap
,
swapMulti
and their compact variants
|
swapPermit2
and
swapMultiPermit2
|
| Input transfer |
The router uses
SafeERC20.safeTransferFrom
to call the token's
transferFrom
|
The router calls Permit2's
permitTransferFrom
|
An allowance belongs to one owner, token contract and spender on a particular network. Approving that spender records permission for a later transfer; approval alone doesn't move the tokens or complete a swap. A sufficient remaining allowance can cover another transfer without a new token approval.
What the Permit2 signature covers
Router V2 uses Permit2's SignatureTransfer interface. Both Permit2 entry points pass the router caller,
msg.sender
, as the token owner. For
swapPermit2
, the signed token and permitted amount must match
inputToken
and
inputAmount
: V2 constructs both the token permission and requested transfer from those fields. The multi-swap entry point constructs a batch permission for its ERC-20 inputs.
The permit includes a nonce, deadline and signature. Its nonce must be unused and its deadline must not have passed; a successful transaction consumes the nonce. This one-use authorization is separate from Permit2's standing AllowanceTransfer permissions. Using or expiring the signature doesn't erase the underlying ERC-20 allowance to Permit2.
Worked example: Two spender allowances
Hypothetical inputs: requested swap input = 482 token units; allowance to the relevant Router V2 deployment = 312 token units; allowance to the selected Permit2 contract = 697 token units. All amounts concern the same wallet, token and network. Assume a standard ERC-20 with sufficient wallet balance and no unrelated transfer restrictions.
The direct
swap
path has an allowance shortfall of
482 - 312 = 170
token units, so its input transfer can't proceed with that allowance. The separate 697-unit Permit2 allowance doesn't reduce this shortfall because it authorizes a different spender.
For
swapPermit2
, 697 units covers the requested 482-unit transfer. That path also needs a valid signature authorizing the relevant Router V2 spender for this token and the exact 482-unit amount, with an unused nonce and an unexpired deadline. Meeting those authorization conditions doesn't guarantee the swap completes: route execution and output checks must also pass. Increasing the router allowance changes the direct-path shortfall; changing the Permit2 allowance doesn't.
Input amounts and transfer destinations
The allowance limit and swap input amount are separate values. V2's direct ERC-20 approval helpers interpret a zero input amount as the caller's full balance of that token.
swapMultiPermit2
also resolves zero ERC-20 input amounts to their full balances before constructing the batch permit. The single-token
swapPermit2
passes
inputAmount
unchanged, so zero isn't a universal full-balance instruction across V2 entry points. The selected spender still needs permission for the resolved transfer amount.
For ERC-20 inputs, the input receiver is the transfer destination and can differ from the approved spender: V2 uses the supplied
inputReceiver
for a single swap or each input's
receiver
for a multi-swap. In compact calls, a zero input receiver resolves to the executor. Output recipients are separate; a zero output receiver in those compact calls resolves to the caller.
Native-coin inputs use
msg.value
and don't require an ERC-20 allowance. The payable
swapMultiPermit2
path handles native value separately from its ERC-20 batch permit.
Reducing permissions after the shutdown
Token allowances are on-chain state, so closing a hosted service doesn't automatically revoke them. For a standard ERC-20,
approve(spender, 0)
clears the selected spender's allowance at that token contract on that network. It doesn't move a balance or reverse a completed swap.
Removing the allowance granted to Router V2 leaves the separate allowance granted to Permit2 unchanged. Clearing the token allowance to Permit2 also affects other integrations using that Permit2 instance for the same owner and token on that network. The owner can invalidate selected Permit2 signature nonces without changing the token allowance.