VimenZap internals
How the single-transaction mint/redeem router works under the hood.
VimenZap is a stateless router over Uniswap v4 (and, in v2, Rialto) that turns "buy N constituents, approve, mint" into one atomic transaction. It shares the basket contracts' trust model: no owner, no admin, no pause, no upgradeability, and it holds nothing between transactions.
The live router is VimenZap2
(0x99c8…12c1),
which supersedes v1
(still live and functional; stateless contracts don't need decommissioning).
zapMint
The user pays one currency (native ETH or USDG, both live in the app) and the router:
- buys the exact constituent amounts on Uniswap v4 using exact-output swaps (so zero dust remains),
- approves the basket and calls
mint, - sends the basket tokens to the recipient,
all inside one transaction. If any leg cannot fill, everything reverts:
no partial state, the user keeps their input. zapRedeem is the mirror:
burn the basket, sell every constituent, receive one currency, protected by
a minOut floor.
The caller supplies the swap path per constituent (the app maintains the
route map); the contract enforces path endpoints, connectivity, exact fill,
maxSpend/minOut and a deadline. In v2, individual legs can alternatively
be filled through the Rialto router, with the contract verifying
coverage (each leg exactly once) and sweeping any surplus back to the user.
Rialto legs are USDG-only; the mixed-venue entry points reject native ETH.
The native-ETH path
ETH is address(0)/msg.value to the router: a single payable zapMint,
no approval and no Permit2 signature, with unspent msg.value refunded
automatically. Routes are rebased onto ETH: legs whose pools are ETH-quoted
drop the main-pair hop (one hop cheaper than the USDG path), while
USDG-quoted legs gain the 0.05% ETH/USDG hop. The frontend's impact gate
converts each constituent's Chainlink fair value through the ETH/USD feed to
score ETH-paid legs, and blocks the ETH path entirely if that feed is stale.
Exact quoting: the v4 unlock trick
quoteZapMint / quoteZapRedeem run the real swaps inside a Uniswap v4
unlock and then revert, carrying the amounts out in the revert data. An
eth_call therefore returns the exact execution numbers (same math,
same pools, same block) with no token balance needed and no dependency on a
deployed quoter. Fork tests assert quote == execution in the same block.
This is why the app's zap quotes aren't estimates with slippage guesswork: what you see is what would execute right now.
The 5% per-leg impact gate
The frontend scores each leg's quoted execution against the constituent's
oracle (Chainlink) price and disables the whole zap when any leg's premium
exceeds MAX_LEG_IMPACT (5%). Thin pools disable the zap loudly instead of
overcharging quietly; as pools deepen, legs re-enable automatically with
zero code changes. zapAvailable() keeps any not-fully-routable basket from
ever showing the "Pay with" toggle.
Permit2: one signature per mint
zapMintPermit2 accepts a Permit2
SignatureTransfer: the user signs (token = USDG, amount = maxSpend,
spender = router) off-chain, and the router pulls only the actual cost
directly into the PoolManager. Per mint: one EIP-712 signature + one
transaction, and no allowance is ever granted to the router itself. The only
prerequisite is a once-ever ERC-20 approval of USDG to the canonical Permit2
(0x000000000022D473030F116dDEE9F6B43aC78BA3, verified deployed on
Robinhood Chain), surfaced in the UI as the one-time "Enable USDG" step.
Fork tests cover the signed path end to end, including nonce-replay
rejection.
Settlement details worth knowing
- Uniswap v4 sign conventions:
amountSpecified > 0means exact-output; swap deltas are from the router's point of view. An unlimited-price exact-output swap fills partially when range liquidity runs out instead of reverting; the router rejects any under-filled leg (LegUnderfilled). - Exact-output multi-hop paths execute in reverse; intermediate currencies net to zero inside the unlock.
- Settlement pulls the payer's USDG straight into the PoolManager
(
sync → transferFrom → settle); the router never custodies input funds. BasketToken.getRequiredUnitsrounds up andmintpulls exactly that, so the router's basket approvals return to zero by construction.
Liquidity reality
Robinhood Chain's deep stock inventory sits in Robinhood's own batch-settlement contract, which is not routable; public v4 pools are what the zap can reach. At launch: TSLA/NVDA/AAPL pools are healthiest, MSFT, AMZN, PLTR and MU are thin (protected by the impact gate), and the launch baskets were composed around this reality: all three are fully routable. If anyone LPs the thinner stock/USDG pools near the oracle price, zap quality improves basket-wide with no code changes.
Full contract API: VimenZap reference.