What the contract will take, and what happens when it does.
The live mint module will accept 9,999,970 USDC more than it currently holds. Minting is enabled, the module is not paused, USDC is a supported stable, and kUSD accepts this module as a minter while refusing both retired modules and the collateral vault. A deposit of one million dollars is mechanically receivable today, with no onboarding, no signature from us, and no permission.
Read the second thing before the first stops sounding impressive. Ten million dollars of capacity against thirty dollars of exposure is not a selling point. It is an accurate description of a protocol that has not been chosen yet. Capacity is what would have to be true for a first large deposit to be possible; it is not evidence that one is coming, and nothing on this page should be read as traction. Anyone can compute that ratio from two public calls, so we would rather be the ones who write it down.
Every figure on this page was read on Base at block 49,930,000 (2026-08-13 19:29:07 UTC), and the fork test linked below asserts against that same block, so the page and the proof cannot drift apart. The live view is app.kerne.fi/api/psm-status and /api/stats.
1. The number, and the subtraction that is not the obvious one
The mint path enforces a per-stable concentration cap. The part worth stating plainly is that the cap does not bind on the exposure counter alone. It binds on the greater of the tracked counter and the module's actual balance:
headroom = stableCaps(USDC) - max(currentExposure(USDC), USDC.balanceOf(module))That is a deliberate fix from June 7, 2026, and the reason for it matters to anyone sizing a deposit. The counter is a net figure that saturates at zero, so a redemption whose payout exceeds it can floor it to zero while the module still holds the stable. A gate reading the counter alone would then re-open the entire cap on top of reserves that never left. Deriving published headroom from the counter alone would over-state it in exactly that case, which is the expensive direction to be wrong in, so both the endpoint and the test below mirror the contract rather than the intuition.
| Read | Call | Raw | Meaning |
|---|---|---|---|
| Concentration cap for USDC | stableCaps(USDC) | 10000000000000 | 10,000,000 USDC |
| Tracked exposure counter | currentExposure(USDC) | 30000000 | 30 USDC |
| USDC the module actually holds | USDC.balanceOf(module) | 30000000 | 30 USDC |
| Headroom, derived | cap - max(exposure, balance) | 9999970000000 | 9,999,970 USDC |
USDC carries 6 decimals, so 10000000000000 is ten million dollars and not ten trillion. The same cap, 10,000,000 USDC, is configured on all three modules.
2. Reproduce the inputs in four calls
No key, no account, no permission. A public Base endpoint is enough.
PSM=0xaBDE1138aa1Ce88d1dF06422C0c3b05D70569803
USDC=0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
RPC=https://mainnet.base.org
cast call $PSM "stableCaps(address)(uint256)" $USDC --rpc-url $RPC
cast call $PSM "currentExposure(address)(uint256)" $USDC --rpc-url $RPC
cast call $USDC "balanceOf(address)(uint256)" $PSM --rpc-url $RPC
cast call $PSM "mintingEnabled()(bool)" --rpc-url $RPCExpect 10000000000000, 30000000, 30000000 and true. Pin to the snapshot with --block 49930000 to get exactly the figures on this page; without it you get the current state, which is the one that matters if you are actually sizing a deposit.
One note on the getter, because it has cost time before. The function is stableCaps and it takes the stable's address. stableCap, cap, mintCap, maxMint and supplyCap all revert on this contract. An internal review probed those five, got five reverts, and recorded that the cap could not be read at all. It can. The full verification walkthrough is in HOW_TO_VERIFY_KERNE.md.
3. The proof that it is a bound and not a brochure
Four reads tell you what the contract says. They do not tell you what it does. So the claim is executed: test/fork/PsmCapacityIsReal.t.sol forks Base at block 49,930,000, deals one million USDC to an address that has never touched Kerne, approves the module, mints through the deployed bytecode, and asserts what comes back.
It then walks the number to its edge, which is the part that makes it a bound. A mint of exactly 9,999,970 USDC succeeds. One USDC more reverts StableCapExceeded() (0x40e97e29). Without that pair, the published figure could be any value at or below the true cap and every other number we publish would still reconcile.
git clone --recurse-submodules https://github.com/kerne-protocol/contracts-public
cd contracts-public
BASE_RPC_URL=https://mainnet.base.org forge test --match-path 'test/fork/PsmCapacityIsReal.t.sol' -vvNine tests. Stated precisely so nobody is misled about what our CI does: the hermetic suite runs on every push, and this file is opt-in, so without BASE_RPC_URL it prints SKIPPED and passes. CI proves it never breaks a clean clone; it does not run the mint. You run the mint. That is the point of publishing it rather than screenshotting it.
4. What one million dollars does the moment it lands
Measured on the fork, not modelled. At one million the tiered fee is 5 bps, so 1,000,000 USDC in returns 999,500 kUSD and 500 USDC is retained as protocol fee. The exposure counter rises by the gross deposit, fee included, so headroom falls from 9,999,970 to 8,999,970. Read the fee for your own size with getFee(USDC, amount) rather than assuming a flat rate: the ladder steps down at 50,000, 250,000 and 1,000,000.
And the part that is not a feature. USDC parked in the module earns nothing, and there is no function on that contract that puts it in a yield strategy. That is a property of the deployed code rather than a temporary state. A mint is an acquisition of kUSD; staking is the thing that earns. The full instrument, including what the exit costs and what can stop it, is at /dossier/anchor-terms, and it should be read before this page is acted on rather than after.
Where the reserve sat at block 49,930,000
| Module | USDC | What it is |
|---|---|---|
Live mint module 0xaBDE1138aa1Ce88d1dF06422C0c3b05D70569803 | 30.000000 | Holds the kUSD minting role. This is the only module a new mint can enter, and the only one the capacity figure describes. |
Retired mint module 0x07eBb486e11BD217e6085eb5ab663e4517595993 | 995.003000 | Superseded July 10, 2026. Its minting role is revoked on the token, so it cannot create kUSD. It still redeems from its own reserve, which is why it still holds most of the backing. |
Redeem reserve 0xFf3025ec18e301855aB0f36Ec6ECa115a29A5Fbc | 85.885006 | Earlier module, redeem only, backing residual kUSD. |
1,110.888006 USDC across the three, against 1,144.707154 kUSD in existence. Re-read any row with cast call $USDC "balanceOf(address)(uint256)" $MODULE, or take the live sum from /api/por. What that reserve is as a multiple of a first large deposit, which parameters were chosen against a book this size, and why all three modules report minting enabled while one can mint, are on /first-money, which derives every figure live rather than pinning it the way this page does.
5. Three things you will find, and where we already published them
Anyone doing real diligence on this contract will surface the following within an hour. None of them is new, and none is being disclosed here for the first time. They are collected on this page because a capacity memo that omitted them would be selling a number without its context, and because the dates are checkable.
A solvency gate that is configured and switched off
solvencyCheckDisabled() returns true on the live module while minSolvencyThreshold() reads 10100, a 101 percent threshold sitting behind a bypassed gate. It was set deliberately, as transaction 7 of the 13-step July 10 deploy ceremony. The honest complication, which is why "just switch it back on" is not the fix: cleared today it would measure nothing, because it reads the vault's solvency ratio and that vault has zero share supply, so the check would pass on a sentinel constant.
Published /risk and /api/risk-status, July 24, 2026.
Most of the backing sits in a module labelled retired
At the snapshot block, 995.003 of 1,110.888 USDC sat in the superseded module, and that module reads paused() == false and mintingEnabled() == true. Both of those are module-local flags and neither is the authority. The authority is on the token, and kUSD does not grant it MINTER_ROLE, so a mint attempted there reverts. It is retained as a redeem reserve while the reserve migrates, which is also why it stays in the backing sum. The fork test asserts both halves, so this cannot quietly stop being true.
Published in the reserve table at /dossier/anchor-terms, August 1, 2026.
Every module lends its whole balance, atomically, at no fee
All three are ERC-3156 flash lenders with flashFeeBps() == 0 and maxFlashLoan(USDC) equal to the full balance. The reserve can therefore leave and return inside a single transaction, and the loan is repaid in that same transaction or the whole thing reverts, so it can never be missing at the end of a block. We state it because a reader will find maxFlashLoan themselves, and because a previously-published sentence about how USDC can leave a module omitted this path and therefore read as a stronger guarantee than the code gives.
Corrected and published at /api/por, August 1, 2026.
One further thing, which is the largest and is not on this list because it is not specific to capacity: administrative control of kUSD and all three modules moved to a timelock with a 48 hour delay on August 6, 2026, and the 2-of-3 Safe still holds proposer, executor and canceller on it. The delay governs when, not who. What that means for a large deposit is set out in /dossier/anchor-terms.
6. What this corrects in our own record
An internal review dated August 12, 2026 concluded that this contract had no readable cap, having probed five plausible getter names and received five reverts. That conclusion was wrong, and the method is what made it wrong: five guesses at an argument-less name, against a getter that takes an argument. The capacity had been published at app.kerne.fi/api/psm-status since August 1 and rendered on the mint page the whole time.
It is written down here for the same reason the rest of this page exists. A wrong belief that lives only in a private record gets rediscovered; a test that runs against the chain does not. That is now nine assertions in a public repository, and the getter name is in the verification document beside the command that calls it.