Skip to content

Protocol Upgradeability Overview

Introduction

Textile Protocol v2.1 uses a hybrid upgradeability approach designed to balance security, efficiency, and operational flexibility.

Upgradeability Patterns

BeaconProxy Pattern (Pools & Tranches)

All StructuredPool and Tranche instances use the BeaconProxy pattern.

How It Works

┌────────────┐     ┌────────────┐     ┌────────────┐
│   Pool 1   │────▶│            │     │            │
├────────────┤     │  Beacon    │────▶│ Pool Impl  │
│   Pool 2   │────▶│ (Pool)     │     │   V2.1.0   │
├────────────┤     │            │     │            │
│   Pool 3   │────▶│            │     └────────────┘
└────────────┘     └────────────┘
 BeaconProxies      Upgradeable        Implementation
  • Each pool/tranche: Lightweight BeaconProxy (~$5-10 to deploy)
  • Beacon: Central contract storing current implementation address
  • Upgrade: Update beacon → all instances upgraded simultaneously

Benefits

Mass Upgrades: Update all pools and tranches at once ✅ Gas Efficient: Similar cost to minimal clones ✅ No Size Limits: Avoids 24KB contract limit ✅ Timelock Protected: 2-day delay on beacon upgrades ✅ Operationally Simple: Maintain single version across all instances ✅ Consolidated Architecture: StructuredPool includes integrated credit line (no separate controller needed)

Trade-offs

⚠️ All-or-nothing: Cannot upgrade individual instances ⚠️ Coordinated rollout: All instances change simultaneously

UUPS Pattern (Infrastructure)

Infrastructure contracts (Registry, future additions) use UUPS with timelock.

How It Works

┌────────────┐
│   Users    │
└──────┬─────┘


┌────────────┐       ┌───────────────┐
│ ERC1967    │──────▶│   Registry    │
│  Proxy     │ deleg │ Implementation│
└────────────┘  call └───────────────┘
  (State)              (Logic)
  • Individual control: Each contract upgrades independently
  • Time lock: 2-day delay enforced
  • Flexible: Can add custom upgrade logic

Benefits

Independent upgrades: Don't affect other contracts ✅ Proven pattern: Well-audited OpenZeppelin standard ✅ Custom logic: Can add special requirements

Access Control

Separate Admin Roles

All upgradeable contracts use two independent roles:

PROTOCOL_ADMIN

  • Schedules upgrades
  • Executes upgrades (after timelock)
  • Cancels pending upgrades
  • Manages protocol operations

TIMELOCK_ADMIN

  • Configures upgrade delay (1 hour to 30 days)
  • Cannot schedule or execute upgrades
  • Independent governance

Two-Party Security

To rush an upgrade (reduce delay), both admins must cooperate:

  1. TIMELOCK_ADMIN reduces delay to minimum (1 hour)
  2. PROTOCOL_ADMIN schedules and executes upgrade

This prevents a single compromised admin from pushing malicious upgrades.

Multi-Sig Recommendations

For production deployments:

  • Protocol Admin: 5/9 multi-sig (execution power)
  • Timelock Admin: 3/5 multi-sig (veto power)
  • Key requirement: Different signers for each multi-sig

Upgrade Workflows

Beacon Upgrade (Pools/Tranches)

Upgrades all pool or tranche instances:

Steps:

  1. Deploy new StructuredPool implementation
  2. Schedule upgrade on beacon (PROTOCOL_ADMIN)
  3. Wait for timelock period (2 days default)
  4. Execute upgrade (PROTOCOL_ADMIN)
  5. All pools instantly use new implementation ✅

Example:

solidity
// 1. Deploy new implementation
StructuredPoolV2 newImpl = new StructuredPoolV2();

// 2. Get beacon from factory
UpgradeableBeaconWithTimelock beacon = factory.poolBeacon();

// 3. Schedule upgrade
beacon.connect(protocolAdmin).scheduleUpgrade(address(newImpl));

// 4. Wait 2 days...

// 5. Execute
beacon.connect(protocolAdmin).executeUpgrade(address(newImpl));

Cost Example (Celo Mainnet):

  • Schedule upgrade: ~1.25 CELO ($0.31)
  • Execute upgrade: ~2.5 CELO ($0.62)
  • Total: ~3.75 CELO ($0.93) to upgrade ALL instances

UUPS Upgrade (Registry)

Upgrades single infrastructure contract:

Steps:

  1. Deploy new Registry implementation
  2. Schedule upgrade on Registry (PROTOCOL_ADMIN)
  3. Wait for timelock period (2 days default)
  4. Call upgradeToAndCall() (PROTOCOL_ADMIN)
  5. Contract uses new implementation ✅

Example:

solidity
// 1. Deploy new implementation
RegistryV2 newImpl = new RegistryV2();

// 2. Schedule on Registry
registry.connect(protocolAdmin).scheduleUpgrade(address(newImpl));

// 3. Wait 2 days...

// 4. Execute
registry.connect(protocolAdmin).upgradeToAndCall(address(newImpl), "0x");

Emergency Procedures

Cancel Pending Upgrade

If vulnerability discovered in scheduled implementation:

solidity
// Cancel immediately (as PROTOCOL_ADMIN)
beacon.connect(protocolAdmin).cancelUpgrade();
// or
registry.connect(protocolAdmin).cancelUpgrade();

Rush Emergency Fix

If critical bug requires immediate fix:

  1. Timelock Admin reduces delay to 1 hour:

    solidity
    beacon.connect(timelockAdmin).setUpgradeDelay(1 hours);
  2. Protocol Admin schedules fix:

    solidity
    beacon.connect(protocolAdmin).scheduleUpgrade(emergencyFixImpl);
  3. Wait 1 hour (minimum timelock)

  4. Protocol Admin executes:

    solidity
    beacon.connect(protocolAdmin).executeUpgrade(emergencyFixImpl);
  5. Timelock Admin restores normal delay:

    solidity
    beacon.connect(timelockAdmin).setUpgradeDelay(2 days);

Monitoring

Critical Events

Monitor these events 24/7:

Beacon Events

solidity
event UpgradeScheduled(address indexed implementation, uint256 scheduledTime);
event UpgradeCancelled(address indexed implementation);
event Upgraded(address indexed implementation);
event UpgradeDelayUpdated(uint256 newDelay);

Registry Events

solidity
event UpgradeScheduled(address indexed implementation, uint256 scheduledTime);
event UpgradeCancelled(address indexed implementation);
event Upgraded(address indexed implementation);
event UpgradeDelayUpdated(uint256 newDelay);

Alerting Strategy

  1. UpgradeScheduled: Immediate review of new implementation
  2. UpgradeDelayUpdated: Verify timelock admin authorization
  3. UpgradeCancelled: Investigate cancellation reason
  4. Upgraded: Verify successful upgrade, monitor for anomalies

Gas Costs (Celo Mainnet)

Costs calculated with 25 Gwei gas price and $0.24867 CELO price

Deployment Costs

ComponentGasCost (CELO)Cost (USD)
Pool Beacon1.5M37.5 CELO$9.33
Tranche Beacon1.5M37.5 CELO$9.33
BeaconProxy (pool)200k5.0 CELO$1.24
BeaconProxy (tranche)200k5.0 CELO$1.24

Operation Costs

  • Delegate call overhead: +2k gas per call (~$0.01)
  • Negligible compared to operation costs

Upgrade Costs

OperationGasCost (CELO)Cost (USD)
Schedule beacon upgrade50k1.25 CELO$0.31
Execute beacon upgrade100k2.5 CELO$0.62
Schedule UUPS upgrade50k1.25 CELO$0.31
Execute UUPS upgrade100k2.5 CELO$0.62

Version Management

Checking Versions

solidity
// Pool/Tranche version (via beacon)
string memory poolVersion = pool.version(); // "2.1.0"
string memory trancheVersion = tranche.version(); // "2.1.0"

// Current implementations
(address poolImpl, address trancheImpl) = factory.getCurrentImplementations();

// Beacon addresses
address poolBeacon = address(factory.poolBeacon());
address trancheBeacon = address(factory.trancheBeacon());

// Registry version
string memory registryVersion = registry.version(); // "2.1.0"

Version Compatibility

  • Pool ↔ Tranche: Must use compatible versions
  • All ↔ Registry: Registry version >= all other components

Best Practices

Pre-Upgrade Checklist

✅ New implementation thoroughly audited ✅ Formal verification completed (if applicable) ✅ Storage layout compatibility verified ✅ Tested on testnet with production-like state ✅ Emergency rollback plan prepared ✅ Community notified via governance forum ✅ Monitoring dashboards ready

During Upgrade

✅ Monitor events in real-time ✅ Have emergency cancellation ready ✅ Team on standby for 24h post-upgrade ✅ Gradual feature rollout if possible

Post-Upgrade

✅ Verify all contracts upgraded correctly ✅ Monitor for anomalies (48 hours minimum) ✅ Publish post-mortem if issues occurred ✅ Update documentation

Security Considerations

Attack Vectors

  1. Compromised Protocol Admin

    • ⚠️ Risk: Medium
    • 🛡️ Mitigation: Cannot bypass timelock, multi-sig required
  2. Compromised Timelock Admin

    • ⚠️ Risk: Low
    • 🛡️ Mitigation: Cannot execute upgrades, only adjust delay
  3. Both Admins Compromised

    • 🚨 Risk: Critical
    • 🛡️ Mitigation: 1-hour minimum timelock, different multi-sig members, 24/7 monitoring
  4. Malicious Implementation

    • 🚨 Risk: Critical
    • 🛡️ Mitigation: Audits, formal verification, community review during timelock
  5. Storage Collision

    • ⚠️ Risk: Medium
    • 🛡️ Mitigation: OpenZeppelin storage gaps, automated validation tools

Defense in Depth

The protocol uses multiple security layers:

  1. Role Separation: PROTOCOL_ADMIN ≠ TIMELOCK_ADMIN
  2. Multi-sig: Multiple signers required for each role
  3. Timelock: Minimum 2-day delay for community review
  4. Monitoring: 24/7 event monitoring and alerting
  5. Audits: Professional security audits before upgrades
  6. Testnet: Full testing on testnet before mainnet

Migration Guide

From v2.0 to v2.1

Old pools (minimal clones) cannot be upgraded. Options:

  1. Keep running: Old pools remain functional
  2. Gradual migration: Deploy v2.1 pools, migrate liquidity over time
  3. Coordinated sunset: Close old pools, open new v2.1 pools

New deployments automatically use v2.1 with BeaconProxy pattern.

References