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

rate limiting · timelocks · guardians

SoliaVSThe Reentrancy Reaper
Solia saysTimelocks queue privileged actions for a mandatory delay (24-72h typical) and rate limits cap how often they fire — together they give users a window to exit before bad upgrades land.

Privileged actions — upgrading an implementation, changing a fee, moving treasury — need friction. A timelock queues the action for a mandatory delay before it can execute; a guardian role can cancel queued actions during the window. Users seeing a malicious queued upgrade have time to exit. Rate limits add a separate guard: at most N privileged calls per time window.

Together they turn "trust the admin" into "verify the admin and have time to respond." The demo queues an action and shows it rejected before the delay elapses, then accepted after, while a rate limiter caps how many calls fit in a window.

Power-ups you unlock

The Reentrancy Reaper attacks — common mistakes

Boss battleQueue an action with a 2-day delay, attempt execution after 1 hour (rejected) and after 2 days (accepted), and rate-limit how many actions fit per window.

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>
const DELAY = 86400 * 2;                       // 2 days
const queue = {};
function propose(actionId, now){ queue[actionId] = now + DELAY; return queue[actionId]; }
function execute(actionId, now){
  if(!(actionId in queue)) return 'NOT QUEUED';
  if(now < queue[actionId]) return 'TOO EARLY (eta ' + (queue[actionId] - now) + 's from now)';
  delete queue[actionId];
  return 'EXECUTED';
}
const now = 1700000000;
propose('upgradeImpl', now);
const r1 = execute('upgradeImpl', now + 3600);          // 1 hour later
const r2 = execute('upgradeImpl', now + DELAY + 1);     // after delay
// rate limit
let calls = 0, windowStart = now;
function rateLimit(t, max, windowSec){
  if(t - windowStart > windowSec){ windowStart = t; calls = 0; }
  if(calls >= max) return false;
  calls++; return true;
}
const rl = [];
for(let i = 0; i < 5; i++) rl.push('  call ' + (i+1) + ': ' + (rateLimit(now + i*60, 3, 3600) ? 'allowed' : 'RATE-LIMITED'));
document.getElementById('o').textContent = [
  'TIMELOCK (2-day delay):',
  '  propose upgradeImpl @ now',
  '  execute after 1 hour    → ' + r1,
  '  execute after 2 days    → ' + r2,
  '',
  'RATE LIMIT (3 calls / hour):',
  ...rl
].join('\n');
</script></body></html>
▶ Open the interactive comic issue
‹ State Machines On-Chain