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

libraries · embedded vs linked · using-for

SoliaVSThe Reentrancy Reaper
Solia saysLibrary functions can be embedded (internal, inlined at every call site) or linked (external, deployed once and delegatecalled) — picking the wrong one wastes bytecode or gas.

Solidity libraries come in two flavors. Embedded libraries have only internal functions; the compiler inlines their code at every call site. Linked libraries have at least one external/public function; they are deployed once and called via delegatecall from every consumer.

Embedded is cheap to call (no delegatecall overhead) but bloats every consumer with the library bytes. Linked saves bytes per consumer but pays ~700 gas per call for the delegatecall. using LibX for Type makes calls look like methods on a type. The demo compares the trade-offs for 5 call sites.

Power-ups you unlock

The Reentrancy Reaper attacks — common mistakes

Boss battleEstimate deploy and per-call gas for an embedded vs a linked library across 5 call sites.

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 LIB_CODE_BYTES = 800;
const DEPLOY_PER_BYTE = 200;
const CALLSITES = 5;
const CALLS_EACH = 100;
const EMBED_CALL_GAS = 25;          // ~ JUMP after inline
const LINKED_CALL_GAS = 700;        // ~ delegatecall overhead
// embedded: code duplicated at each call site
const embedDeploy = LIB_CODE_BYTES * CALLSITES * DEPLOY_PER_BYTE;
const embedRuntime = CALLSITES * CALLS_EACH * EMBED_CALL_GAS;
// linked: library deployed once, consumers delegatecall
const linkDeploy = LIB_CODE_BYTES * DEPLOY_PER_BYTE;
const linkRuntime = CALLSITES * CALLS_EACH * LINKED_CALL_GAS;
document.getElementById('o').textContent = [
  'library: ' + LIB_CODE_BYTES + ' bytes, ' + CALLSITES + ' call sites × ' + CALLS_EACH + ' calls each',
  '',
  'EMBEDDED (internal, inlined):',
  '  deploy gas:  ' + embedDeploy.toLocaleString() + '   (inlined ' + CALLSITES + '×)',
  '  runtime gas: ' + embedRuntime.toLocaleString() + '   (~' + EMBED_CALL_GAS + ' per call)',
  '',
  'LINKED (external, delegatecalled):',
  '  deploy gas:  ' + linkDeploy.toLocaleString() + '   (single deploy)',
  '  runtime gas: ' + linkRuntime.toLocaleString() + '   (~' + LINKED_CALL_GAS + ' per call)',
  '',
  'embedded wins on per-call gas; linked wins on deployment when many consumers exist'
].join('\n');
</script></body></html>
▶ Open the interactive comic issue
‹ Custom Errors · Revert DataFallback · Receive · Low-Level Calls ›