Protocol documentation

How Vestora works

Vestora turns a vesting schedule into collateral. This page describes every contract call, every parameter, and every way the system can lose you money.

Chain · Robinhood 4663Unit · USDGMax LTV · 35%Admin · none

Overview

An equity grant is a promise with a calendar attached. Until the calendar runs out the shares exist, have a price, and cannot be spent. The usual escape is a secondary desk that buys the promise at a thirty to fifty percent discount and keeps everything above it.

Vestora replaces the sale with a loan. A tokenised award is deposited into a vesting position; the protocol values the remaining schedule, applies a haircut, and lends USDG against it. As tranches unlock they either repay the loan or flow to the wallet. When the debt is clear the position burns and the shares leave untouched.

Three properties define the system: the schedule is immutable once written, the protocol has no owner or pause switch, and the only party that can move a position is its beneficiary — or a liquidator, once the position is demonstrably underwater.

Vision and mission

Employee equity is the largest illiquid asset most technical workers will ever hold, and the market that serves it is opaque, relationship-gated, and priced against the seller. A grant worth two hundred thousand dollars routinely trades for a hundred and twenty because the holder needed a deposit on an apartment in the wrong quarter.

The mission is narrow: make the schedule itself bankable. Not a new asset class, not a synthetic derivative — a credit line whose collateral is a published, verifiable unlock curve. The price of liquidity should be an interest rate, not the upside.

Architecture

Two contracts, no shared vault, no router between them, no proxy. Each one can be read and used on its own.

VestingCredit.sol
  positions        ERC-721, one per grant
  lender reserve   USDG supplied by funds
  debt index       per-second accrual at RATE_PER_SEC
  pricing          Uniswap v3 spot, USDG pair per asset

UnlockMarket.sol
  tranche listings sale of future unlock slices
  settlement       USDG in, claim rights out
  fee              protocol fee, discounted for $VSTR holders

Value flows one way through a position: shares in, credit out, unlocks back against the debt. There is no path by which the protocol can move a beneficiary’s shares while the position is healthy.

behind cliffvestingclaimable

Vesting positions

open(address asset, uint256 amount, uint64 cliff, uint64 duration, address beneficiary) returns (uint256 id)
claim(uint256 id)
close(uint256 id)

open pulls the tokenised award into the contract and mints an ERC-721 to the beneficiary. Cliff and duration are written at mint and are immutable; there is no function that edits them. Duration is capped at 730 days.

Vested fraction is linear after the cliff: vested = amount × min(now − start, duration) ÷ duration, and zero while now < start + cliff. claim transfers vested − claimed, minus any auto-repay share.

close reverts while debt is outstanding. With zero debt it sends the unclaimed remainder to the beneficiary and burns the token.

Borrowing

supply(uint256 usdg)            // lender in
redeem(uint256 shares)          // lender out
borrow(uint256 id, uint256 usdg)
repay(uint256 id, uint256 usdg)

Collateral value is the present value of what has not yet been claimed, discounted by the asset haircut:

spot      = unclaimedShares × price(asset)   // Uniswap v3 sqrtPriceX96
pv        = spot × (10000 − HAIRCUT_BPS) / 10000
maxDebt   = pv × MAX_LTV_BPS / 10000

With a 25% haircut and a 35% cap, a grant worth $100,000 at spot supports at most $26250 of debt. The haircut is deliberately heavy: unlike a liquid stock position, the collateral here cannot be seized and sold in full on the day it goes bad.

Interest accrues per second on a global index at RATE_PER_SEC = 2535100000 (~8% APR). All of it goes to the lender reserve; there is no treasury cut and no spread.

Unlock stream

setAutoRepay(uint256 id, bool on)
stream(uint256 id)   // permissionless once a tranche has vested

With auto-repay on, stream sells nothing — it routes the newly vested tranche’s value against debt first and forwards any excess to the beneficiary. With it off, the whole tranche goes to the wallet and the debt keeps accruing. The call is permissionless so a keeper can advance it, but it can only ever move value in the beneficiary’s favour or against their own debt.

Missed periods queue. One call settles one tranche; nothing is skipped or forfeited.

Early unlock market

list(uint256 id, uint64 fromTs, uint64 toTs, uint256 askUsdg)
fill(uint256 listingId)
delist(uint256 listingId)

A beneficiary may sell a future slice of their own schedule outright rather than borrow against it. The listing names a time window; the buyer receives the claim rights to tranches vesting inside that window, and the seller receives USDG now, minus the protocol fee. Positions with outstanding debt must clear the debt attached to the listed window first.

This is a sale, not credit. It is the right tool when the holder wants certainty and is willing to pay a discount for it; the loan is the right tool when they want to keep the upside.

Liquidation

Three bands, all measured against the haircut present value:

LTVStateWhat you can do
0 – 35%HealthyBorrow more, claim, close
3550%BufferNo new borrow; repay or wait for the next unlock
> 50%LiquidatableAnyone may repay up to half the debt
seized = repayAmount × (1 + LIQ_BONUS_BPS/10000) / price(asset)

A liquidator repays at most 50% of the debt and seizes vested-but-unclaimed shares at a 8% discount. Shares still behind the cliff cannot be seized — which is exactly why the haircut is set where it is. A position opened at the 35% cap needs roughly a 30% drop in the underlying before it becomes liquidatable.

Custody model

Your keyAnyoneProtocol
open, claim, closestream a vested tranchenothing
borrow, repay, set auto-repayliquidate above 50%no pause, no fee switch, no upgrade
list, delist on the marketread all stateno freeze, no seize

There is no owner address, no guardian, no proxy admin, and no migration hatch. The deployed bytecode is the final version.

Cryptography and safety

Authorisation is plain ECDSA over EVM transactions; ownership of the position NFT is the only credential that matters. Every state-changing external is nonReentrant, and all token movement goes through SafeERC20.

Price comes from sqrtPriceX96, a Q64.96 value squared with a full-width 512-bit mulDiv and rescaled between USDG’s six decimals and the asset’s eighteen. The classic bug in this codebase shape is a 1e12 error in that rescale, so the test suite pins the conversion in both directions.

Risks and limits

  1. Legal restrictions on your grant. Most employer equity plans prohibit pledging, transferring, or creating a security interest in unvested awards, and doing so can forfeit the grant outright. Tax treatment of borrowing against an award differs by jurisdiction. Read your plan documents; the contract cannot and does not check them.
  2. Spot pricing. Collateral is valued at Uniswap v3 spot, not a TWAP. A thin pool can be pushed within a block. Caps limit the damage; manipulation remains possible.
  3. Illiquid collateral. Only vested-but-unclaimed shares can be seized. If the underlying gaps down hard before the next tranche vests, the reserve can end up short even after full liquidation. First-loss $VSTR staking absorbs that gap before lenders do — up to its size, and no further.
  4. Wrapper and custody risk. A tokenised equity is an issuer’s claim wrapper. If the wrapper depegs or the issuer fails, the collateral fails with it.
  5. Immutability. No pause, no upgrade. A bug discovered after deployment stays deployed. Nothing here is insured, regulated, or recoverable through a counterparty.

Vesting credit is the highest-risk module in this design. Size positions on the assumption that the loan will not be rescued by anyone.

Reference

NameRoleAddress
VestingCreditPositions, reserve, borrow0x…0x
UnlockMarketTranche sales0x…0x
USDGQuote, 6 dp0x5fc5…d168
Uniswap v3 factoryPool lookup0x1f7d…2EfA
$VSTRProduct token — live$VSTR
ConstantValueMeaning
MAX_LTV_BPS3500Borrow cap against present value
HAIRCUT_BPS2500Discount applied to spot
LIQ_THRESHOLD_BPS5000Liquidatable from here
LIQ_BONUS_BPS800Liquidator discount
CLOSE_FACTOR_BPS5000Max debt repaid per call
RATE_PER_SEC2535100000~8% APR, 1e18 index
MAX_DURATION730 daysLongest vesting schedule

Explorer: robinhoodchain.blockscout.com. Ready to try it on testnet funds? Open the app.