Composable credit
A research track tokenised HyperCore lending positions as HyperEVM ERC20s, proved a contract can supply on testnet, and found the vault must be a queue, not a wrapper.
A HyperCore lender holds a balance, not an asset. It cannot be transferred, sold or pledged, no HyperEVM protocol can take it as collateral, and the only exit is a withdrawal that needs idle liquidity in the reserve. On 2026-09-20 none of the lending book was tokenised.
The docs say HyperCore lending is not tokenised “but an EVM protocol could do so” with a yield-bearing ERC20 built on CoreWriter and the precompiles. That token would give lenders a secondary market and an exit that does not queue behind utilisation, and give HyperEVM protocols an asset paying the native rate. Split into fixed and floating legs, it gives fixed-rate lending with no governance-set rate.
The track tested whether a contract can supply at all. It can: one block after its action, a testnet contract whose precompile had reverted held 500.00000051 USDC supplied and accruing.
The docs disagree on whether a contract can supply
Section titled “The docs disagree on whether a contract can supply”The CoreWriter action table lists action 15, borrow and lend, with op 0 supply and 1 withdraw; the portfolio margin page says “in a future upgrade, CoreWriter will expose the same supply action for smart contracts”.
On testnet, a contract supplies and withdraws
Section titled “On testnet, a contract supplies and withdraws”A probe contract walked the path, reading 0x811 borrowLendUserState at each step:
| Step | Action | Result |
|---|---|---|
| 0 | Deploy the contract | Not a HyperCore user; 0x811 reverts |
| 1 | Fund it on HyperCore with 500 USDC (CoreWriter action 6 from an EOA) | coreUserExists true |
| 2 | The contract sets its own account mode to 1 (Standard) with action 16 |
userAbstraction changes from default to disabled |
| 3 | The contract supplies 500 USDC with action 15 | One block later 0x811 returns a basis of 500.00000000 and a value of 500.00000051; spot balance 0 |
| 4 | The contract withdraws 100 USDC with action 15 | 400 supplied, 100 in spot |
HyperCore’s action log shows each operation decoded as SystemBoleAction and accepted with no error, and the HTTP read agreed.
On mainnet, the path is wired but a contract supply is unproven
Section titled “On mainnet, the path is wired but a contract supply is unproven”- Wired and rule-enforced. A portfolio-margin account emitted action 15 twice; HyperCore decoded both as
SystemBoleActionwith an integerweiand refused them withManual borrow/lend not allowed with portfolio margin. The EVM transactions succeeded; the one inspected used 47,889 gas. - Provably from CoreWriter. On one testnet account, action 15 lands as
SystemBoleActionwith integerwei, the HTTPborrowLendaction asborrowLendwith a decimal stringamount. The shape discriminates, and the mainnet refusals have the CoreWriter shape. - A success is consistent, not proven. A multi-owner contract wallet holds about 823,079 USDC supplied, reconciling to eight decoded action-15 emissions within about 0.4 basis points. But it also has an API wallet and the HTTP path works on mainnet, so the emissions may have done nothing; the explorer keeps only the last 300 actions per account, so this cannot be settled from outside.
Settling it needs a contract supply on mainnet, which needs mainnet capital. None was moved.
No tokenised wrapper exists
Section titled “No tokenised wrapper exists”A scan of 3,000,001 mainnet blocks (about 35 days, no gaps) found none. The one contract supplying at size is a multi-owner wallet, not an ERC20.
The numbers
Section titled “The numbers”| Quantity | Value | Basis |
|---|---|---|
| Action 15 fields | (uint8 op, uint64 token, uint64 wei); op 0 supply, 1 withdraw; wei = 0 means the full balance |
docs |
| USDC decimals | 8 on HyperCore, 6 on the HyperEVM (evmExtraWeiDecimals = -2); action 15 wei is 1e8 |
spec 02 |
| USDC contracts on the HyperEVM | HyperCore token 0 links 0x6b9e7731...; the docs’ HyperEVM USDC 0xb88339cb... is a different, unlinked ERC20 |
docs; spec 02 |
| Supply rate identity | borrow * utilisation * 0.9; reproduces the API to 9 decimal places |
spec 02 |
| Supply rate, 2026-09-20 | 3.01% at 66.97% utilisation, about 441 million USDC supplied | spec 02 |
| Per-user USDC supply cap | 250 million: the ceiling for one vault account | docs |
| Mainnet scan | 3,000,001 blocks; 13 action-15 emissions, 4 addresses, 2 contracts, 0 wrappers | spec 02 |
| HyperCore to HyperEVM gas | 200k gas, charged from the HyperCore balance; 99 of 100 USDC sent for 0.000588 USDC, measured on testnet | docs; spec 02 |
| Activation fee | 1 USDC on the first send to a new HyperCore account; 0 afterwards | docs; spec 02 |
| Vault guards | a pending deposit cannot be failed before 5 blocks (FAIL_DELAY), because an action can land late; after 1,200 blocks it can only be failed, never settled (SETTLE_WINDOW); deposits under 0.1 USDC refused |
digest 04; contract source |
| Tests | 44 passing, including three invariants over 3,072 calls | spec 02 |
An adversarial pass found four exploits
Section titled “An adversarial pass found four exploits”The first vault ran on testnet from a UI and was written up as working. Each exploit is now a passing test:
| Attack | Needs a HyperCore failure? | Effect | Defence in the second version |
|---|---|---|---|
| Two deposits recorded in the same block share one snapshot | yes | Shares minted for money that never arrived | A cumulative accountedAssets check, one deposit in flight |
| Two redemptions price against the same assets | no | Claims exceed what the vault holds | reservedAssets; everything priced off net assets |
| A failed deposit leaves the depositor’s USDC on HyperCore | yes | Funds stranded with no path out | A permissionless refundDeposit |
| A payout drawn from spot without checking the position fell | yes | A depositor’s money pays a redeemer | Payout only after the supplied position is proven to have fallen |
The second matters most. Two redeemers, one pot. No HyperCore failure, no adversary, no dropped action. Redeeming burned shares and fixed a claim but left the asset figure untouched: Alice redeems 50 of 100 shares against 100 of assets and is owed 50, then Bob redeems the other 50 and is owed 100. Two people redeeming is the ordinary case.
The first is the same-block double mint. The brief’s rule, record the intent and verify from 0x811 next block, was implemented literally and still failed: two deposits in one block both verified against a HyperCore state neither had touched, so both settled when only one was funded. Verification must be cumulative, against a figure every earlier settlement has raised, with one deposit in flight.
Why a queue, never a wrapper
Section titled “Why a queue, never a wrapper”The vault cannot mint at deposit time, because the HyperEVM is never told: every refusal returns success, gas is spent, a log is emitted and the money stays put. So the vault records the intent, mints nothing, and later mints only what HyperCore credited.
Seven corrections to the brief
Section titled “Seven corrections to the brief”Each would have lost money silently:
| Correction | Evidence | Consequence |
|---|---|---|
| USDC is 8 decimals on HyperCore, not 6 | Action 15 wei is 1e8-scaled; the HyperEVM side is 1e6 |
The brief taken literally is a 100x error |
| Non-round withdrawals are rejected, not burned | With evmExtraWeiDecimals of -2, a HyperCore to HyperEVM amount that is not a multiple of 100 wei fails with Invalid number of decimals (5 of 5) |
Interest accrues at 8 decimals, so a full-balance withdrawal almost never passes: floor before bridging |
| The whole balance cannot be bridged out | The 200k gas for that leg is charged from the HyperCore balance; sending all 100 USDC was refused, 99 succeeded | Keep a gas reserve on HyperCore |
0x811 reverts for an account with no lending record |
It does not return zeros, and a precompile revert consumes the call frame’s gas | An unguarded totalAssets() bricks the vault when its first depositor arrives |
balance is not totalSupplied - totalBorrowed |
The gap was about 46.57 USDC and grew with every read, consistent with the protocol’s retained 10% of interest | Pricing shares off balance credits suppliers with money that is not theirs; the vault prices off its own supply.value |
| Portfolio margin is disqualified | It refuses manual borrow and lend, and supplies idle borrowable balances automatically, fighting the vault’s accounting | The vault sets Standard mode on itself before holding anything; all 123 accounts seen setting a mode through CoreWriter targeted themselves, and all 30 sampled contracts took effect |
| There is no rate history | Precompiles answer only at the latest block | Comparison data can only be logged forward; the logger started before the router |
The fixed and floating split was walked to a short maturity on testnet: 1,000 wrapped USDC split, settlement refused before maturity, then 99,999,997,062 shares to the fixed leg and 2,938 to the floating, exactly the 100,000,000,000 that went in. The fixed leg is only as fixed as the exit: it redeems into the vault’s own queue.
Deposit custody comes first
Section titled “Deposit custody comes first”The testnet linked USDC ERC20 reverts on every standard call, so deposits arrived as HyperCore spot sends, which carry no sender the HyperEVM can see, and the operator names the receiver. It cannot mint unbacked shares, since credit is verified, but can misdirect one; a depositor attestation or per-depositor HyperCore sub-accounts must come before the split legs and any mainnet capital.
| Also open | Detail |
|---|---|
| A successful mainnet supply by a contract | Wired and rule-enforced is proven; success is not |
| The mainnet ERC20 deposit leg | HyperCore USDC links to 0x6b9e773128f453f5c2c60935ee2de2cbc5390a24, a proxy carrying the system transfers (133 to its system address per 2,000 blocks when measured) whose ERC20 view functions reverted on two RPCs. Provenance unestablished; the deposit leg has not run through it; the testnet link is unusable |
| The basis is not risk-adjusted | HyperEVM lending markets use the docs’ HyperEVM USDC, 0xb88339cb7199b77e23db6e890353e22632ba630f, not linked to HyperCore token 0, so a USDC basis trade is a swap, not a transfer. USDT0 (token 268) links the same contract the lending markets use, so that basis is directly executable. Even then, a rate gap between a protocol primitive and a curated lending market is not an arbitrage |
| The floating leg is fungible | A late splitter dilutes earlier holders, bounded by the subscription window and reported live; fixing it needs per-holder yield indexing |
| Borrow and repay through CoreWriter | Only supply and withdraw were measured; one tool routes action 15 ops 2 and 3, and whether they exist is unresolved |
For the failure model the vault is built around, see What one HyperEVM transaction can and cannot do. For system addresses, decimals and the bridge fee, see Moving assets between HyperCore and the HyperEVM.