Skip to content

Foundry toolkit for effortless EIP-2535 Diamond upgrades.

Notifications You must be signed in to change notification settings

montyp0x/diamond-foundry

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

37 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Foundry CI

Diamond Upgrades for Foundry

A zero-friction manager for EIP-2535 Diamond upgrades. This library detects what changed since your last deploy, syncs selectors from ABI, deploys whatever is needed, and executes one deterministic diamondCut. You focus on facet code—everything else is handled.

TL;DR: Change your facets → call upgrade("<name>") → done.


What it does

  • Auto-discovers facets in src/<name>/facets/**.
  • Auto-syncs selectors from out/** (no hand-written bytes4 arrays).
  • Diffs “desired vs last manifest” to build Add / Replace / Remove plan.
  • Deploys new/changed facets and executes diamondCut (optionally with init).
  • Persists a manifest at .diamond-upgrades/<name>/manifest.json after a real broadcast.
  • Protects core (Cut / Loupe / Ownership) and rejects selector collisions.

Project layout

project/
├─ src/
│  ├─ <name>/
│  │  ├─ facets/        # your facets
│  │  ├─ interfaces/
│  │  └─ libraries/
├─ .diamond-upgrades/
│  └─ <name>/
│     ├─ storage.json   # TBA
│     ├─ facets.json    # desired facets (selectors auto-synced)
│     └─ manifest.json  # last on-chain snapshot
├─ out/                 # Foundry artifacts
└─ foundry.toml

Foundry config (required)

Enable FFI and allow the library to read/write manifests:

# foundry.toml
[profile.default]
ffi = true
fs_permissions = [
  { access = "read",       path = "src" },
  { access = "read",       path = "out" },
  { access = "read-write", path = ".diamond-upgrades" }
]

remappings = [
  "diamond-foundry/=lib/diamond-foundry/src/"
]

Quick start

0) Install lib

forge install montyp0x/diamond-foundry

1) Build your code

forge build

2) Deploy a new Diamond

import {DiamondUpgrades} from "diamond-foundry/DiamondUpgrades.sol";

DiamondUpgrades.deployDiamond(
    "example",
    DiamondUpgrades.DeployOpts({
        owner: user,
        opts: DiamondUpgrades.Options({unsafeLayout: false, allowDualWrite: false, force: false})
    }),
    DiamondUpgrades.InitSpec({target: address(0), data: ""})
);

3) Upgrade after changes

// No manual prepare step needed — discovery & selector sync run automatically.
address diamond = DiamondUpgrades.upgrade("example");

The library compares the latest .diamond-upgrades/example/manifest.json with your desired facets, deploys what’s needed, executes a single diamondCut, and writes an updated manifest.


How it works (under the hood)

  • Desired state lives in .diamond-upgrades/<name>/facets.json:

    • each facet is referenced by artifact File.sol:Contract,
    • selectors are always rebuilt from ABI in out/** (so they never drift).
  • Current state lives in .diamond-upgrades/<name>/manifest.json:

    • diamond address, facet addresses, selector ↔ facet mapping, runtime bytecode hashes, history, and a deterministic stateHash.
  • Planner creates a deterministic plan:

    • Add (new selectors),
    • Replace (same selector routed to new facet/bytecode),
    • Remove (selector no longer desired).
  • Executor deploys / reuses facets and calls diamondCut(init?).


Safety & guarantees

  • Core selectors are protected by default (Cut/Loupe/Ownership won’t be accidentally touched).
  • Selector collisions across facets cause a clear revert.
  • No-op upgrades keep facet addresses and stateHash unchanged.
  • Manifests live at .diamond-upgrades/<name>/manifest.json (per diamond name).

Files explained

  • .diamond-upgrades/<name>/facets.json — desired facets & auto-synced selectors.
  • .diamond-upgrades/<name>/manifest.json — last known on-chain snapshot; used for diffing on the next upgrade.
  • .diamond-upgrades/<name>/storage.json — optional namespace/storage policy config (you can ignore it for now).

License

MIT.


Credits

Built for the Foundry ecosystem, inspired by EIP-2535 and the developer experience of OpenZeppelin Upgrades.

About

Foundry toolkit for effortless EIP-2535 Diamond upgrades.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published