Lock a token,
hold the note.
The app at /app is a thin client over the vault: one form to wrap, one field to claim, and a live preview of the note you are about to mint. No accounts, no backend — every action is a wallet transaction.
Requirements
#- A browser wallet that injects
window.ethereum: MetaMask, Rabby or Coinbase Wallet are what the app names in its error copy; any EIP-1193 provider works. - Native gas on the target network (ETH on Robinhood Chain).
- An ERC-20 balance to wrap, and a deployed vault address configured for the site (see vault address resolution). Without a CA the app is preview-only.
Connect a wallet
#Press Connect wallet in the header. The app calls eth_requestAccounts, stores the first account, and shows it shortened (0x1234...abcd) with a green dot. Clicking the connected pill disconnects locally (it does not revoke the site in your wallet).
The app listens to accountsChanged and chainChanged, so switching accounts or networks in the wallet updates the header without a reload. You do not need to be on the right chain to connect; the app switches (or adds) the network when you send the first transaction.
Wrap a position
#Choose the token
Paste an ERC-20 contract address, or click a preset pill. Pasting and leaving the field reads the token's name, symbol and decimals from the chain and updates the preview. On Robinhood Chain every pill carries a real address; on other networks the showcase pills ($CASHCAT, $PONS, $IF) preview only.
Enter the amount
Human units (e.g. 250000). The app converts with the token's decimals. Must be greater than zero.
Pick a term
INSTANT (0), 30D, 90D, 180D, 1Y, or CUSTOM with 1–3650 whole days. The label above the pills reminds you: claim active immediately regardless of term.
Approve and wrap
The button reads Connect to wrap, Vault required or Approve and wrap depending on state. On press the app: ensures the network, checks your allowance, sends approve only if needed, reads nextTokenId, then sends wrap.
Confirm
A View transaction link to the explorer appears at the bottom while each transaction is pending. After the wrap receipt, the app switches to the Notes tab with your new note id pre-filled.
If the vault's allowance for your token is already ≥ amount, the approve step is skipped and you sign only the wrap. The allowance the app requests is exactly the amount, not unlimited.
Reading the preview card
#The card on the right is a render of the note you are composing. It updates as you type. Fields:
| Field | Source | Onchain? |
|---|---|---|
| Symbol / name | Token metadata (preset or read from chain) | Indirect — the vault stores the token address only |
| Balance | Amount field | Yes — positions(id).amount |
| Term | Term selector | Yes — as maturity = wrap time + term |
| Claim: ACTIVE | Constant | Yes — isClaimable(id) is true for every live note |
| Entry mark | Live USD price from DexScreener for the token address on the default network, refreshed every 30 s (pulsing dot = live). Falls back to $— when no market is found. | No — the vault stores no price; this is the market mark at the moment you compose the note |
| 000421, TRANSFERABLE | Static card copy | No |
Nothing on the card is signed or stored; it is a preview. The authoritative note is what positions(tokenId) returns after the wrap.
Claim a note
#Open the Notes tab, enter a note id and press Claim note. The app ensures the network and sends claim(tokenId) from the connected account. The transaction succeeds only if that account is the note's current owner; otherwise the wallet shows Vellum: holder only.
The full underlying balance arrives in the same transaction. The note id is then burned and cannot be reused.
There is no indexer behind the UI. To find ids you hold, use the explorer's NFT view for the vault contract, or the Transfer / NoteWrapped events for your address. The app remembers the id of the note you just wrapped only for the current page session.
Transfer a note
#The app has no transfer screen. Because the note is a standard ERC-721 on the vault contract, transfer it with any NFT-capable wallet or marketplace: pick the Vellum Note (VNOTE) collection, the token id, and send. Before accepting a note from someone else, read positions(id) on the explorer and check the token, amount and claimed == false.
Errors you may see
#| Message | Cause | Fix |
|---|---|---|
| Install MetaMask, Rabby, or Coinbase Wallet | No injected provider | Install a wallet extension or open in a wallet browser |
| Enter a valid ERC-20 contract address | Address field is not a 0x address | Paste the full contract address |
| Couldn't read this token: … | name/symbol/decimals call failed | Wrong network for that token, or not an ERC-20 |
| Deploy the Vellum test vault first | No vault address resolved | Configure the CA (env var or admin panel) |
| Choose Instant, a preset, or enter 1–3650 custom days | Custom term invalid | Whole days in range |
| Amount must be greater than zero | Amount parsed to 0 | Enter a positive amount |
| Enter a deployed vault and note ID | Claim with empty id or no CA | Fill both |
| Vellum: … | Contract revert | See revert reasons |
Admin panel (CA)
#/admin is a password-protected page for setting the vault address without redeploying the site. It is intended for the team, not end users.
- Password is
VELLUM_ADMIN_PASSWORDon the server. If unset, login always fails. - A successful login sets an HMAC-derived,
httpOnly,sameSite=strictcookie scoped to/adminfor 12 hours. - Saving a CA writes it to
localStorage["vellum-vault-address"]in that browser only and broadcasts avellum:vault-address-changeevent so an open app tab updates immediately. It does not change the deployment's environment variables or other visitors' experience. - Clear empties the override; the app falls back to environment variables.
To publish a CA to all visitors, set NEXT_PUBLIC_VELLUM_ROBINHOOD_VAULT_ADDRESS in the hosting environment and redeploy. The admin override is a local testing convenience.