Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 2 additions & 11 deletions .prettierrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,17 @@
"tabWidth": 4,
"useTabs": true,
"singleQuote": false,
"bracketSpacing": false,
"trailingComma": "all",
"overrides": [
{
"files": "*.sol",
"options": {
"printWidth": 120,
"tabWidth": 4,
"useTabs": true,
"singleQuote": false,
"bracketSpacing": false
}
},
{
"files": ["*.ts", "*.js", "*.json"],
"options": {
"tabWidth": 4,
"useTabs": true,
"singleQuote": false
}
"files": ["*.json", "*.js", "*.ts"],
"options": {}
}
]
}
263 changes: 172 additions & 91 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,60 +2,176 @@

**ProxyForge** is a lightweight, gas-optimized framework for deploying and managing upgradeable proxies on the Ethereum Virtual Machine (EVM). It maintains compatibility with OpenZeppelin's proxy architecture while introducing low-level optimizations and slot-based metadata tracking.

---

## Features

- **Transparent Proxy** — Transparent proxy pattern (`ERC1967` compatible)
- **Proxy Admin** — Upgrade proxies securely using minimal admin logic
- **Factory Deployment** — Deploy proxies via `CREATE` and `CREATE2`
- **Slot-Based Tracking** — No mappings, storage traced via keccak256 seeds
- **Modular Design** — Components can be used independently or via the factory
- **Transparent Proxy Pattern**: ERC-1967 compliant with admin isolation for security
- **Assembly Optimized**: Extensive use of inline assembly for maximum efficiency
- **Gas-Optimized Deployments**: Highly efficient CREATE and CREATE2 proxy deployments
- **Comprehensive Management**: Deploy, upgrade, transfer ownership, and revoke proxies
- **Deterministic Addresses**: CREATE2 support with collision-resistant salt validation
- **Modular Design**: Components can be used independently or via the factory

## Architecture

### Directory

```text
proxy-forge/
├── deployments/...
├── script/
│ ├── BaseScript.sol
│ ├── Deploy.s.sol
│ ├── DeployProxy.s.sol
│ └── UpgradeProxy.s.sol
├── src/
│ ├── interfaces/
│ │ ├── IForgeProxy.sol
│ │ ├── IForgeProxyAdmin.sol
│ │ └── IProxyForge.sol
│ ├── proxy/
│ │ ├── ForgeProxy.sol
│ │ └── ForgeProxyAdmin.sol
│ └── ProxyForge.sol
└── test/
├── proxy/
│ ├── ForgeProxy.t.sol
│ └── ForgeProxyAdmin.t.sol
├── shared/...
├── ProxyForge.fuzz.t.sol
└── ProxyForge.t.sol
```

---
### Core Contracts

## Contracts Overview
**ProxyForge**: The main factory contract that handles deployment and management operations

| Contract | Description |
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **ForgeProxy** | The core proxy contract that delegates calls to implementation contracts. Features assembly-optimized routing and automatic admin deployment. |
| **ForgeProxyAdmin** | Ultra-lightweight admin contract for managing proxy upgrades. Automatically deployed per proxy with minimal overhead, enabling isolated upgrade control. |
| **ProxyForge** | The central hub for proxy deployment and management. Provides multiple deployment strategies via factory methods, including deterministic and non-deterministic paths. |
- Deploys new proxy instances using CREATE or CREATE2
- Manages proxy ownership and implementation upgrades
- Provides deterministic address computation

---
**ForgeProxy**: Gas-optimized upgradeable proxy implementation

## API Reference
- Follows ERC-1967 standard for storage slots
- Automatic admin contract deployment during construction
- Assembly-optimized fallback routing for maximum efficiency

### Deployment Flow
**ForgeProxyAdmin**: Ultra-lightweight admin contract for proxy management

1. Call `deploy()` or `deployAndCall()` on `ProxyForge`.
2. A `ForgeProxy` is deployed with the specified implementation and (optionally) initialized via delegatecall.
3. A `ForgeProxyAdmin` is auto-deployed and linked to the proxy.
4. Proxy ownership, admin, and implementation are tracked via factory-local slot logic.
- Handles upgrade operations with calldata transformation
- Implements standard ownership patterns
- Compatible with OpenZeppelin ProxyAdmin interface (v5.0.0)

### Usage Snippet
## Deployments

```solidity
// Deploy via CREATE without initialization
address proxy = proxyForge.deploy(implementation, owner);
**ForgeProxy** is deployed on the following chains:

| Network | Chain ID | Address |
| ---------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------- |
| Ethereum | 1 | [0x58b819827cB18Ba425906C69E1Bfb22F27Cb1bCe](https://etherscan.io/address/0x58b819827cB18Ba425906C69E1Bfb22F27Cb1bCe) |
| Ethereum Sepolia | 11155111 | [0x58b819827cB18Ba425906C69E1Bfb22F27Cb1bCe](https://sepolia.etherscan.io/address/0x58b819827cB18Ba425906C69E1Bfb22F27Cb1bCe) |
| Optimism | 10 | [0x58b819827cB18Ba425906C69E1Bfb22F27Cb1bCe](https://optimistic.etherscan.io/address/0x58b819827cB18Ba425906C69E1Bfb22F27Cb1bCe) |
| Polygon | 137 | [0x58b819827cB18Ba425906C69E1Bfb22F27Cb1bCe](https://polygonscan.com/address/0x58b819827cB18Ba425906C69E1Bfb22F27Cb1bCe) |
| Base | 8453 | [0x58b819827cB18Ba425906C69E1Bfb22F27Cb1bCe](https://basescan.org/address/0x58b819827cB18Ba425906C69E1Bfb22F27Cb1bCe) |
| Base Sepolia | 84532 | [0x58b819827cB18Ba425906C69E1Bfb22F27Cb1bCe](https://sepolia.basescan.org/address/0x58b819827cB18Ba425906C69E1Bfb22F27Cb1bCe) |
| Arbitrum One | 42161 | [0x58b819827cB18Ba425906C69E1Bfb22F27Cb1bCe](https://arbiscan.io/address/0x58b819827cB18Ba425906C69E1Bfb22F27Cb1bCe) |
| Arbitrum Sepolia | 421614 | [0x58b819827cB18Ba425906C69E1Bfb22F27Cb1bCe](https://sepolia.arbiscan.io/address/0x58b819827cB18Ba425906C69E1Bfb22F27Cb1bCe) |

## Usage

### Installation

#### Foundry

```bash
forge install fomoweth/proxy-forge
```

#### Clone

```bash
git clone https://github.com/fomoweth/proxy-forge.git
```

### Build

```bash
forge build --sizes
```

### Test

```bash
# Run all tests
forge test

# Run with detailed logs
forge test -vvv

# Run with gas reporting
forge test --gas-report

# Run specific test
forge test --match-path test/ProxyForge.fuzz.t.sol
```

### Deploy

// Deploy via CREATE and initialize in one tx
address proxy = proxyForge.deployAndCall(implementation, owner, data);
#### To Deploy Contract

// Deploy deterministically via CREATE2 without initialization
address proxy = proxyForge.deployDeterministic(implementation, owner, salt);
```bash
forge script \
script/Deploy.s.sol:Deploy \
-vvv \
--slow \
--multi \
--broadcast
```

#### To Verify Contract

// Deploy deterministically via CREATE2 and initialize in one tx
address proxy = proxyForge.deployDeterministicAndCall(implementation, owner, salt, data);
```bash
forge verify-contract <CONTRACT_ADDRESS> \
src/ProxyForge.sol:ProxyForge \
--compiler-version v0.8.30+commit.73712a01 \
--verifier etherscan \
--etherscan-api-key <ETHERSCAN_API_KEY> \
--chain-id <CHAIN_ID>
```

// Upgrade existing proxy
proxyForge.upgrade(proxy, implementation);
### Basic Usage

// Upgrade existing proxy with initialization
proxyForge.upgradeAndCall(proxy, implementation, data);
```solidity
import {IProxyForge} from "lib/proxy-forge/interfaces/IProxyForge.sol";

contract MyContract {
IProxyForge public constant PROXY_FORGE = IProxyForge(0x58b819827cB18Ba425906C69E1Bfb22F27Cb1bCe);

function deployProxy(address implementation) external returns (address proxy) {
// Deploy a new proxy with msg.sender as owner
return PROXY_FORGE.deploy(implementation, msg.sender);
}

function deployProxy(address implementation, uint96 identifier) external returns (address proxy) {
// Create a deterministic salt (first 20 bytes must be caller or zero address)
bytes32 salt = bytes32((uint256(uint160(msg.sender)) << 96) | uint256(identifier));
// Deploy with CREATE2 for deterministic address
return PROXY_FORGE.deployDeterministic(implementation, msg.sender, salt);
}

function deployProxy(address implementation, bytes memory data) external returns (address proxy) {
// Encode initialization call data
bytes memory initData = abi.encodeWithSignature("initialize(bytes)", data);
// Deploy and initialize in one transaction
return PROXY_FORGE.deployAndCall(implementation, msg.sender, initData);
}
}
```

### Deployment Functions
## API Reference

### Core Functions

#### Deployment Functions

```solidity
function deploy(address implementation, address owner) external payable returns (address proxy);
Expand All @@ -64,87 +180,52 @@ function deployDeterministic(address implementation, address owner, bytes32 salt
function deployDeterministicAndCall(address implementation, address owner, bytes32 salt, bytes calldata data) external payable returns (address proxy);
```

### Management Functions
#### Management Functions

```solidity
function upgrade(address proxy, address implementation) external payable;
function upgradeAndCall(address proxy, address implementation, bytes calldata data) external payable;
function setProxyOwner(address proxy, address owner) external payable;
function revoke(address proxy) external payable;
function changeOwner(address proxy, address owner) external payable;
```

### View Functions
#### View Functions

```solidity
function getProxyOwner(address proxy) external view returns (address owner);
function getProxyAdmin(address proxy) external view returns (address admin);
function getProxyImplementation(address proxy) external view returns (address implementation);

function computeProxyAddress(address implementation, bytes32 salt, bytes calldata data) external view returns (address proxy);
function adminOf(address proxy) external view returns (address admin);
function implementationOf(address proxy) external view returns (address implementation);
function ownerOf(address proxy) external view returns (address owner);
function computeProxyAddress(uint256 nonce) external view returns (address proxy);
function computeProxyAdminAddress(address proxy) external view returns (address admin);
function computeProxyAddress(address implementation, bytes32 salt, bytes calldata data) external view returns (address proxy);
```

### Events

```solidity
event ProxyDeployed(address indexed proxy, address indexed owner, bytes32 indexed salt);
event ProxyUpgraded(address indexed proxy, address indexed implementation);
event ProxyAdminChanged(address indexed proxy, address indexed admin);
event ProxyImplementationChanged(address indexed proxy, address indexed implementation);
event ProxyOwnerChanged(address indexed proxy, address indexed owner);
event ProxyRevoked(address indexed proxy);
```

---

## Testing

This project includes a Foundry-based test suite that verifies:

- Deployment paths (`CREATE`, `CREATE2`)
- Admin upgrade controls
- Proxy delegatecall correctness
- Storage slot consistency
- Revert conditions and unauthorized access

Run tests with:

```bash
# Run all tests
forge test

# Run with detailed logs
forge test -vvv
### Errors

# Run with gas reporting
forge test --gas-report

# Run specific test
forge test --match-path test/ProxyForge.fuzz.t.sol
```solidity
error InvalidProxy();
error InvalidProxyImplementation();
error InvalidProxyOwner();
error InvalidSalt();
error UnauthorizedAccount(address account);
error UpgradeFailed();
```

---

## Deployment

**ForgeProxy** is deployed on the following chains:

| Network | Chain ID | Address |
| ---------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
| Sepolia | 11155111 | [0x5bbbb378546a9b1dB3d6a2FaCa37E3B93dBB03b9](https://sepolia.etherscan.io/address/0x5bbbb378546a9b1dB3d6a2FaCa37E3B93dBB03b9) |
| Arbitrum Sepolia | 421614 | [0x5bbbb378546a9b1dB3d6a2FaCa37E3B93dBB03b9](https://sepolia.arbiscan.io/address/0x5bbbb378546a9b1dB3d6a2FaCa37E3B93dBB03b9) |
| Base Sepolia | 84532 | [0x5bbbb378546a9b1dB3d6a2FaCa37E3B93dBB03b9](https://sepolia.basescan.org/address/0x5bbbb378546a9b1dB3d6a2FaCa37E3B93dBB03b9) |

---

## Acknowledgements

Inspired by:
The following repositories served as key references during the development of this project:

- [OpenZeppelin TransparentUpgradeableProxy](https://github.com/OpenZeppelin/openzeppelin-contracts)
- [OpenZeppelin](https://github.com/OpenZeppelin/openzeppelin-contracts)
- [Solady](https://github.com/Vectorized/solady)

---

## Author

- [@fomoweth](https://github.com/fomoweth)
- [fomoweth](https://github.com/fomoweth)
Loading