Vetra Docs Open app

Docs

Vetra is a vault that provides liquidity to tokenized equities only while the New York stock market is shut, and holds plain USDG while it is open. This page is what it does, call by call, including the parts that can lose you money.

What it is

A tokenized stock trades every hour of the week. The exchange it tracks is open for 32 and a half of them. Vetra posts a liquidity band into the USDG pool at the closing bell, collects trading fees overnight, and unwinds back to USDG an hour before the next open.

The reason to bother is where an equity liquidity provider actually loses money. It is not spread across the day. It arrives in the minutes after the open, when everything that happened overnight is priced at once and a passive range is the last to know. Vetra is not there for that. It sits in cash for the 32 and a half hours of the regular session and quotes the rest.

One caveat worth putting near the top, because it is the honest limit of the idea. Pre-market trading starts at 04:00 New York and after-hours runs until 20:00, and both are real price discovery. The window in which no venue anywhere is quoting the underlying is about 88 hours a week, not the 130 the vault currently quotes. Roughly 42 of the hours it works have a live print behind them somewhere. Those hours are thin and the fees are real, but the pool is not blind in them, and a tighter schedule would hand them back.

It has never traded a night. There is no track record and neither contract has been audited.

A night, end to end

  1. 16:00 ET, deploy. The manager calls deploy. Half the committed USDG is swapped into the stock token, and both sides are minted as a concentrated position around the current price. The call reverts unless the calendar says the market is shut.
  2. Overnight, quote. The position sits in the Uniswap v4 USDG pool taking the 0.30% fee from whoever trades against it. Fees accrue to the position, not to a claimable balance.
  3. 08:30 ET, unwind. Anyone at all calls unwind. The band burns, fees come in, and any stock left over is sold back to USDG in the same transaction. The caller keeps 0.05% of the vault for having done it.
  4. 09:30 ET, flat. The bell rings against an empty position. The vault holds USDG only, and stays that way until the next close.

The calendar

0xF1b5c3dE1462eeACfa93D69410C209467DA1c2BF

Given a unix timestamp it returns one of three states: Closed, Unwind, or Open. It derives the New York civil date from the timestamp itself, including US Eastern daylight saving, then checks the weekday, the holiday list and the session bounds. There is no oracle, no keeper and no off-chain feed anywhere in it.

Regular session
09:30 to 16:00 New York
Early close
13:00 on a marked half day
Unwind window
the hour before the open
Daylight saving
second Sunday in March to first Sunday in November, computed on chain
Holidays loaded
27 closures and early closes, through 2028

The holiday list is the only human input, and the setter only moves one way: a day can be made more closed and never more open. The session bounds themselves are constants that no key can change. So the worst a stolen calendar key can do is mark a trading day as a holiday, which costs fees and risks nothing. Once the calendar is filled far enough ahead, ownership can be renounced and the contract becomes a pure function.

It is free for anyone to call. If you are building anything on this chain that should not act while the equity market is shut, use it.

The vault

0x5De64bDdbbC27322f3Ad7dcBdAf5Ddb19a279F5C

One vault, one pool: the AAPL and USDG pool at the 0.30% tier. Four calls matter.

deposit(assets)
Takes USDG, mints shares. Only while the vault is flat.
redeem(shares)
Burns shares, returns USDG. Only while the vault is flat.
deploy(...)
Manager only. Reverts unless the calendar says Closed.
unwind(minOut)
Anyone. Reverts while the calendar still says Closed.

Deposits and redemptions being open only while flat is the shape of the strategy rather than a restriction. With no position, a redemption is a token transfer instead of an unwind, and price per share is a balance instead of a valuation. It is also why nothing in the contract reads a price oracle: it never needs to mark a position it is holding, because during the hours you can enter and leave, it is not holding one.

The liquidity number passed to deploy is worked out off chain, in the browser. Too large a number and the settlement runs out of funds and the whole transaction reverts. Too small and the band is simply smaller than intended. A maxUsdgIn argument caps what the call may take out of the vault either way, checked against the vault's own balance afterwards.

Shares and price per share

Depositing mints vUSDG, an ordinary ERC-20 with six decimals, no transfer hook, no rebasing and no lockup. Because it is ordinary, another protocol can hold it as collateral without special handling, and it keeps accruing while it sits there.

Price per share is simply the vault's USDG divided by the shares outstanding. Fees harvested from a night land in the vault and mint nothing, so the number rises. A night that loses money lowers it. The first deposit mints one share per USDG and everything after that is priced off the ratio.

The unwind bounty

A band left out through the opening bell is the one thing this design exists to prevent, and a contract cannot wake anybody up. So the unwind is permissionless and paid: from the start of the unwind window, any address can call unwind, and the contract pays the caller 0.05% of the vault for doing it.

This is not a courtesy. It is the mechanism. It means an unwound band is somebody's payday rather than everybody's problem, and it removes the operator from the critical path entirely.

Why it is not a hook

The obvious way to enforce a schedule on a Uniswap v4 pool is a hook, and it cannot work here. A hook is bound to a pool when the pool is initialised, and the USDG pools these tokens actually trade in were created without one. Nothing can be attached afterwards.

So the rule lives in the contract that owns the liquidity instead. That trades a physical guarantee for two weaker but real ones: a band cannot be opened into a live session, because deploy reverts, and a band is unlikely to survive into one, because unwinding it pays. The upside of doing it this way is that it works on pools that already exist, with the depth already in them.

What you are trusting

The manager address can do exactly one thing: choose the band and open it, during the hours the calendar permits. It cannot:

  • move funds out of the vault
  • open a band while the market is open
  • stop anyone else from unwinding
  • block a deposit or a redemption
  • change the session hours, which are constants

The worst version of a malicious or absent manager is a vault that never opens a band and therefore earns nothing. The calendar owner is separate and can only add days off.

How it loses money

  • The gap. This is the trade. An earnings print at 16:05 walks straight through the band and the vault unwinds into it the next morning. One of those can undo a month of quiet nights on a concentrated name.
  • The round trip. Opening a band swaps half the commitment into stock and unwinding sells it back. Both legs pay the pool fee and move the price. On a quiet night that cost can exceed the fees earned, which is exactly what the fork tests show.
  • Extended hours. The vault quotes through pre-market and after-hours, where a real price exists elsewhere and somebody can arbitrage the pool against it. This is the weakest part of the current schedule and the first thing a second version would tighten.
  • Thin books. Wide overnight spreads are the reason there is a fee worth collecting and the reason unwinding costs more than it should.
  • Unaudited code. Two contracts, written by one person, holding real money on a young chain. This is the risk that does not show up in any model.
  • A wrong calendar. The holiday list is set by hand. A missing entry means the vault treats a closed day as a session and stays flat, which costs fees rather than money.

Addresses

Chain
Robinhood Chain, 4663
Calendar
0xF1b5c3dE1462eeACfa93D69410C209467DA1c2BF
Vault
0x5De64bDdbbC27322f3Ad7dcBdAf5Ddb19a279F5C
Shares
vUSDG, 6 decimals, minted by the vault
USDG
0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168
Pool
AAPL / USDG, fee 3000, spacing 60, no hook
PoolManager
0x8366a39CC670B4001A1121B8F6A443A643e40951

Checking it yourself

Ask the calendar what time it thinks it is:

cast call 0xF1b5c3dE1462eeACfa93D69410C209467DA1c2BF \
  "stateNow()(uint8)" --rpc-url https://rpc.mainnet.chain.robinhood.com

# 0 closed, 1 unwinding, 2 open

Then watch the vault refuse to open a band while it says open:

cast call 0x5De64bDdbbC27322f3Ad7dcBdAf5Ddb19a279F5C \
  "deploy(int24,int24,uint128,uint256,uint256)" 218640 219300 1000000 0 1000000 \
  --rpc-url https://rpc.mainnet.chain.robinhood.com

# reverts 0x36bd0147, which is MarketIsOpen()

Nothing on this page needs to be taken on trust. Those two calls are free, read only, and answer the only question that matters about the design.

Call reference

CallWhoWhenDoes
deposit(uint256)anyonevault flatpulls USDG, mints vUSDG at price per share
redeem(uint256)anyonevault flatburns vUSDG, returns the USDG behind it
deploy(int24,int24,uint128,uint256,uint256)managercalendar Closedswaps half, mints the band
unwind(uint256)anyonecalendar not Closedburns the band, sells inventory, pays 0.05%
totalAssets()viewanyUSDG held by the vault
bandLiquidity()viewany0 when flat
state(uint256)viewanycalendar: 0 closed, 1 unwind, 2 open
nextChange(uint256)viewanycalendar: the next boundary, as a timestamp

Errors you may see

MarketIsOpen0x36bd0147the session is live, no band may be opened
MarketIsShut0x1fed0c6etoo early to unwind, the night is not over
BandIsOut0x591bcca1deposits and redemptions are closed until the unwind
NoBand0x4a25a7eathere is nothing out to unwind
NotManager0xc0fc8a8aonly the manager opens bands