Explorando el Patrón de Proxy Universal Actualizable (UUPS)

El patrón UUPS (Universal Upgradeable Proxy Standard) es una estrategia empleada en Ethereum para dotar de capacidad de actualización a los contratos inteligentes. Este enfoque se basa en la segregación de las responsabilidades entre un contrato proxy y uno o varios contratos de lógica.

Una ventaja distintiva del patrón UUPS radica en que las funciones de actualización residen dentro del contrato de lógica. Esto mitiga el riesgo de colisiones potenciales entre los selectores de función de la operación de actualización y las funcionse definidas en el contrato proxy.

Conceptos Clave del Patrón UUPS

  • Contrato Proxy: Su función principal es recibir y redirigir todas las invocaciones de transacciones hacia el contrtao de lógica correspondiente.
  • Contrato de Lógica: Alberga la implementación del código de negocio. Puede ser reemplazado por nuevas versiones de contratos de lógica para efetcuar las actualizaciones.
  • Función de Actualización: Cada contrato de lógica incluye una función específica diseñada para gestionar el proceso de actualización.

Ejemplo Práctico

Contrato Proxy


pragma solidity ^0.8.0;

contract UUPSProxy {
   address public implementation; // Dirección del contrato de lógica
   address public admin;          // Dirección del administrador
   string public dataStorage;     // Almacenamiento de datos, modificable vía lógica

   constructor(address _initialImplementation) {
       admin = msg.sender;
       implementation = _initialImplementation;
   }

   // Función fallback para delegar llamadas al contrato de lógica
   receive() external payable {
       _callImplementation();
   }

   fallback() external payable {
       _callImplementation();
   }

   function _callImplementation() private {
       (bool success, bytes memory result) = implementation.delegatecall(msg.data);
       require(success, "Delegatecall failed");
   }
}
	

Contratos de Lógica


pragma solidity ^0.8.0;

// Versión inicial del contrato de lógica UUPS
contract LogicV1 {
   address public implementation; // Debe coincidir con el proxy
   address public admin;          // Debe coincidir con el proxy
   string public dataStorage;     // Debe coincidir con el proxy

   // Función para modificar el estado y ser llamada vía proxy
   // Selector: 0x12345678 (ejemplo)
   function updateData(string memory _newData) public {
       dataStorage = _newData;
   }

   // Función de actualización. Cambia la dirección del contrato de lógica.
   // Requiere autorización del administrador. Selector: 0x87654321 (ejemplo)
   function upgradeTo(address newImplementation) external {
       require(msg.sender == admin, "Only admin can upgrade");
       implementation = newImplementation;
   }
}

// Nueva versión del contrato de lógica UUPS
contract LogicV2 {
   address public implementation; // Debe coincidir con el proxy
   address public admin;          // Debe coincidir con el proxy
   string public dataStorage;     // Debe coincidir con el proxy

   // Función para modificar el estado y ser llamada vía proxy
   // Selector: 0x12345678 (ejemplo, el mismo que V1)
   function updateData(string memory _newData) public {
       dataStorage = string(abi.encodePacked("V2 Updated: ", _newData));
   }

   // Función de actualización. Cambia la dirección del contrato de lógica.
   // Requiere autorización del administrador. Selector: 0x87654321 (ejemplo, el mismo que V1)
   function upgradeTo(address newImplementation) external {
       require(msg.sender == admin, "Only admin can upgrade");
       implementation = newImplementation;
   }
}
	

Etiquetas: smart contracts Ethereum Solidity upgradeability uups

Publicado el 6-29 21:31