This document is unsolicited and uncommissioned. ENS DAO is not a client of Kerne, has not been contacted about this document, has not reviewed it, and has not endorsed it. There is no engagement, no mandate and no relationship of any kind. It was built entirely from public Ethereum state that anyone can read without permission, it names no private information, and it is published as a worked example of a deliverable, not as advice to anyone.
A treasury health check, in full, on a $116M public treasury.
This is the whole of what the $5,000 fixed-scope health check produces, written against a treasury nobody had to consent to, because all of its data is public. Address map, holdings, concentration, counterparty and venue exposure, the full control surface, a liquidity ladder, an idle-cash line and a dated allocation memo. Every figure carries the call that reproduces it, and every figure is pinned to one block so it stays reproducible after this page stops being new.
How to check this document
Nothing here asks to be believed. Every number is a return value from a public Ethereum node at one specific block, and the command that produces it sits next to it. If a figure below is wrong, the command beside it is how you find that out in under a minute.
The block, and why it is pinned
Every read is at block 25,721,000, 2026-08-10 00:26:59 UTC, hash 0x14a7c7350efb160dae7f80015dfc66c0f1f664c3319893579af5f73bc9f92e65. An unpinned treasury figure is wrong within a minute of publication. A pinned one stays checkable for as long as an archive node exists, which is why every command carries --block 25721000.
The endpoint, and why it needs no key
Commands use https://eth.merkle.io, a keyless archive endpoint. Five others served the same values: Tenderly's public gateway, MEV Blocker, 1RPC, Nodies and OnFinality. Any archive node answers identically, because these are reads of consensus state, not of anybody's database.
If a command comes back HTTP 429, the endpoint is rate limiting you rather than refusing the query. Swap the URL for https://gateway.tenderly.co/public/mainnet and the answer is byte for byte identical. That happened often enough while this document was being produced to be worth writing down.
Two passes, then a third
The whole read set was collected twice over different RPC operators and diffed key by key: 153 shared reads, zero disagreements. The headline balances were then re-read a third time through a different tool entirely, on a fourth endpoint. A figure that appeared in only one pass is not published.
Nothing derived from a label
No address here came from a block-explorer label or from memory. Each was resolved from an ENS name the DAO controls, or derived from a contract that points at it, and where both paths existed they were run and required to agree.
One step here is not a chain read, and it is the completeness step
Finding out which tokens an address holds is not something a node will answer: there is no call for it, because ERC-20 balances live in each token's own storage. The candidate list here came from a public indexer, and then every balance that reaches a total on this page was re-read from the chain with balanceOf at the pinned block. So the values are chain-verified and the completeness of the list is not: a holding the indexer missed would be missing here too. On a paid engagement the same list is cross-checked against the address's own transfer history, which the client's answer to "what do you think you hold" then has to agree with. Stating which step is weakest is part of the deliverable.
Valuation conventions, stated before the numbers
- •Liquid staking tokens are converted to their ETH equivalent using each protocol's own on-chain redemption rate, then valued at the Chainlink ETH/USD feed. This is a redemption-rate valuation, not a market-price one. Secondary market prices can sit below redemption value, and this document does not read them.
- •Stablecoins are valued at exactly $1.0000 per unit. This is a convention, and it is generous by a measurable amount: the Chainlink USDC/USD feed reads 0.99980963 at this block, so the operating wallet's USDC is overstated by $1,437.38 against that feed.
- •stETH is treated as 1 ETH. The Chainlink stETH/ETH feed reads 1.000133577293157200 at this block, so this convention understates the stETH position by $263.04.
- •ENS is valued at the Chainlink ENS/USD feed. That feed had not updated for 20h 34m at the block, which is inside its heartbeat but is the single stalest input in this document. Every ENS-denominated figure moves with it.
- •Airdropped tokens with no price feed are excluded from every total and are addressed separately under hygiene. Excluding them is a decision, not an oversight.
- •Every total is computed from raw integer values and rounded once, at the end, while each row is rounded independently for display. So adding a displayed column can land a cent away from the displayed total, and where it does the total is the right figure. It happens twice here: the ETH bucket carries a WETH dust line worth $0.000192 that prints as $0.00, and the stablecoin bucket rounds down across its rows. Both are stated rather than papered over, because a reader who checks the addition should find the explanation already written down.
| Chainlink feed | Aggregator | Answer at the block | Age at the block |
|---|---|---|---|
| ETH / USD | 0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419 | 1,921.45000000 | 14m 48s |
| stETH / USD | 0xCfE54B5cD566aB89272946F602D76Ea879CAb4a8 | 1,908.39300831 | 52m 24s |
| USDC / USD | 0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6 | 0.99980963 | 16h 26m 36s |
| stETH / ETH | 0x86392dC19c0b719886221c78AB11eb8Cf5c52812 | 1.000133577293157200 | 19h 49m 36s |
| ENS / USD | 0x5C00128d4d1c2F4f652C267d7bcdD7aC99C16E16 | 4.29061484 | 20h 34m 00s |
Age is the block timestamp minus the feed's updatedAt. Every one of these is inside its published heartbeat; the ENS/USD and stETH/ETH ages are stated because a reader pricing a 35% ENS position should know how fresh that price is.
cast call 0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419 \ "latestRoundData()(uint80,int256,uint256,uint256,uint80)" \ --rpc-url https://eth.merkle.io --block 25721000
1. The perimeter, and how each address was proven
A treasury map is only as good as its address list, and an address list taken from a block explorer's label is a rumour. ENS publishes its own addresses as ENS names, which makes the enumeration self-proving: the DAO controls the name, so the name is the DAO's own statement about which address is which.
cast resolve-name wallet.ensdao.eth --rpc-url https://eth.merkle.io cast resolve-name endowment.ensdao.eth --rpc-url https://eth.merkle.io cast resolve-name controller.ens.eth --rpc-url https://eth.merkle.io # and the same answer from a completely different direction: cast call 0x323A76393544d5ecca80cd6ef2A560C6a395b7E3 "timelock()(address)" \ --rpc-url https://eth.merkle.io --block 25721000 # -> 0xFe89cc7aBB2C4183683ab71653C4cdc9B02D44b7, matching wallet.ensdao.eth
The DAO wallet. An OpenZeppelin TimelockController, not a Safe. In scope.
Proven by: ENS resolution, and independently ENSGovernor.timelock()
The endowment. A Safe v1.3.0 whose only owner is the DAO wallet. In scope.
Proven by: ENS resolution, confirmed by reverse resolution of the address
Registration revenue accrues here before it is swept. 0.639850507409239097 ETH at the block. In scope, immaterial.
Proven by: ENS resolution
1.174809703328599995 ETH at the block. In scope, immaterial.
Proven by: Predecessor of controller.ens.eth
Meta-governance working group Safe, 2 of 4. 23.63 ETH, 119,601.14 USDC, 130,129.41 ENS. Perimeter only, not consolidated.
Proven by: ENS resolution, and independently as the sole allowance-module delegate
Public goods working group Safe, 3 of 4. Zero ETH, zero USDC, zero ENS at the block. Perimeter only.
Proven by: ENS resolution
What is deliberately outside the perimeter
- •One chain. Ethereum mainnet only. The fixed tier covers one entity on up to two chains, and this subject's mapped value is on mainnet, so the second chain was not needed. Holdings on other chains, if any exist, are not in these totals.
- •Working group Safes are listed in the perimeter with their headline balances but are NOT consolidated into any total, because they are separately governed budgets rather than treasury reserves. Consolidating them would inflate every concentration percentage on this page.
- •wg.ens.eth resolves to an externally owned account holding 0.000030444067337795 ETH and no tokens. Recorded, immaterial, excluded.
- •Registration revenue reaches the DAO wallet as an internal ETH transfer, which emits no log and therefore cannot be measured from a public node without trace access. This document does not estimate the DAO's income, and says so rather than guessing.
- •Off-chain commitments, grant obligations, vesting schedules and anything else that lives in governance forum posts rather than in state. A health check on public data can only see the balance sheet, never the liabilities beside it.
2. What is held, and where
The DAO wallet: wallet.ensdao.eth
The operating treasury. Everything here is held directly, in the timelock contract itself, and none of it is deployed into a yield venue.
| Asset | Balance | Price used | Value |
|---|---|---|---|
| ENS | 9,629,421.596646019731884049 | $4.29061484 | $41,316,139.20 |
| ETH (native) | 4,499.789208485555923108 | $1,921.45 | $8,646,119.97 |
| USDC | 7,550,477.216881 | $1.0000 | $7,550,477.22 |
| WETH | 0.000000100000000000 | $1,921.45 | $0.00 |
Total $57,512,736.39. The ENS position is 9.6294% of the 100,000,000 total supply, held by the DAO in its own token.
W=0xFe89cc7aBB2C4183683ab71653C4cdc9B02D44b7 cast balance $W --rpc-url https://eth.merkle.io --block 25721000 # -> 4499789208485555923108 cast call 0xC18360217D8F7Ab5e7c516566761Ea12Ce7F9D72 "balanceOf(address)(uint256)" $W \ --rpc-url https://eth.merkle.io --block 25721000 # -> 9629421596646019731884049 cast call 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 "balanceOf(address)(uint256)" $W \ --rpc-url https://eth.merkle.io --block 25721000 # -> 7550477216881
The endowment, ETH leg: endowment.ensdao.eth
Receipt tokens are converted to their ETH equivalent using each protocol's own rate function, read at the same block. The rate column is the redemption rate per whole token, so the arithmetic in the fourth column is one multiplication a reader can repeat.
| Position | Balance | Rate to ETH | ETH equivalent | Value |
|---|---|---|---|---|
| weETH (ether.fi) | 7,449.133773802619493417 | 1.101127921644879141 | 8,202.449190 | $15,760,596.00 |
| ETHx (Stader) | 6,495.065507483995959061 | 1.094783933789241951 | 7,110.693367 | $13,662,841.77 |
| stETH (Lido) | 1,024.845959951092689837 | 1 (rebasing) | 1,024.845960 | $1,969,190.27 |
| WETH | 195.800000000000000000 | 1 | 195.800000 | $376,219.91 |
| ETH (native) | 43.633973104581372937 | 1 | 43.633973 | $83,840.50 |
| wstETH (Lido) | 0.121897498127091334 | 1.241292942091248770 | 0.151311 | $290.74 |
| KPK ETH Prime | 0.000109453105315006 | 1.018954167821159223 | 0.000112 | $0.21 |
| eETH (ether.fi) | 0.000000000000000001 | 1 (rebasing) | 0.000000 | $0.00 |
Total 16,577.573912 ETH equivalent, $31,852,979.39. Rates are redemption rates read on chain, not market quotes.
E=0x4F2083f5fBede34C2714aFfb3105539775f7FE64 # ether.fi weETH: balance, then the rate that turns it into eETH cast call 0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee "balanceOf(address)(uint256)" $E \ --rpc-url https://eth.merkle.io --block 25721000 # -> 7449133773802619493417 cast call 0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee "getEETHByWeETH(uint256)(uint256)" 1000000000000000000 \ --rpc-url https://eth.merkle.io --block 25721000 # -> 1101127921644879141 # Stader ETHx: the rate lives on the pool manager, and the manager is derived, # not assumed. ETHx.staderConfig() -> StaderConfig.getStakePoolManager(). cast call 0xA35b1B31Ce002FBF2058D22F30f95D405200A15b "staderConfig()(address)" \ --rpc-url https://eth.merkle.io --block 25721000 # -> 0x4ABEF2263d5A5ED582FC9A9789a41D85b68d69DB cast call 0x4ABEF2263d5A5ED582FC9A9789a41D85b68d69DB "getStakePoolManager()(address)" \ --rpc-url https://eth.merkle.io --block 25721000 # -> 0xcf5EA1b38380f6aF39068375516Daf40Ed70D299 cast call 0xcf5EA1b38380f6aF39068375516Daf40Ed70D299 "getExchangeRate()(uint256)" \ --rpc-url https://eth.merkle.io --block 25721000 # -> 1094783933789241951
The endowment, stablecoin leg
Where a position is an ERC-4626 vault, the figure below is the vault's own answer to how many underlying units the holding is worth, not a number this document computed. Where it is a rebasing receipt, the balance already is the underlying.
| Position | Underlying | Value at $1.0000 |
|---|---|---|
| fUSDC (Fluid) | 9,938,670.831761 USDC | $9,938,670.83 |
| KPK USDC Prime (Morpho Vault V2) | 7,522,942.548734 USDC | $7,522,942.55 |
| fGHO (Fluid) | 2,509,044.576077 GHO | $2,509,044.58 |
| aEthUSDC (Aave v3) | 2,501,043.736715 USDC | $2,501,043.74 |
| sUSDS (Sky) | 2,008,180.542688 USDS | $2,008,180.54 |
| cUSDCv3 (Compound III) | 1,500,550.842665 USDC | $1,500,550.84 |
| fUSDT (Fluid) | 1,015,275.581726 USDT | $1,015,275.58 |
| USDS, unstaked (Sky) | 6.165847 USDS | $6.17 |
Total $26,995,714.83. Deriving these from convertToAssets independently reproduces the vault-reported figures exactly for fUSDC, fUSDT and fGHO, and to twelve decimal places for sUSDS.
# Fluid fUSDC: shares held, then what the vault says they are worth cast call 0x9Fb7b4477576Fe5B32be4C1843aFB1e55F251B33 "balanceOf(address)(uint256)" $E \ --rpc-url https://eth.merkle.io --block 25721000 # -> 8210632302044 cast call 0x9Fb7b4477576Fe5B32be4C1843aFB1e55F251B33 "maxWithdraw(address)(uint256)" $E \ --rpc-url https://eth.merkle.io --block 25721000 # -> 9938670831761 # Aave and Compound receipts are already denominated in USDC cast call 0x98C23E9d8f34FEFb1B7BD6a91B7FF122F4e16F5c "balanceOf(address)(uint256)" $E \ --rpc-url https://eth.merkle.io --block 25721000 # -> 2501043736715 cast call 0xc3d688B66703497DAA19211EEdff47f25384cdc3 "balanceOf(address)(uint256)" $E \ --rpc-url https://eth.merkle.io --block 25721000 # -> 1500550842665
3. Concentration, stated as numbers rather than colours
The single largest line is the DAO's own token, at 35.51% of mapped value. That is the structural exposure every token-governed treasury carries, and it is the one number in this document that is not a criticism: a DAO cannot diversify out of its own token without selling it, and selling it is a governance question rather than a treasury one. What matters for a health check is that it is stated, sized, and that the remaining 64.49% is not correlated to it by accident. Here it is not: the non-ENS balance is roughly half ETH and half dollars, and both halves are held in instruments that redeem rather than in positions that need a buyer.
Counterparty and venue exposure
Every venue below is a distinct set of smart contracts with a distinct failure mode. Percentages are of the endowment, then of total mapped value, because those two denominators answer different questions.
| Venue | Instrument | Exposure | % endowment | % mapped |
|---|---|---|---|---|
| ether.fi | weETH, eETH | $15,760,596.00 | 26.78% | 13.54% |
| Stader | ETHx | $13,662,841.77 | 23.22% | 11.74% |
| Fluid | fUSDC, fUSDT, fGHO | $13,462,990.99 | 22.88% | 11.57% |
| Morpho Vault V2 | KPK USDC Prime | $7,522,942.55 | 12.78% | 6.47% |
| Aave v3 | aEthUSDC | $2,501,043.74 | 4.25% | 2.15% |
| Sky | sUSDS, USDS | $2,008,186.71 | 3.41% | 1.73% |
| Lido | stETH, wstETH | $1,969,481.01 | 3.35% | 1.69% |
| Compound III | cUSDCv3 | $1,500,550.84 | 2.55% | 1.29% |
| None (WETH) | WETH | $376,219.91 | 0.64% | 0.32% |
| None (native ETH) | ETH | $83,840.50 | 0.14% | 0.07% |
| Morpho Vault V2 | KPK ETH Prime | $0.21 | 0.00% | 0.00% |
Sums to $58,848,694.22, the endowment total, to the cent. Largest single venue 26.78% of the endowment; top three 72.88%.
What the concentration table actually says
- •Roughly half the endowment's ETH leg sits in two liquid staking protocols that are not Lido: ether.fi at 26.78% and Stader at 23.22%, against Lido at 3.35%. Whether that is diversification away from the dominant staking provider or concentration into two smaller ones is a policy judgement, not an arithmetic one. This document sizes it and stops there.
- •The stablecoin leg is spread across five distinct lending and savings protocols with no venue above 22.88% of the endowment. That is a deliberate-looking spread rather than a single-venue bet.
- •Three of the eleven venue lines are not venues at all: unwrapped WETH, native ETH and a dust vault position, together 0.78% of the endowment. Naming them keeps the table summing to the total, which is how a reader knows nothing was quietly dropped.
- •Two named tokens carry the same manager's name, KPK USDC Prime and KPK ETH Prime. They are Morpho Vault V2 instances rather than a proprietary custody wrapper, so the exposure is to Morpho's vault code and to that vault's allocation, both readable on chain.
4. Who can move this money
This is the section a treasurer should read first and the one most treasury dashboards do not have. Holdings tell you what is at risk; the control surface tells you who has to agree before it moves. The role set below was not assembled by checking addresses we already suspected. It was derived by replaying every access-control event the timelock has ever emitted, which is the only method that can find a role holder nobody thought to look for.
| Block | Event | Role | Account | Status at the pinned block |
|---|---|---|---|---|
| 13,533,514 | grant | TIMELOCK_ADMIN | 0x0904dac3...b99859 (deployer) | revoked at 13,533,811 |
| 13,533,514 | grant | TIMELOCK_ADMIN | the timelock itself | in force |
| 13,533,514 | grant | EXECUTOR | 0x0000...0000 (anyone) | in force |
| 13,533,792 | grant | PROPOSER | ENS Governor | in force |
| 13,533,811 | revoke | TIMELOCK_ADMIN | 0x0904dac3...b99859 (deployer) | deployer key stood down |
| 20,399,028 | grant | PROPOSER | 0xb8FA0Ce3...63ee0 (council v1) | revoked at 25,660,634 |
| 25,586,264 | grant | PROPOSER | 0x2acbF518...0AE051 (council v2) | in force |
| 25,660,634 | revoke | PROPOSER | 0xb8FA0Ce3...63ee0 (council v1) | self-revoked after expiry |
Eight events, from the timelock's deployment in November 2021 to the pinned block. This is the complete access-control history of the contract, not a sample.
cast rpc eth_getLogs '{
"address": "0xFe89cc7aBB2C4183683ab71653C4cdc9B02D44b7",
"topics": [[
"0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d",
"0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b"
]],
"fromBlock": "0x0", "toBlock": "0x1887968"
}' --rpc-url https://gateway.tenderly.co/public/mainnet
# topic[0] values are keccak("RoleGranted(bytes32,address,address)") and
# keccak("RoleRevoked(bytes32,address,address)"). Confirm each result with:
cast call 0xFe89cc7aBB2C4183683ab71653C4cdc9B02D44b7 "hasRole(bytes32,address)(bool)" \
$(cast keccak "PROPOSER_ROLE") 0x323A76393544d5ecca80cd6ef2A560C6a395b7E3 \
--rpc-url https://eth.merkle.io --block 25721000 # -> trueThe governance path
ENS Governor at 0x323A76393544d5ecca80cd6ef2A560C6a395b7E3. Proposal threshold 100,000 ENS, quorum 1,000,000 ENS, voting delay 1 block, voting period 45,818 blocks, roughly 6.4 days. A passed proposal queues into the timelock, which enforces a minimum delay of 172,800 seconds, exactly 2 days, before anything can execute.
Execution is open, and that is fine
EXECUTOR_ROLE is held by the zero address, which in an OpenZeppelin timelock means anyone may execute a matured operation. This looks alarming and is not: execution can only run what the Governor already queued and the delay already matured. It removes a liveness dependency on a privileged executor rather than adding a privilege.
There is a second proposer, and it is a veto
A contract at 0x2acBf518b3759f6e1fA163294eda55bF1d0ae051 also holds PROPOSER_ROLE, granted at block 25,586,264. In this timelock, cancelling requires PROPOSER_ROLE, so a security council needs it in order to cancel. The important check is what that contract can actually do: its runtime bytecode exposes veto(bytes32) and cancel(bytes32) and contains no schedule, scheduleBatch, execute or grantRole entry point at all. It can stop a queued proposal. It has no code path to create one.
The council term is enforced in code, and it fired
The council contract carries an expiration() of 2028-07-16 19:49:11 UTC and a renounceTimelockRoleByExpiration() entry point. Its predecessor at 0xB8fA0cE3f91F41C5292D07475b445c35ddF63eE0 expired on 2026-07-24 and its PROPOSER_ROLE was revoked at block 25,660,634, in a transaction sent by the expired contract itself. A term limit that has actually been observed on chain is worth more than one that has only been written down.
The endowment's own control surface
The endowment is a Safe, but not the kind of Safe most treasuries run. Its owner set has exactly one entry, and that entry is the DAO timelock.
cast call $E "getOwners()(address[])" --rpc-url https://eth.merkle.io --block 25721000 # -> [0xFe89cc7aBB2C4183683ab71653C4cdc9B02D44b7] (the DAO timelock, and only it) cast call $E "getThreshold()(uint256)" --rpc-url https://eth.merkle.io --block 25721000 # -> 1 cast call $E "VERSION()(string)" --rpc-url https://eth.merkle.io --block 25721000 # -> "1.3.0" cast call $E "getModulesPaginated(address,uint256)(address[],address)" \ 0x0000000000000000000000000000000000000001 20 --rpc-url https://eth.merkle.io --block 25721000 # -> [0x703806E61847984346d2D7DDd853049627e50A40, # 0xCFbFaC74C26F8647cBDb8c5caf80BB5b32E43134]
A passed ENS vote, then 2 days in the timelock, then the timelock signs as the Safe's only owner. No human signer can take this path alone, because the only owner is a contract.
Module 0x703806E61847984346d2D7DDd853049627e50A40 is a Zodiac Roles Modifier: an EIP-1167 minimal proxy to mastercopy 0x9646fDAD06d3e24444381f44362a3B0eB343D337, whose avatar, target and owner are all the endowment Safe itself. Exactly one address is enabled on it: 0xb423e0f6E7430fa29500c5cC9bd83D28c8BD8978, which reverse-resolves to ens-endowment.pod.xyz and is a Safe v1.3.0 with 8 owners and a threshold of 2, at nonce 861. So the day-to-day manager is a 2-of-8, and it does not sign as an owner of the endowment. It routes through a modifier that can only permit what the DAO scoped into it.
This is a genuinely strong arrangement, and the honest caveat is the size of the scope rather than the shape of it: the exact permission set inside a Roles Modifier is not readable from a single call, so this document reports the structure and marks the scope as unmeasured rather than pretending to have priced it.
Module 0xCFbFaC74C26F8647cBDb8c5caf80BB5b32E43134 is the Safe Allowance Module, version 0.1.0. It has one delegate for this Safe: 0x91c32893216dE3eA0a55ABb9851f581d4503d39b, which reverse-resolves to main.mg.wg.ens.eth, a 2-of-4 Safe. The allowance is on ETH only, capped at 30 ETH per 36,000 minute window, which is 25 days, with 0 spent in the current window.
At the block's ETH price that ceiling is about $57,643 per window, or 0.098% of the endowment. It is small, it is scoped to one asset, it resets rather than accumulating, and it was granted by governance. It is also the only path on this page by which value leaves the endowment without either a DAO vote or the Roles Modifier, which is exactly why a health check names it instead of rounding it to zero. Note too that the DAO timelock is itself one of that Safe's four owners.
AM=0xCFbFaC74C26F8647cBDb8c5caf80BB5b32E43134 cast call $AM "getDelegates(address,uint48,uint8)(address[],uint48)" $E 0 20 \ --rpc-url https://eth.merkle.io --block 25721000 # -> [0x91c32893216dE3eA0a55ABb9851f581d4503d39b] cast call $AM "getTokenAllowance(address,address,address)(uint256[5])" \ $E 0x91c32893216dE3eA0a55ABb9851f581d4503d39b \ 0x0000000000000000000000000000000000000000 \ --rpc-url https://eth.merkle.io --block 25721000 # -> [30000000000000000000, 0, 36000, 29761613, 26] # amount, spent, resetTimeMin, lastResetMin, nonce
5. How much of it could actually move today
A holdings table says what is owned. A liquidity ladder says what could be turned into dollars before the end of the day, which is the number that matters the moment anything goes wrong. Every figure in the exitable column is the venue's own answer at the pinned block, not an estimate.
| Position | Held | Exitable same block | Constraint |
|---|---|---|---|
| fUSDC (Fluid) | $9,938,670.83 | $9,938,670.83 | maxWithdraw covers the whole position |
| KPK USDC Prime | $7,522,942.55 | $0.00 | vault idle balance is zero at this block |
| fGHO (Fluid) | $2,509,044.58 | $2,509,044.58 | maxWithdraw covers the whole position |
| aEthUSDC (Aave v3) | $2,501,043.74 | $2,501,043.74 | pool holds 177,579,728.10 USDC |
| sUSDS (Sky) | $2,008,180.54 | $2,008,180.54 | maxWithdraw covers the whole position |
| cUSDCv3 (Compound III) | $1,500,550.84 | $1,500,550.84 | comet holds 47,075,019.75 USDC |
| fUSDT (Fluid) | $1,015,275.58 | $1,015,275.58 | maxWithdraw covers the whole position |
| USDS, unstaked | $6.17 | $6.17 | plain ERC-20 balance |
Stablecoin leg: $19,472,772.28 of $26,995,714.83 exitable in a single block, 72.13%. The $7,522,942.55 that is not exitable is one position.
The one position that reports zero, and what that actually means
KPK USDC Prime returns maxWithdraw = 0 for this holder at this block, on a position worth $7,522,942.55. Before reporting that as a lock, three things were checked, because a zero in an ERC-4626 view has several possible causes and only one of them is alarming.
- •It is not a transfer gate. The vault is a Morpho Vault V2, which gates share movement, and canSendShares for this holder returns true.
- •It is not an async redemption queue. The vault does not implement ERC-7540, and pendingRedeemRequest and claimableRedeemRequest are not present.
- •It is idle liquidity. USDC.balanceOf on the vault itself is 0 at this block, against totalAssets of 20,373,297.502416 USDC. Every asset is allocated out to adapters, so there is nothing sitting in the vault to hand back in the same transaction.
So the correct statement is not that the money is stuck. It is that exiting requires an allocator to deallocate first, or the holder to call forceDeallocate, which the vault exposes permissionlessly and which carries a penalty. That is a normal design for a vault that is meant to stay invested. It is still worth a line in a health check, because "28% of the dollar leg needs a second step to exit" is a fact a treasurer should learn on a quiet Tuesday rather than during a drawdown.
V=0x4Ef53d2cAa51C447fdFEEedee8F07FD1962C9ee6 cast call $V "maxWithdraw(address)(uint256)" $E --rpc-url https://eth.merkle.io --block 25721000 # -> 0 cast call $V "canSendShares(address)(bool)" $E --rpc-url https://eth.merkle.io --block 25721000 # -> true cast call $V "totalAssets()(uint256)" --rpc-url https://eth.merkle.io --block 25721000 # -> 20373297502416 cast call 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 "balanceOf(address)(uint256)" $V \ --rpc-url https://eth.merkle.io --block 25721000 # -> 0
The ETH leg, and the boundary this document will not cross
$31,852,979.39 of the endowment is liquid staking positions. None of it redeems in a single block. Lido, Stader and ether.fi each exit through a withdrawal queue whose depth changes daily, and the alternative is a secondary market sale at whatever depth exists on the day. Measuring either honestly means measuring queue length and market depth at a point in time, and neither is a single call.
So this document does not put a number on it. What it says instead is the shape: the dollar leg is where same-day liquidity lives, the ETH leg is not, and any plan that assumes otherwise is assuming something nobody has checked. Marking the boundary is the finding.
6. The idle cash line
The operating wallet holds 7,550,477.216881 USDC and 4,499.789208485555923108 ETH, both sitting directly in the timelock contract, neither deployed anywhere. Together that is $16,196,597.19, or 13.92% of mapped value, earning nothing.
The benchmark used below is deliberately not a Kerne product. It is the Sky Savings Rate, which this same treasury is already earning on $2,008,180.54 of sUSDS in its own endowment, read from the same chain at the same block. Comparing an idle balance to a rate the owner has already chosen elsewhere is the only comparison that does not smuggle in a recommendation.
| Balance | Amount | Earning today | At the rate the endowment already uses |
|---|---|---|---|
| Operating USDC | $7,550,477.22 | 0.00% | 3.5200%, about $265,777 per year |
| Operating ETH | $8,646,119.97 | 0.00% | not benchmarked, see note |
| Endowment raw ETH and WETH | $460,060.41 | 0.00% | not benchmarked, see note |
The 3.5200% figure is computed from the Sky Savings Rate ray read on chain, 1000000001096988989836188433, compounded over 31,536,000 seconds. The ETH balances are not benchmarked because staking them changes their liquidity profile, and a health check that quietly assumes a treasury wants that has stopped measuring and started advising.
cast call 0xa3931d71877C0E7a3148CB7Eb4463524FEc27fbD "ssr()(uint256)" \ --rpc-url https://eth.merkle.io --block 25721000 # -> 1000000001096988989836188433 (per-second rate, 27 decimals) # APY = (ssr / 1e27) ** 31536000 - 1 = 3.5200%
Read this line carefully before treating it as a finding
An idle operating balance is not automatically a mistake. Operating cash is meant to be spendable at zero notice, and a treasury that has deliberately chosen to hold its next several quarters of expenses in an instrument with no smart contract risk at all has made a defensible choice, not a lazy one. $265,777 a year is the price of that choice, and the only person who can say whether it is worth paying is the one who knows the spending schedule, which is not readable on chain and is therefore not in this document.
What a health check contributes here is the number, not the verdict.
7. Where the balance has been
One balance is a snapshot. Five are a shape. Each row below is one historical read at a specific block, so the trend is as reproducible as the snapshot.
| Block | Date | Wallet ETH | Wallet USDC |
|---|---|---|---|
| 23,093,000 | 2025-08-08 | 2,795.376 | 7,425,507.53 |
| 24,425,000 | 2026-02-10 | 4,048.714 | 379,665.36 |
| 25,073,000 | 2026-05-11 | 4,466.590 | 2,192,265.26 |
| 25,505,000 | 2026-07-10 | 4,504.788 | 8,097,977.22 |
| 25,721,000 | 2026-08-10 | 4,499.789 | 7,550,477.22 |
Blocks chosen at roughly 12, 6, 3 and 1 month before the pinned block.
for B in 23093000 24425000 25073000 25505000 25721000; do
cast call 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 "balanceOf(address)(uint256)" \
0xFe89cc7aBB2C4183683ab71653C4cdc9B02D44b7 --rpc-url https://eth.merkle.io --block $B
doneTwo things fall out of that table. ETH accumulates steadily and almost monotonically, which is what a treasury funded by a fee stream looks like. The dollar balance does not: it fell to $379,665.36 in February 2026, then was refilled twice. That is a lumpy replenishment cycle rather than a running balance, and the useful question it raises is whether the February low was intentional. A treasury that plans to hold a floor of operating dollars and got within a rounding error of zero has learned something about its own process. A treasury that meant to run that lean has learned nothing and needs no change. Public data can show the shape. It cannot tell you which of those two happened, and this document does not pretend otherwise.
8. Housekeeping, including one thing that would break a naive dashboard
Besides ENS, USDC and WETH, the DAO wallet shows a balance in 58 other token contracts, none of which it asked for. Fifteen of the 58 carry a web address or a claim-your-reward lure in their own name, which is a nuisance rather than a risk as long as nobody ever interacts with them. One of the remaining forty three is worth naming.
A token calling itself Tether USD that is not Tether USD
The wallet holds 6,170,411.31 units of a contract at 0x91235900178f3Ce970028fAd5f1Be25Cd385A2E4 whose name() returns "Tether USD" and whose symbol() returns "USDT". It is not Tether. Real USDT is 0xdAC17F958D2ee523a2206206994597C13D831ec7 and has 6 decimals; this one has 18.
The reason it belongs in a treasury memo rather than a spam folder is arithmetic. Any dashboard that aggregates holdings by ticker symbol rather than by contract address will read this wallet as holding $6.17M of USDT that does not exist, an overstatement of 5.3% against mapped value. That is not a hypothetical failure mode; it is the most common way a treasury report ends up wrong. This document values positions by contract address only, which is why the figure does not appear in any total above.
cast call 0x91235900178f3Ce970028fAd5f1Be25Cd385A2E4 "name()(string)" \ --rpc-url https://eth.merkle.io --block 25721000 # -> "Tether USD" cast call 0x91235900178f3Ce970028fAd5f1Be25Cd385A2E4 "decimals()(uint8)" \ --rpc-url https://eth.merkle.io --block 25721000 # -> 18 cast call 0xdAC17F958D2ee523a2206206994597C13D831ec7 "decimals()(uint8)" \ --rpc-url https://eth.merkle.io --block 25721000 # -> 6 (the real one)
There is no action implied here. Unsolicited tokens cannot be refused, sweeping them costs gas for no benefit, and interacting with them is the actual risk. The finding is about how the treasury is measured, not about what it holds.
9. Allocation memo, dated 2026-08-09
Read this as a worked example of the format, not as advice. Kerne holds no licence to give investment, legal or tax advice, has no relationship with the subject, and cannot see the spending schedule, grant obligations or off-chain commitments that would determine whether any of the observations below matter. A real engagement starts by asking for exactly those things. This one could not, because nobody was asked.
What the numbers say
- 1. The control architecture is stronger than most treasuries of this size, and the evidence is on chain rather than in a policy document.
A Safe whose only owner is a 2-day timelock cannot be drained by a compromised signer, because there is no signer. A manager that operates through a permission modifier rather than as an owner cannot exceed the permissions the DAO scoped. A security council that can cancel but has no bytecode path to schedule cannot become an attacker. And the previous council's term expired and its role was actually revoked on chain, which is the difference between a governance control and a governance intention.
- 2. The concentration that dominates the balance sheet is the one nobody can fix, and it is disclosed rather than hidden.
35.51% in the DAO's own token is structural. The meaningful question is not whether to hold it but whether the other 64.49% would survive the same shock that hit it, and here the answer is reasonable: the non-ENS balance is split roughly evenly between ETH-denominated and dollar-denominated assets, and the dollar half is spread across five protocols with no venue above 22.88% of the endowment.
- 3. Same-day dollar liquidity is 72.13% of the dollar leg, and the gap is one position with a known second step.
$19.47M of the $27.00M stablecoin leg exits in one block. The remaining $7.52M needs a deallocation first. That is a design choice of the vault rather than a defect, but it is the kind of fact that should be written down before it is needed rather than discovered during a week when it is.
- 4. The staking allocation is concentrated away from the market leader, and that is a policy question this document cannot answer.
ether.fi and Stader together are 50.00% of the endowment against Lido at 3.35%. There are defensible reasons to underweight the dominant provider and defensible reasons not to. What a treasurer should want is for that split to be the result of a decision that was written down, rather than the residue of a series of individually sensible allocations.
- 5. $16.20M sits idle, and the cost of that is $265,777 a year at a rate this treasury already accepts elsewhere.
This is the only line in the memo with a dollar figure attached to inaction, and it is also the line most likely to be correct-as-is. Operating cash is supposed to be boring. The number is offered so the choice can be made deliberately rather than by default.
The case against everything above
A memo that only argues one way is marketing. Here is the strongest version of the opposite case, which a reader should weigh at least as heavily.
- •Every observation here is a snapshot of one block. A treasury is a moving thing, and a manager who rebalanced yesterday will look different tomorrow. Nothing in this document establishes a pattern, because one block cannot.
- •The idle-cash figure assumes the balance would otherwise sit still for a year. If it is working capital with a known drawdown schedule, the real foregone yield is a fraction of $265,777 and possibly close to zero.
- •The liquidity ladder measures venue capacity, not market capacity. Withdrawing $19.47M from lending markets in one block is possible per the contracts; doing it without moving rates against yourself is a different question this document does not touch.
- •The Roles Modifier scope is unmeasured. If that scope is wide, the 2-of-8 manager pod is a materially larger control surface than the structure suggests, and this document would have understated it. It reports the shape it can prove and flags the part it cannot.
- •An outside reader with no access to the subject's plans will always find things that look like gaps and are actually decisions. The value of a health check is that it produces a list worth arguing with, not a list that is right.
10. What this document could not determine
Every one of these is a boundary rather than an omission. A memo that does not have this section has one and is not telling you.
- •Income. Registration revenue arrives at the DAO wallet as an internal ETH transfer, which emits no event and is not readable from a public node without trace access. No revenue or runway figure appears anywhere above.
- •Liabilities. Grant commitments, streams, vesting and anything agreed in a forum post are invisible to state reads. Every figure here is an asset figure.
- •The exact permission scope of the Zodiac Roles Modifier, which is not retrievable in a single call.
- •Withdrawal-queue depth at Lido, Stader and ether.fi, and therefore the true same-week liquidity of $31.85M of ETH-denominated assets.
- •The underlying allocation inside the two Morpho Vault V2 positions. The vaults are readable, and following them one layer deeper is a larger piece of work than a fixed-tier check contains.
- •Whether any observation here matters, which depends entirely on intent that public data does not carry.
That is the deliverable.
The paid version is this, on your addresses, with the parts that needed your intent filled in by asking you. Same format, same discipline about reproducing every figure, same section marking the limits. It is $5,000, fixed, for one entity on up to two chains and up to twenty addresses, delivered within 5 business days of scope confirmation, and fully refundable until that scope is confirmed with you in writing.
This document took the same box: two core addresses, four more in the perimeter, one chain, one block.
No mandate has been signed to date and this document describes no client engagement, which is exactly why it exists: rather than ask you to take the work on trust, here is the work.
Kerne is infrastructure, not a custodian or an investment adviser. Nothing on this page is investment, legal, tax, or accounting advice, and nothing on it is a solicitation to or about ENS DAO, which is not a client and was not consulted. All figures are reads of public Ethereum state at block 25,721,000 and were correct at that block only. The health check is not an audit and not a security review; see the published scope for what it excludes.