Proxy Contract
🧠 What is a Proxy Contract?
A proxy contract is a smart contract that delegates or forwards function calls and data to another contract — called the implementation contract or logic contract.
🎯 Key Purpose
- Upgradability: Blockchains are immutable. If you deploy a contract and later find a bug or need new features, you can’t change it. Proxy contracts solve this by separating storage from logic, so you can update the logic without losing your data.
- Gas optimization: You can reuse the logic contract across multiple proxies, saving space and deployment costs.
🧱 How Proxy Contracts Work
The architecture consists of two main contracts:
- Proxy Contract: Handles storage and forwards calls.
- Logic/Implementation Contract: Contains the actual functions/logic.
🔄 Flow
- User interacts with the proxy contract.
- Proxy forwards the call/data to the logic contract using a delegate-like function.
- Logic is executed in the context of the proxy, using the proxy’s storage.
Think of the proxy as a permanent house address, and the logic contract as the actual tenants that can change while the address remains the same.
🛠 Types of Proxy Patterns
| Proxy Type | Description |
|---|---|
| Transparent Proxy | Admin-only access to upgrade; users cannot call admin functions. |
| Universal/Upgradeable | Calls are delegated based on logic; storage is preserved. |
| Beacon Proxy | Uses a beacon to point to the latest logic contract for multiple proxies. |
| Minimal Proxy (EIP-1167) | Lightweight proxy that clones logic contracts for cost efficiency. |
🔐 Key Security Considerations
- Storage layout mismatch: If your new logic has a different variable order/type, it can corrupt data.
- Access control: Only an authorized admin should upgrade the logic.
- Initialization: Avoid re-initializing logic multiple times (use initializer guards).
- Reentrancy: Forwarding calls may introduce reentrancy vulnerabilities if not handled properly.
📦 Simple Proxy Contract Example (clarity)
Clarity doesn’t natively support low-level delegation like Ethereum (e.g., delegatecall), but here’s how you could simulate a simplified proxy upgrade pattern using Clarity logic:
🧩 1. Logic Contract (v1)
;; contract-name: logic-v1.clar
(define-public (get-message)
(ok "Hello from V1")
)
🧩 2. Logic Contract (v2)
;; contract-name: logic-v2.clar
(define-public (get-message)
(ok "Hello from V2")
)
🛡️ 3. Proxy Contract
;; contract-name: proxy.clar
(define-data-var logic-contract principal 'SP123...logic-v1)
(define-public (upgrade (new-contract principal))
(begin
(asserts! (is-eq tx-sender 'SP123...admin) (err u1))
(var-set logic-contract new-contract)
(ok true)
)
)
(define-public (proxy-get-message)
(contract-call? (var-get logic-contract) get-message)
)
🧪 Usage Flow
- User calls
proxy-get-message():- Delegates to
logic-v1.get-message - Returns
"Hello from V1"
- Delegates to
- Admin upgrades logic:
(upgrade 'SP123...logic-v2)
- User calls
proxy-get-message()again:- Now points to
logic-v2.get-message - Returns
"Hello from V2"
- Now points to
📝 Summary Table
| Component | Role |
|---|---|
| Proxy Contract | Stores state & forwards calls |
| Logic Contract | Contains the actual functionality |
| Upgrade Function | Allows admin to change logic |
| State Preservation | Achieved via proxy storage |
💬 Real-World Analogy
Think of a proxy contract like a universal remote control:
- The remote (proxy) always stays in your hand.
- You can change the TV (logic contract) it controls.
- Your preferences (volume, channel = storage) remain unchanged even when the TV changes.
🚀 Use Cases
- Upgradable dApps
- DAO governance changes
- Token contracts that evolve
- Security patches for critical systems