Skip to content

AEON-Project/bna_contract

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MyToken — 可升级 ERC20 合约

基于 Foundry 的 ERC20 工程,合约支持 UUPS 升级,使用 CREATE2 确保代理合约在主网与测试网部署在同一地址。

架构

用户/应用
    │
    ▼
ERC1967Proxy  ←── CREATE2 部署,地址跨链不变(这是代币的"永久地址")
    │
    │  delegatecall
    ▼
MyTokenV1 / MyTokenV2  ←── 实现合约,逻辑在这里,可被升级替换
  • 代理合约:持有所有状态(余额、授权等),地址永不变
  • 实现合约:只含逻辑,升级时部署新版本,代理切换指向即可,状态不受影响

工程结构

src/
  MyTokenV1.sol          # V1 实现:标准 ERC20 + mint + burn
  MyTokenV2.sol          # V2 实现:新增 maxSupply 总量上限(升级示例)
script/
  DeployMyToken.s.sol    # 首次部署(impl + proxy,均走 CREATE2)
  UpgradeMyToken.s.sol   # 升级(V1 → V2)
test/
  MyToken.t.sol          # 单元测试(ERC20 基础 + 升级 + CREATE2 地址预测)
.env.example             # 环境变量模板
foundry.toml             # Foundry 配置

跨链同地址原理

CREATE2 地址由以下公式确定,与"谁来部署"、"在哪条链"无关:

proxy_addr = keccak256(
    0xff
    ++ 0x4e59b44847b379578588920cA78FbF26c0B4956C  // Nick's factory,所有链相同
    ++ proxy_salt
    ++ keccak256(ERC1967Proxy_initcode + impl_addr + initialize_calldata)
)[12:]

保证地址一致需固定以下三项:

参数 说明
PROXY_SALT 代理 salt,一旦确定不要修改(脚本有默认值)
TOKEN_OWNER 每条链必须填写同一个地址
代币参数 TOKEN_NAME / TOKEN_SYMBOL / INITIAL_SUPPLY 不能变

impl salt 无需配置,脚本自动由 keccak256(MyTokenV1.creationCode) 派生。

快速开始

环境要求

curl -L https://foundry.paradigm.xyz | bash && foundryup

安装依赖

git clone <repo>
cd <repo>
forge install

运行测试

forge test -v

配置环境变量

cp .env.example .env
# 编辑 .env,填写 PRIVATE_KEY、RPC_URL、TOKEN_OWNER 等
source .env

部署

预演(不广播,仅查看预测地址)

forge script script/DeployMyToken.s.sol --rpc-url $RPC_URL

部署到测试网(Sepolia)

forge script script/DeployMyToken.s.sol \
  --rpc-url $RPC_URL \
  --private-key $PRIVATE_KEY \
  --broadcast \
  --verify \
  --etherscan-api-key $ETHERSCAN_API_KEY

部署到主网(地址与测试网完全相同)

forge script script/DeployMyToken.s.sol \
  --rpc-url $MAINNET_RPC_URL \
  --private-key $PRIVATE_KEY \
  --broadcast \
  --verify \
  --etherscan-api-key $ETHERSCAN_API_KEY

脚本内置幂等保护:如果目标地址已有代码(重复执行),直接跳过,不报错。

升级

将代理从 V1 升级到 V2。V2 新增了可选的 maxSupply 总量上限。

# 不设上限
PROXY_ADDRESS=0x... \
forge script script/UpgradeMyToken.s.sol \
  --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast

# 设置上限为 2,000,000 个代币
PROXY_ADDRESS=0x... MAX_SUPPLY=2000000 \
forge script script/UpgradeMyToken.s.sol \
  --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast

升级后可通过 version() 确认:

cast call $PROXY_ADDRESS "version()(string)" --rpc-url $RPC_URL
# 返回 "2.0.0"

合约接口

MyTokenV1

函数 权限 说明
initialize(name, symbol, supply, owner) 仅初始化一次 替代 constructor
mint(address to, uint256 amount) onlyOwner 增发
burn(uint256 amount) 任何人 销毁调用者的代币
upgradeToAndCall(address impl, bytes data) onlyOwner 升级实现合约
version() view 返回 "1.0.0"

MyTokenV2(在 V1 基础上新增)

函数 权限 说明
initializeV2(uint256 maxSupply) onlyOwner,仅调用一次 设置总量上限
mint(address to, uint256 amount) onlyOwner 增发,超过 maxSupply 时 revert
maxSupply() view 查询上限(0 表示无上限)
version() view 返回 "2.0.0"

依赖

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors