Integrate Hull in Your Frontend
This page has two halves with different levels of certainty.
The first half describes what a frontend will read from Vessel at Gate-0: series terms, NAV, maturity, and remaining issuance capacity under the subordination floor. As of 2026-08-29 the public repository (github.com/Lemma-Development-Labs/vessel) contains only a README and a LICENSE. No contracts, ABIs, or deployed addresses are published. Every function name, return shape, and address in that half is therefore a design-stage placeholder, marked as such. Do not build against it until the contracts are published and the markers are removed.
The second half is guidance that applies now to any frontend on Monad, Vessel or otherwise. It is drawn from the Monad developer documentation and holds regardless of what Vessel ships.
Vessel is experimental software in testnet and unaudited. Nothing on this page is a stable interface. The Vessel-specific commands are templates with placeholders, not something to paste into a build.
What a frontend reads at Gate-0
The litepaper fixes what an integrator needs to display for a Hull series. The values are defined; the calls that return them are not yet public.
| Value | Defined by | Read via |
|---|---|---|
Series rate r_H | Contract parameter: r_H = clamp(EWMA_30d(net funding APR) × (1 − h), 0, r_cap), h = 40%, r_cap = 15% APR | view call, name pending UNVERIFIED — PENDING GATE-0 |
| Maturity | Fixed-maturity series, 4-week at launch | view call, name pending UNVERIFIED — PENDING GATE-0 |
| Hull NAV | Continuous NAV; daily accrual A_H = r_H × H × Δt | view call, name pending UNVERIFIED — PENDING GATE-0 |
| Remaining Hull capacity | Subordination floor B / (H + B) ≥ 20%, enforced at all times | view call, name pending UNVERIFIED — PENDING GATE-0 |
The rate is a contract parameter, not a yield forecast. A frontend must label it as the series' fixed rate, set at issuance, and must not present it as expected or historical performance.
Series terms
Template. Replace every bracketed token when the ABI is published.
# PENDING: contract address and function name are not published as of 2026-08-29
cast call <HULL_SERIES_ADDRESS> "<seriesTerms()(...)>" \
--rpc-url https://testnet-rpc.monad.xyz
What the response has to carry, per the litepaper: the series rate r_H, the maturity timestamp, and the issuance date. The exact return tuple is unpublished UNVERIFIED — PENDING GATE-0.
NAV
# PENDING: function name unpublished
cast call <HULL_SERIES_ADDRESS> "<nav()(uint256)>" \
--rpc-url https://testnet-rpc.monad.xyz
Hull NAV accrues at the fixed series rate. Display it as principal plus accrued fixed yield to date. Under the shortfall ordering, Ballast NAV absorbs losses first, then the Reserve, and only then is Hull principal impaired; a frontend showing Hull NAV below principal is showing a credit event, and should say so plainly.
Maturity
# PENDING: function name unpublished
cast call <HULL_SERIES_ADDRESS> "<maturity()(uint256)>" \
--rpc-url https://testnet-rpc.monad.xyz
Hull redeems principal plus fixed yield at maturity. Early exit is by secondary sale only. A frontend should not offer a redeem action before maturity, because the contract does not have one.
Remaining capacity under the floor
New Hull issuance is constrained by the subordination floor. Given Hull notional H and Ballast NAV B, the floor B / (H + B) ≥ 20% bounds how much additional Hull can be issued. Whether the contract exposes a single capacity view or the frontend derives it from H and B is undecided UNVERIFIED — PENDING GATE-0.
# PENDING: either a direct capacity view, or read H and B and derive
cast call <ENGINE_ADDRESS> "<hullCapacity()(uint256)>" \
--rpc-url https://testnet-rpc.monad.xyz
If deriving, the arithmetic follows from the floor alone: the maximum Hull notional for a given B is H_max = B × (1 − θ_min) / θ_min with θ_min = 20%, so H_max = 4 × B, and remaining capacity is max(H_max − H, 0). This is a consequence of the published invariant, not a published function.
Addresses
| Contract (testnet) | Address | Actions |
|---|---|---|
| Engine | UNVERIFIED — PENDING GATE-0 | |
| Hull series (current) | UNVERIFIED — PENDING GATE-0 | |
| Ballast | UNVERIFIED — PENDING GATE-0 | |
| Reserve | UNVERIFIED — PENDING GATE-0 |
Once addresses are published, confirm code is present before wiring anything:
cast code <ADDRESS> --rpc-url https://testnet-rpc.monad.xyz
Testnet chain ID is 10143. The primary testnet RPC is https://testnet-rpc.monad.xyz, rate-limited to 50 requests per second, with 25 per second for eth_call and eth_estimateGas. A frontend that polls NAV on every block will hit the eth_call limit; batch through Multicall3 or poll on a timer.
Monad rules that apply now
Everything below is independent of Vessel. It is how a Monad frontend has to handle gas, balances, and confirmation, and getting it wrong costs users money.
Gas is charged on the limit
On Monad, gas_paid = gas_limit × price_per_gas. The user pays for the limit set on the transaction, not the gas the execution used. This follows from asynchronous execution: leaders build blocks before executing them, so consumption is not known at inclusion time. See the network page for the full parameter set.
Consequences for a frontend:
- Set explicit gas limits on every transaction. Do not leave the limit to a wallet default.
- Keep the estimation buffer at or under about 10 percent. A 50 percent safety margin on Ethereum is free; on Monad it is paid in full.
- Never display a cost derived from
gasUsedon the receipt. The number the user paid isgasLimit × effectiveGasPrice. ShowinggasUsed × priceunderstates the real cost. - Hardcode 21,000 for native MON transfers. That is always the exact cost; there is nothing to estimate.
- Guard the revert path. If
eth_estimateGasreverts, some wallets fall back to a very large limit, and on Monad the user pays that entire limit. Surface the revert to the user rather than letting the transaction proceed with a fallback limit.
eth_call and eth_estimateGas simulate against speculative state and return accurate results, so estimates themselves are reliable. The hazard is what happens to the number after estimation.
The reserve balance and new accounts
Two Monad behaviours shape onboarding UX.
10 MON reserve floor. Each EOA has a 10 MON reserve balance floor. Accounts at or below it are limited to roughly one transaction per 1.2 seconds. A frontend that funds a fresh wallet and then fires a batch of transactions will see them throttled. Check the balance before sequencing multiple sends, and tell the user when the account is below the floor.
Newly funded accounts. Consensus validates transactions against a state view delayed by three blocks (D = 3). A freshly funded account cannot send until its funding is three blocks old, about 1.2 seconds at 300 ms blocks. Onboarding flows that fund a wallet and immediately submit a transaction will fail on the first attempt. Wait for the funding transaction to be three blocks deep, or simply wait 1.2 seconds, before enabling the next action.
Block tags and UI transitions
Monad block states map to standard tags: latest is speculative (proposed), safe is validator-backed (voted), finalized is irreversible. Speculative finality is 300 ms; full finality is 600 ms.
- Use
finalizedfor any transition the UI cannot walk back: marking a deposit as complete, updating a displayed balance the user will act on, showing a Hull position as held. - Use
latestfor optimistic feedback: a pending indicator, a provisional NAV refresh, a toast.
The gap between the two is 300 ms. There is no UX reason to accept reversibility risk to save it.
Same-call receipts
eth_sendRawTransactionSync returns the receipt in the send call itself. For a frontend this removes the send-then-poll loop: submit, receive the receipt, render. Pair it with the block-tag rule above; a receipt from the sync call tells you the transaction was included, and the finalized tag tells you it will stay included.
Cold access costs
Cold account access costs 10,100 gas (Ethereum: 2,600) and cold storage access 8,100 (Ethereum: 2,100); warm access is 100, unchanged. This matters for a frontend only in that gas estimates for first-touch operations run higher than Ethereum intuition suggests. Do not trim a Monad estimate toward an Ethereum number.
What this page cannot yet tell you
- Contract names, function signatures, return types, and ABIs. None are published.
- Deployed testnet addresses for the Engine, Hull series, Ballast, or Reserve.
- Whether remaining Hull capacity is a direct view or derived client-side.
- Event signatures for indexing deposits, issuance, and accrual. The indexing pipeline (see docs.envio.dev/docs/HyperIndex/envio-cloud-cli) requires a deployed and explorer-verified contract before an ABI can be imported, so indexing guidance waits on the same publication.
- Any frontend SDK or package. None exists.
When the contracts are published, this page will replace each placeholder with the verified call and drop the markers. Until then, treat the second half as binding and the first half as a preview of shape.