VimenDocs
Protocol

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:

  1. buys the exact constituent amounts on Uniswap v4 using exact-output swaps (so zero dust remains),
  2. approves the basket and calls mint,
  3. 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 > 0 means 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.getRequiredUnits rounds up and mint pulls 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.

On this page