Research / Chain files / Base
13 contracts on Base are tracked and scored by an oracle on Base Sepolia, among them Morpho Blue, Aerodrome and the Uniswap factories. Base is where one Safe signs for the largest tracked lending contract and where Uniswap is governed from Ethereum through a forwarder.
Three calls on the Base (Sepolia) oracle, replayed at the block the Watch read (48160953). They need a public RPC and cast (Foundry) and nothing from us. If your RPC does not keep that block, drop --block: the answers change when the oracle is re-pushed.
RPC=https://sepolia.base.org ORACLE=0x50840a7667baEa9D05ad4ae3dCeb384724b58720 TARGET=0xbbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb # Morpho Blue (singleton) # 1. how many contracts this oracle tracks cast call $ORACLE "trackedTargetsCount()(uint256)" --rpc-url $RPC --block 48160953 # 2. its score, five sub-scores then the composite, then lastUpdated and the method hash cast call $ORACLE "getScore(address)((uint8,uint8,uint8,uint8,uint8,uint8,uint64,bytes32))" $TARGET --rpc-url $RPC --block 48160953 # 3. is that score older than maxStaleness cast call $ORACLE "isStale(address)(bool)" $TARGET --rpc-url $RPC --block 48160953
Expected
1 -> 13 2 -> (65, 95, 0, 100, 80, 55, 1791847930, 0x0ffe08e65a4a36a26b89b8257fca91ff5c4c558f13e367f9bf457231d6848c70) admin, multisig, timelock, price feed, shared signers, composite 3 -> false
The owner of the Morpho Blue singleton on Base is a Safe that needs 5 of 9 signatures. It has no module and no guard, and no timelock sits in front of it. The Morpho Blue contract of Robinhood Chain is owned by a different Safe address whose owner set is identical, at the same threshold: the same nine signers hold the lending contract on two chains. The oracle publishes 80 for shared signers on this target for that reason; the composite (55) does not include that dimension.
# owner of Morpho Blue on Base, and its threshold BASE=https://mainnet.base.org OWNER=$(cast call 0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb "owner()(address)" --rpc-url $BASE) cast call $OWNER "getThreshold()(uint256)" --rpc-url $BASE # -> 5 # number of owners, modules and guard cast call $OWNER "getOwners()(address[])" --rpc-url $BASE | tr ',' '\n' | wc -l cast call $OWNER "getModulesPaginated(address,uint256)(address[],address)" 0x0000000000000000000000000000000000000001 10 --rpc-url $BASE cast storage $OWNER 0x4a204f620c8c5ccdca3fd54d003badd85ba500436a431f0cbda4f558c93c34c8 --rpc-url $BASE # -> 9 owners; modules: [] ; guard slot: all zeros # the Robinhood Chain Safe: same threshold, same owner set (the diff prints nothing) RH=https://rpc.mainnet.chain.robinhood.com SAFE=$(cast call 0x9d53d5e3bd5e8d4cbfa6db1ca238aea02e651010 "owner()(address)" --rpc-url $RH) # Morpho Blue on Robinhood Chain cast call $SAFE "getThreshold()(uint256)" --rpc-url $RH diff <(cast call $OWNER "getOwners()(address[])" --rpc-url $BASE | tr -d '[] ' | tr ',' '\n' | tr A-F a-f | sort) <(cast call $SAFE "getOwners()(address[])" --rpc-url $RH | tr -d '[] ' | tr ',' '\n' | tr A-F a-f | sort) && echo identical # -> 5, then: identical
Notes: finding_2026-09-19-base-morpho-blue-robinhood-overlap.md · scored_targets_2026-09-19-maintenance.md
On Aerodrome, the Voter's governor is the same Safe address as the pool factory's pauser and fee manager: a 3-of-7 Safe with no module attached. None of the governor functions checks a timelock; each one takes effect in the transaction. The Voter's emergency council is a separate Safe (3-of-5) that shares no owner with it and whose powers are limited to killing and reviving gauges. The published composite for the pool factory is 46, with a timelock score of 0.
# the three roles point at one address BASE=https://mainnet.base.org cast call 0x16613524e02ad97eDfeF371bC883F2F5d6C480A5 "governor()(address)" --rpc-url $BASE cast call 0x420DD381b31aEf6683db6B902084cB0FFECe40Da "pauser()(address)" --rpc-url $BASE cast call 0x420DD381b31aEf6683db6B902084cB0FFECe40Da "feeManager()(address)" --rpc-url $BASE # -> the same address three times (0xE6A4...2075) # that Safe: threshold, owners, modules G=$(cast call 0x16613524e02ad97eDfeF371bC883F2F5d6C480A5 "governor()(address)" --rpc-url $BASE) cast call $G "getThreshold()(uint256)" --rpc-url $BASE cast call $G "getOwners()(address[])" --rpc-url $BASE | tr ',' '\n' | wc -l cast call $G "getModulesPaginated(address,uint256)(address[],address)" 0x0000000000000000000000000000000000000001 10 --rpc-url $BASE # -> 3, then 7, then modules: []
Notes: finding_2026-09-18-aerodrome-voter-governor-identity.md
The owner of the Uniswap V4 PoolManager and of the V2 factory on Base is an OP-stack forwarder contract. Its storage slot 0 holds the L2 cross-domain messenger predeploy and its slot 1 holds the Uniswap Governance Timelock on Ethereum, whose delay is 2 days. Three Base targets (V3, V2, V4) sit under that one root, which also roots targets on four other ecosystems: 11 tracked targets in all. The oracle folds that shared root into the shared-signers dimension as 80.
# the owner of the V4 PoolManager and of the V2 factory on Base is one forwarder BASE=https://mainnet.base.org cast call 0x498581ff718922c3f8e6a244956af099b2652b2b "owner()(address)" --rpc-url $BASE cast call 0x8909dc15e40173ff4699343b6eb8132c65e18ec6 "feeToSetter()(address)" --rpc-url $BASE # -> the same address twice (0x31FAfd4889FA1269F7a13A66eE0fB458f27D72A9) # its storage: slot 0 the OP-stack messenger predeploy, slot 1 the Ethereum Timelock F=0x31FAfd4889FA1269F7a13A66eE0fB458f27D72A9 cast storage $F 0 --rpc-url $BASE cast storage $F 1 --rpc-url $BASE # -> a word ending in 4200...0007 (the OP-stack messenger), then a word ending in the Uniswap Timelock address (0x1a9C...35BC) # that Timelock on Ethereum: delay in seconds TL=$(cast parse-bytes32-address $(cast storage $F 1 --rpc-url $BASE)) cast call $TL "delay()(uint256)" --rpc-url https://ethereum-rpc.publicnode.com # -> 172800 (2 days)
Notes: finding_2026-09-20-uniswap-one-timelock-eleven-targets.md · scored_targets_2026-09-16.md
13 targets are tracked on Base, read from mainnet and scored by the oracle on Base (Sepolia). Bands of the composite score:
| moderate | 3 |
|---|---|
| decent | 7 |
| strong | 3 |
Up to 12 targets, ordered by value where known, then by lowest score. Each name opens the contract page.
| Target | Composite | Band |
|---|---|---|
| Morpho Blue (singleton) | 55 | moderate |
| Aave V3 Base | 71 | decent |
| Uniswap V3 Factory (Base) | 85 | strong |
| Aerodrome Slipstream CLFactory | 46 | moderate |
| Aerodrome Finance PoolFactory | 46 | moderate |
| Uniswap V2 Factory (Base) | 85 | strong |
| Uniswap V4 PoolManager (Base) | 85 | strong |
| Compound V3 (Comet, USDC market) | 78 | decent |
| Moonwell Comptroller (Unitroller) | 71 | decent |
| Spark USDC Vault (sparkUSDC) | 63 | decent |
| Gauntlet USDC Prime (gtUSDCp) | 66 | decent |
| Steakhouse USDC | 73 | decent |
Read from the public repository and the Watch at build, 2026-10-15 21:09 UTC. A finding is a dated reading with its replay, not an audit and not investment advice. All chain files · Dashboard.