Lição: 282: Proxies Transparentes vs UUPS
Os proxies são um padrão de design poderoso no desenvolvimento de contratos inteligentes, usados principalmente para permitir a upgradeabilidade dos contratos. Dois padrões de proxy comumente utilizados no Solidity são o Proxy Transparente e o UUPS (Universal Upgradeable Proxy Standard). Compreender as nuances desses proxies é crucial para qualquer desenvolvedor de Solidity que aspire a construir contratos inteligentes adaptáveis e de fácil manutenção.
1. Padrão de Proxy Transparente
O padrão de Proxy Transparente envolve dois contratos: o proxy em si e o contrato de lógica (também conhecido como contrato de implementação). O proxy delega chamadas para o contrato de lógica, permitindo que a lógica seja atualizada enquanto mantém o mesmo endereço.
Características Principais dos Proxies Transparentes:
- O proxy contém uma referência ao contrato de lógica e é responsável por encaminhar as chamadas.
- Somente o proprietário do proxy pode atualizar o contrato de lógica.
- Utiliza uma função de fallback para lidar com chamadas recebidas.
Exemplo de Código
Aqui está uma implementação simples de um Proxy Transparente:
Contrato de Lógica (Implementação)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Logic {
uint public number;
function setNumber(uint _number) public {
number = _number;
}
}
Contrato Proxy
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Proxy {
address public logic;
address public owner;
constructor(address _logic) {
logic = _logic;
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner, "Não autorizado");
_;
}
function upgrade(address _newLogic) public onlyOwner {
logic = _newLogic;
}
fallback() external {
(bool success, ) = logic.delegatecall(msg.data);
require(success, "Falha na Delegatecall");
}
}
Usando o Proxy Transparente
- Implemente o contrato
Logic
. - Implemente o contrato
Proxy
com o endereço do contratoLogic
. - Interaja com o proxy, que delegará as chamadas ao contrato de lógica.
2. Padrão de Proxy UUPS
O padrão de Proxy UUPS é uma abordagem mais moderna que integra a lógica de atualização diretamente dentro dos contratos de implementação. Isso permite que cada contrato de lógica controle seus próprios mecanismos de atualização.
Características Principais dos Proxies UUPS:
- A funcionalidade de atualização reside no próprio contrato de lógica.
- Proxies UUPS utilizam a função
initialize
para inicialização. - O proxy é minimalista e contém apenas a lógica de encaminhamento.
Exemplo de Código
Veja como um Proxy UUPS pode ser estruturado:
Contrato de Lógica com UUPS
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract Logic is UUPSUpgradeable, Ownable {
uint public number;
function initialize(uint _number) public initializer {
number = _number;
}
function setNumber(uint _number) public {
number = _number;
}
function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}
}
Proxy UUPS
A implementação do Proxy UUPS não requer um contrato separado, pois o que é diretamente derivado dos contratos OpenZeppelin gerencia a lógica.
Usando o Proxy UUPS
- Implemente o contrato
Logic
usando uma abordagem de implantação compatível com UUPS (por exemplo,ERC1967Proxy
). - Inicialize o contrato de lógica através da função
initialize
. - Atualize a implementação chamando
_authorizeUpgrade
.
Resumo
A escolha entre proxies Transparentes e UUPS depende do caso de uso e das preferências do desenvolvedor. Proxies transparentes são diretos e tornam a posse clara, enquanto proxies UUPS oferecem mais flexibilidade e descentralização ao permitir que os contratos de implementação gerenciem suas próprias atualizações.
Ambos os métodos têm suas vantagens e desvantagens, portanto, entender os requisitos do seu projeto ajudará a escolher a melhor estratégia de atualização para seus contratos inteligentes.