freecoding.school100% FREE · NO SIGNUP
The EVM CoreISSUE #43 of 48

proxy patterns · transparent vs uups

SoliaVSThe Reentrancy Reaper
Solia saysTransparent proxies use the proxy admin to route upgrade calls (admin → proxy, user → implementation); UUPS puts upgrade logic in the implementation itself — cheaper proxy, smarter implementation.

The two dominant upgrade patterns differ in WHERE the upgrade function lives. Transparent proxies route based on the caller: if msg.sender is the proxy admin, the call hits proxy admin functions (upgradeTo, changeAdmin); everyone else delegatecalls to the implementation. The proxy has to check msg.sender on every call. UUPS (Universal Upgradeable Proxy Standard, EIP-1822) moves upgrade logic into the implementation itself, so the proxy is dirt-cheap and the implementation enforces upgrade authorization.

UUPS is cheaper to deploy and call (no admin check on every fallback), but if you ship an implementation without an upgrade function, you brick the proxy forever. The demo shows both dispatch flows.

Power-ups you unlock

The Reentrancy Reaper attacks — common mistakes

Boss battleShow how transparent and UUPS proxies dispatch the same call differently.

Example code

<!doctype html><html><head><meta charset="utf-8"></head>
<body style="background:#06040d;color:#e6e0ff;font-family:monospace;padding:20px"><pre id="o"></pre>
<script>
function transparent(caller, selector, adminAddr){
  if(caller === adminAddr){
    return ['upgradeTo','changeAdmin'].includes(selector) ? 'admin fn in PROXY' : 'admin → non-admin: REVERTS (transparent rule)';
  }
  return 'delegatecall → IMPLEMENTATION';
}
function uups(caller, selector){
  return 'delegatecall → IMPLEMENTATION (upgrade auth checked there)';
}
const calls = [
  { who:'admin', sel:'upgradeTo' },
  { who:'admin', sel:'transfer' },
  { who:'user',  sel:'transfer' },
  { who:'user',  sel:'upgradeTo' }
];
const rows = calls.map(c => '  ' + c.who.padEnd(6) + ' ' + c.sel.padEnd(12) +
  '  transparent: ' + transparent(c.who, c.sel, 'admin').padEnd(34) + '  UUPS: ' + uups(c.who, c.sel));
document.getElementById('o').textContent = ['proxy dispatch comparison:', ...rows].join('\n');
</script></body></html>
▶ Open the interactive comic issue
‹ Commit-Reveal · Hiding IntentThe Diamond Standard · Eip-2535 Facets ›