1. Core Architecture1.4 UUPS Proxy Pattern (EIP-1967)

1.4. UUPS Proxy Pattern (EIP-1967)

The Fhenix-FairMarket protocol implements the Universal Upgradeable Proxy Standard (UUPS) compliant with EIP-1967 to decouple persistent user funds and state variables from the executable business logic. This architectural pattern enables seamless protocol iterations, safe adaptation to CoFHE SDK updates, and strict, time-delayed governance over contract modifications without risking fund migration or storage corruption.

By storing all auction state, escrow balances, and bidder mappings in a dedicated proxy contract while delegating execution to an upgradable logic implementation, the protocol guarantees continuity, auditability, and mathematical integrity across its lifecycle.

Core Design Principles

PrincipleTechnical Implementation
Logic/Storage SeparationFhenixFairMarketProxy.sol (EIP-1967) holds all storage variables. FhenixFairMarket.sol contains only executable bytecode, accessed via delegatecall.
Zero Fund MigrationStorage layout remains immutable during upgrades. User balances, bid histories, and NFT locks persist atomically without manual state migration scripts.
SDK Isolation via AdapterAll @cofhe/sdk and FHE library calls are routed through CofheAdapter.sol. Upgrading the adapter does not require touching the core auction logic.
Timelocked GovernanceA mandatory 48-hour Timelock enforces a review window between upgrade proposal and execution, allowing community scrutiny and emergency intervention.
Multisig Authorization_authorizeUpgrade() is restricted to a 5-of-9 multisig council (devs, auditor, AVS operator, community rep, legal/compliance).

️ Technical Implementation

1. Proxy & Logic Contract Architecture

The protocol follows OpenZeppelin’s UUPSUpgradeable standard with strict initialization guards.

// FhenixFairMarket.sol (Logic Implementation)
contract FhenixFairMarket is 
 UUPSUpgradeable, 
 OwnableUpgradeable, 
 ReentrancyGuardUpgradeable 
{
 // Storage variables are inherited via proxy layout
 mapping(address => uint256) public escrowBalances;
 mapping(uint256 => Auction) public auctions;
 
 /**
 * @notice Secure initialization function (called exactly once)
 */
 function initialize(
 address initialOwner, 
 address cofheAdapter,
 address slashingPot
 ) external initializer {
 __Ownable_init(initialOwner);
 __ReentrancyGuard_init();
 __UUPSUpgradeable_init();
 // Register core dependencies
 }
 
 /**
 * @notice Restricts upgrade capability to authorized governance
 */
 function _authorizeUpgrade(address newImplementation) internal override onlyOwner {
 // Enforced via Multisig + 48h Timelock at governance layer
 // Unauthorized calls revert immediately
 }
}

2. Deployment & Initialization Sequence

Upgrades are executed atomically using upgradeToAndCall(), ensuring state transitions and dependency updates occur in a single transaction.

// Deployment Script: 01_deploy_core_proxy.ts
const Logic = await ethers.getContractFactory("FhenixFairMarket");
const Proxy = await ethers.getContractFactory("ERC1967Proxy");
 
// 1. Deploy Logic Implementation (no init called yet)
const logicImpl = await Logic.deploy();
await logicImpl.deployed();
 
// 2. Deploy Proxy, pointing to Logic + calling initialize() in constructor
const proxy = await Proxy.deploy(
 logicImpl.address,
 Logic.interface.encodeFunctionData("initialize", [
 multisigAddress,
 cofheAdapter.address,
 slashedPot.address
])
);
await proxy.deployed();

3. Safe Upgrade Execution

All upgrades pass through the governance timelock contract, which validates the payload and enforces the delay window.

// Timelock Controller (Governance Layer)
function executeUpgrade(
 address proxy, 
 address newLogic, 
 bytes calldata initData
) external onlyTimelock {
 // 1. Verify newLogic passes static analysis (Slither/Mythril)
 // 2. Verify no storage layout collisions
 // 3. Execute atomic swap
 (bool success, ) = proxy.call(
 abi.encodeWithSignature("upgradeToAndCall(address,bytes)", newLogic, initData)
 );
 require(success, "Upgrade failed");
}

Architectural Impact & Gas Comparison

MetricTraditional Non-UpgradeableFhenix-FairMarket UUPS v2.0
Upgrade CostFull redeployment + manual state migration scripts (~500k–2M gas)Single proxy.upgradeTo() transaction (~40k gas)
DowntimeHours/days for fund migration, verification, and user re-approvalNear-zero (atomic bytecode swap, state preserved)
State IntegrityHigh risk of data loss or layout collision during migrationGuaranteed (EIP-1967 standardizes storage slots)
SDK DependencyHardcoded FHE imports break core logic on @cofhe/sdk version bumpsDecoupled via CofheAdapter; core contract remains stable

️ Security & Governance Guarantees

  1. Storage Collision Protection: EIP-1967 reserves specific storage slots for proxy administrative variables (_owner, _implementation), preventing overlap with business logic variables. Layout changes require explicit audit review.
  2. Unauthorized Upgrade Prevention: The _authorizeUpgrade modifier strictly validates caller identity. Even if the proxy admin key is compromised, the 48-hour timelock and multisig requirement prevent immediate malicious execution.
  3. Emergency Halt Compatibility: If a critical vulnerability is detected during the timelock window, the governance council can trigger EmergencyHalt before the upgrade executes, prioritizing capital recovery over logic deployment.
  4. Audit Gate Compliance (P0):
  • UUPS Proxy isolation — no logic in storage contract
  • initialize() callable only once
  • _authorizeUpgrade restricted to multisig
  • Zero selfdestruct or uncontrolled delegatecall in logic

Upgrade Lifecycle Workflow

Pre-Upgrade Verification Checklist

Before any upgradeToAndCall execution, the following must pass:

  • [] Storage layout comparison shows zero collisions (@openzeppelin/upgrades-core)
  • [] Slither & Mythril scans return zero High/Critical findings
  • [] Test coverage ≥90% for new logic + regression tests pass 100%
  • [] CofheAdapter interface compatibility verified
  • [] Governance multisig approves payload + 48h timelock initiated
  • [] Post-upgrade monitoring KPIs configured in Tenderly/Defender

Next Steps