Comparaison·7 min de lecture·Par Solingo

OpenZeppelin vs Solady — Which Library for Gas Optimization?

Compare OpenZeppelin and Solady contracts to see which saves more gas and when to use each.

# OpenZeppelin vs Solady — Which Library for Gas Optimization?

OpenZeppelin is the industry standard for Solidity contracts — audited, battle-tested, and trusted. But Solady, a newer library by Vectorized, optimizes aggressively for gas savings. Let's compare.

The Libraries

OpenZeppelin

  • Focus: Security, readability, standards compliance
  • Audited: Multiple audits, 8+ years in production
  • Gas: Optimized, but prioritizes safety over gas
  • Use case: Most projects, especially when audited code is critical

Solady

  • Focus: Extreme gas optimization
  • Audited: Newer, growing audit coverage
  • Gas: Heavily optimized, uses assembly
  • Use case: High-volume contracts, L2s, gas-critical apps

Gas Comparison: ERC20

OpenZeppelin ERC20

// @openzeppelin/contracts/token/ERC20/ERC20.sol

function transfer(address to, uint256 amount) public virtual returns (bool) {

address owner = _msgSender();

_transfer(owner, to, amount);

return true;

}

function _transfer(address from, address to, uint256 amount) internal virtual {

require(from != address(0), "ERC20: transfer from the zero address");

require(to != address(0), "ERC20: transfer to the zero address");

_beforeTokenTransfer(from, to, amount);

uint256 fromBalance = _balances[from];

require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");

unchecked {

_balances[from] = fromBalance - amount;

_balances[to] += amount;

}

emit Transfer(from, to, amount);

_afterTokenTransfer(from, to, amount);

}

Gas cost: ~51,000 gas for first transfer, ~34,000 for subsequent

Solady ERC20

// solady/src/tokens/ERC20.sol

function transfer(address to, uint256 amount) public virtual returns (bool) {

_transfer(msg.sender, to, amount);

return true;

}

function _transfer(address from, address to, uint256 amount) internal virtual {

assembly {

let fromBalance := sload(add(_balances.slot, from))

if gt(amount, fromBalance) {

mstore(0x00, 0xf4d678b8) // InsufficientBalance()

revert(0x1c, 0x04)

}

sstore(add(_balances.slot, from), sub(fromBalance, amount))

sstore(add(_balances.slot, to), add(sload(add(_balances.slot, to)), amount))

// Emit Transfer event

mstore(0x00, amount)

log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, from, to)

}

}

Gas cost: ~48,000 gas for first transfer, ~31,000 for subsequent

Savings: ~3,000 gas per transfer (9% cheaper)

Gas Comparison: ERC721

OpenZeppelin ERC721

function transferFrom(address from, address to, uint256 tokenId) public virtual {

require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved");

_transfer(from, to, tokenId);

}

function _transfer(address from, address to, uint256 tokenId) internal virtual {

require(ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner");

require(to != address(0), "ERC721: transfer to the zero address");

_beforeTokenTransfer(from, to, tokenId, 1);

delete _tokenApprovals[tokenId];

unchecked {

_balances[from] -= 1;

_balances[to] += 1;

}

_owners[tokenId] = to;

emit Transfer(from, to, tokenId);

_afterTokenTransfer(from, to, tokenId, 1);

}

Gas cost: ~76,000 gas

Solady ERC721

function transferFrom(address from, address to, uint256 id) public virtual {

assembly {

let ownerAndApproval := sload(add(_ownersAndApprovals.slot, id))

let owner := and(ownerAndApproval, _BITMASK_ADDRESS)

if iszero(eq(owner, from)) {

mstore(0x00, 0xa1148100) // TransferFromIncorrectOwner()

revert(0x1c, 0x04)

}

// Check approval

let approved := shr(160, ownerAndApproval)

if iszero(or(eq(caller(), owner), eq(caller(), approved))) {

if iszero(sload(add(add(_operatorApprovals.slot, owner), caller()))) {

mstore(0x00, 0x4b6e7f18) // NotOwnerNorApproved()

revert(0x1c, 0x04)

}

}

// Transfer

sstore(add(_balances.slot, from), sub(sload(add(_balances.slot, from)), 1))

sstore(add(_balances.slot, to), add(sload(add(_balances.slot, to)), 1))

sstore(add(_ownersAndApprovals.slot, id), to)

log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, from, to, id)

}

}

Gas cost: ~68,000 gas

Savings: ~8,000 gas per transfer (11% cheaper)

Feature Comparison

| Feature | OpenZeppelin | Solady |

|---------|-------------|--------|

| ERC20 | Full featured | Full featured |

| ERC721 | Full featured | Full featured |

| ERC1155 | ✅ | ✅ |

| Access Control | Ownable, AccessControl | Ownable, auth patterns |

| Upgradeability | UUPS, Transparent, Beacon | UUPS variants |

| Utils | SafeMath, Address, Strings | LibBit, LibMap, LibClone |

| Assembly usage | Minimal | Heavy |

| Readability | High | Medium (due to assembly) |

| Audit coverage | Extensive | Growing |

When to Use OpenZeppelin

1. Audit Requirements

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

import "@openzeppelin/contracts/access/Ownable.sol";

contract MyToken is ERC20, Ownable {

constructor() ERC20("MyToken", "MTK") {}

function mint(address to, uint256 amount) external onlyOwner {

_mint(to, amount);

}

}

Why: Auditors are familiar with OZ, security track record is proven.

2. Upgradeable Contracts

import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";

import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

contract MyTokenUpgradeable is Initializable, ERC20Upgradeable {

function initialize() public initializer {

__ERC20_init("MyToken", "MTK");

}

}

Why: OZ has comprehensive upgradeable variants.

3. Extensions and Hooks

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";

import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Pausable.sol";

contract MyToken is ERC20, ERC20Burnable, ERC20Pausable {

// Hooks are easy to override

function _beforeTokenTransfer(

address from,

address to,

uint256 amount

) internal override(ERC20, ERC20Pausable) {

super._beforeTokenTransfer(from, to, amount);

// Custom logic

}

}

Why: OZ's hook system is mature and composable.

When to Use Solady

1. High Transaction Volume

import "solady/src/tokens/ERC20.sol";

contract HighVolumeToken is ERC20 {

function name() public pure override returns (string memory) {

return "HighVolume";

}

function symbol() public pure override returns (string memory) {

return "HVT";

}

// Saves 3k gas per transfer

// 1M transfers = 3B gas saved = ~$500+ at 20 gwei

}

Why: Gas savings compound at scale.

2. L2 Deployments

import "solady/src/tokens/ERC721.sol";

contract L2NFT is ERC721 {

// L2s have lower gas costs but higher throughput

// Solady's optimizations still matter for tx/sec

}

Why: Even on cheap L2s, optimization improves throughput.

3. Gas-Critical Apps

import "solady/src/utils/LibClone.sol";

contract Factory {

address immutable implementation;

function createClone() external returns (address) {

// Solady's LibClone is 10x cheaper than OZ's Clones

return LibClone.clone(implementation);

}

}

Why: Solady's utilities are hyper-optimized.

Hybrid Approach

You can mix libraries:

import "@openzeppelin/contracts/access/Ownable.sol";  // Familiar, audited

import "solady/src/tokens/ERC20.sol"; // Gas-optimized core

contract HybridToken is ERC20, Ownable {

function mint(address to, uint256 amount) external onlyOwner {

_mint(to, amount);

}

}

Real-World Examples

OpenZeppelin Users

  • USDC: Audited, industry standard
  • Uniswap V2/V3: Trusted, proven
  • Compound: Security-first

Solady Users

  • Blur: NFT marketplace (high volume)
  • Zora: L2 NFTs
  • Farcaster: Social protocol (L2)

Benchmarks

| Operation | OpenZeppelin | Solady | Savings |

|-----------|-------------|--------|---------|

| ERC20 transfer | 34,000 | 31,000 | 9% |

| ERC721 transfer | 76,000 | 68,000 | 11% |

| ERC721 mint | 92,000 | 84,000 | 9% |

| Clone creation | 45,000 | 4,500 | 90% |

| Ownable check | 2,400 | 2,100 | 12% |

Key Takeaways

  • OpenZeppelin: Default choice for most projects
  • - Proven security track record

    - Extensive audit coverage

    - Rich ecosystem of extensions

  • Solady: Choose for gas optimization
  • - 9-11% cheaper on standard ops

    - 90% cheaper on specialized utils

    - Growing audit coverage

  • Hybrid: Best of both worlds
  • - Use OZ for access control, upgradeability

    - Use Solady for tokens, utilities

  • Decision factors:
  • - Transaction volume (high → Solady)

    - Audit requirements (strict → OZ)

    - L2 deployment (Solady edge)

    - Team familiarity (OZ default)

  • Test both:
  • forge snapshot --diff

    Both libraries are excellent. OpenZeppelin is the safe default; Solady is the gas-conscious alternative. Choose based on your priorities: security-first or gas-first.

    Prêt à mettre en pratique ?

    Applique ces concepts avec des exercices interactifs sur Solingo.

    Commencer gratuitement