UUPS 代理合约:深入理解与实现

news/2025/3/10 18:51:01/文章来源:https://www.cnblogs.com/zhanchenjin/p/18763371

在可升级智能合约的设计中,UUPS(Universal Upgradeable Proxy Standard) 是一种高效且安全的升级模式。与 透明代理(Transparent Proxy) 方案相比,UUPS 代理合约更加轻量级,减少了额外的存储消耗,同时逻辑合约本身控制升级权限,增强了安全性。本文将深入探讨 UUPS 代理合约的核心机制,并结合具体实现来分析其工作原理。


1. UUPS 代理的核心思想

UUPS 代理的核心思想是:
代理合约本身不存储业务逻辑,而是通过 delegatecall 调用逻辑合约
代理合约存储逻辑合约地址implementation),并且在升级时修改这个地址,让 delegatecall 执行新合约的代码。
存储数据保持不变,因为存储始终在代理合约中,而不是逻辑合约中。

代理合约的结构

在 UUPS 代理模式下,合约分为两个部分:

  1. 代理合约(Proxy):存储 implementation 地址,并将调用转发到逻辑合约。
  2. 逻辑合约(Logic):包含具体的业务逻辑,同时提供 upgradeTo 方法用于升级合约。

2. 代理合约的 implementation 存储槽

UUPS 代理采用 EIP-1967 标准 来存储 implementation 地址,这样可以避免存储冲突,确保升级兼容性。

存储 implementation 地址

bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

📌 关键点

  • 这个存储槽是固定的,所有基于 ERC1967 的代理合约都会用它存 implementation 地址。
  • 升级的本质就是修改这个槽的值,让 delegatecall 调用新合约的代码。

3. UUPS 代理的升级机制

UUPS 代理的升级机制是由逻辑合约本身控制的,它提供 upgradeTo 方法来修改 implementation 地址。

升级 implementation 地址

function _upgradeTo(address newImplementation) internal {require(newImplementation != address(0), "Invalid address");StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;emit Upgraded(newImplementation);
}

📌 执行流程

  1. 检查 newImplementation 地址是否合法
  2. 修改 _IMPLEMENTATION_SLOT,让 delegatecall 目标变成新逻辑合约。
  3. 触发 Upgraded 事件,通知成功升级。

4. delegatecall 如何执行逻辑合约?

升级后,代理合约仍然存在,但调用的代码已经切换到新的逻辑合约。

执行前

 
Proxy → delegatecall → LogicV1(旧逻辑合约)

执行 upgradeTo(newImplementation)

 
Proxy: _setImplementation(newImplementation)

执行后

Proxy → delegatecall → LogicV2(新逻辑合约)
 

📌 重要细节

  • 代理合约的存储不变,因为所有数据存储在代理合约中,而逻辑合约只是代码执行者。
  • 代理 delegatecall 执行新合约的代码,但 msg.sender 仍然是调用者,而不是代理合约。

5. UUPS 代理合约的完整实现

代理合约

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol";contract UUPSProxy is ERC1967Upgrade {constructor(address _logic) {require(_logic != address(0), "Invalid logic address");_upgradeTo(_logic);}fallback() external payable {_delegate(_getImplementation());}function _delegate(address implementation) internal {assembly {calldatacopy(0, 0, calldatasize())let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)returndatacopy(0, 0, returndatasize())switch resultcase 0 { revert(0, returndatasize()) }default { return(0, returndatasize()) }}}
}


📌 关键点

  • constructor(address _logic):在部署时初始化逻辑合约地址。
  • fallback():将所有调用代理到 implementation
  • _delegate(address implementation):使用 delegatecall 调用逻辑合约。

逻辑合约

 
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";contract LogicV1 is UUPSUpgradeable, Ownable {uint256 public value;function setValue(uint256 _value) public {value = _value;}function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}
}

📌 关键点

  • 继承 UUPSUpgradeable,确保支持 UUPS 升级。
  • _authorizeUpgrade 限制只有 owner 可以升级合约。

6. UUPS 代理的安全性

只能通过逻辑合约升级,防止意外升级。
存储不变,业务逻辑可升级,降低合约管理成本。
轻量级,相比 Transparent Proxy 更省 Gas


7. 结论

UUPS 代理模式通过 修改 implementation 存储槽 来升级逻辑合约,实现轻量级可升级合约。
相较于透明代理(Transparent Proxy),UUPS 更节省 Gas升级权限更可控,是当前主流的可升级方案之一。

🚀 UUPS 代理的关键点

  1. 代理合约的 _IMPLEMENTATION_SLOT 决定了逻辑合约的地址。
  2. 升级时仅修改 _IMPLEMENTATION_SLOTdelegatecall 自动转发到新逻辑合约。
  3. 代理存储不变,逻辑可升级,数据安全且降低成本。

如果你在开发可升级智能合约,UUPS 是一种更高效的选择 🎯!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/896917.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Java开发】Tools4AI:一个适用于企业Java应用的开源智能体框架

一、简介 GitHub主页:(https://github.com/vishalmysore/Tools4AI) Tools4AI 是一个基于 Java 的开源智能体框架,它为企业Java应用程序提供了一种集成人工智能的独特方法。作为一个大型动作模型(Large Action Model,LAM)智能体,Tools4AI 能够根据自然语言指令自主执行任务…

英语328个词缀和词根汇总(14张图)

在所有的单词记忆法中,构词法是最科学、记忆效果最佳的词汇记忆法。下面整理了高中常用的词根、词缀。利用有限的词根、词缀对英语单词进行构词分析和解形释义,单词变得好认又好记,词义也一目了然。通过构词法记单词,可以举一反三,记一识十,从而达到事半功倍的记忆效果。…

No.48 ES6---数组扩展之扩展运算符和新增方法

一、数组扩展之扩展运算符 1.扩展运算符扩展运算符(spread)是三个点(…)。将一个数组转为用逗号分隔的参数序列。<script>var arr = [10,23,45,6,7];//以前获取数组中的每个元素for(let i = 0;i<arr.length;i++){console.log(arr[i]);}//有了扩展运算符之后console.lo…

Zabbix 7.0 LTS 部署

Zabbix 7.0LTS教程 一、环境介绍 操作系统:Rocky Linux 9.5 软件版本:7.0LTS 二、安装教程 官网:Zabbix:企业级开源监控解决方案 点击右上角的下载ZABBIX选择对应的环境:选择之后往下拉会看到相应的部署步骤:2.1 软件源配置 按照文档提示:如果有epel.repo源码,需要先注释…

IDC机房无人值守:智能运维一体化解决方案

“智和网管平台”,通过实时监控、远程配置等技术实现数据中心机房的自动检测、自动报警、自动修复等功能,从而达到无需人工干预的机房运维状态,减少人为因素对设备运行的干扰,增强机房设备、设施数据的直观可视性、提高其利用率。 企业数字化转型以及5G、物联网、云…

rust学习二十.1、不安全代码之原始指针(裸指针)

一、前言 指针在前面的篇幅中已经介绍过许多,但主要是智能指针。 智能指针管理堆上的数据,并且受到rust的所有权和借用规则管理(注意,这里的所有权和借用有时候不同于最原始的那种)。 智能指针好歹能管着这些数据,但是rust中存在一些不能使用所有权管理的数据,它们需要利…

环境变量Path学习

什么是Path环境变量? “环境变量”和“path环境变量”其实是两个东西,不要混为一谈。 “环境变量”是操作系统工作环境设置的一些选项或属性参数。每个环境变量由变量名和文件路径组成的,可以设置很多个环境变量。 我们一般使用环境变量指定一个文件夹的位置,或一个应用程序…

rust学习二十.1、原始指针(裸指针)

一、前言 指针在前面的篇幅中已经介绍过许多,但主要是智能指针。 智能指针管理堆上的数据,并且受到rust的所有权和借用规则管理(注意,这里的所有权和借用有时候不同于最原始的那种)。 智能指针好歹能管着这些数据,但是rust中存在一些不能使用所有权管理的数据,它们需要利…

深度测评国产 AI 程序员,在 QwQ 和满血版 DeepSeek 助力下,哪些能力让你眼前一亮?

通义灵码上新模型选择功能,不仅引入了 DeepSeek 满血版 V3 和 R1 这两大 “新星”,Qwen2.5-Max 和 QWQ 也强势登场,正式加入通义灵码的 “豪华阵容”。开发者只需在通义灵码智能问答窗口的输入框中,单击模型选择的下拉菜单,便能轻松开启不同模型,畅享个性化服务。通义灵码…

AI Station使用笔记

一、安装maui (1)在104上,终端操作(必须有sudo权限):sudo apt install cifs-utilspip install maui==0.0.32 -i http://10.9.54.102:8888/simple --trusted-host 10.9.54.102 maui login (fang.wang03,密码为开机密码) maui project init RC_Collaboratives (前…

mysql索引浅谈

一. 索引: 索引是数据库中重要的数据结构,主要作用是提高查询的效率。索引相当于书本的目录,即可以快速定位所需数据的位置,而不用逐页查找。 二. 索引底层结构:索引底层主要采用B+树来实现索引的管理。B+树内部分为叶子节点和非叶子节点;非叶子节点主要用来存储索引和指…