概述
在部署后能够调整和改进智能合约的能力变得至关重要。随着项目的发展,可能会出现意想不到的需求、潜在的优化或不同的产品。对许多人来说,传统的部署全新合约并迁移用户的方法不仅不切实际,而且可能导致用户的沮丧和信任流失。这就是可升级合约的威力所在,它允许你在保留其地址和用户数据的同时改进代币的逻辑。在本教程中,我们将向你展示如何利用 OpenZeppelin 的经过审计的合约套件和 Foundry 的部署功能来创建一个可升级的 ERC-20 代币。
将要做的事情
巩固你对 ERC-20 代币的理解
了解可升级性如何为你的 ERC-20 代币增加更多功能
使用 QuickNode[5] 连接到区块链 (译者备注:本文原作者为 QuickNode )
使用 OpenZeppelin[6] 和Foundry[7]创建和部署可升级的 ERC-20 代币
你需要准备的东西
对以太坊和智能合约的基本理解[8]
了解 ERC-20 代币标准[9]
已安装[10] Node.js
一个 Web3 钱包
什么是 ERC-20 代币?
ERC-20 代币标准[11]是在以太坊和基于 EVM 的区块链上创建可互换代币的蓝图。ERC-20 引入了一套标准化的规则,包括了强制性的transfer、balanceOf和totalSupply等函数,确保了代币之间的一致行为。类似于面向对象编程中的接口,开发人员可以欣赏它在强制采用这些关键函数方面的作用。这种统一性已经彻底改变了代币的交互方式,使它们变得无缝和高效,现在代币可以轻松交易、在 dApps 中使用或存储在钱包中,而所有这些都是在以太坊的区块链上运行的。
什么是可升级的 ERC-20 代币?
在其核心,可升级的代币拥抱在部署后增强或修改其功能的灵活性。这是通过分层架构实现的:代理充当与用户交互的不可变智能合约,而逻辑智能合约(有时也称为实现合约)包含业务逻辑。升级是通过更改代理对较新逻辑合约的引用来实现的,确保代币余额和其他状态变量保持不变。在这种设计中,管理员角色通常管理升级过程,决定逻辑合约何时以及如何更改,从而在代币的生命周期中引入了一种治理元素。
有不同类型的可升级智能合约,让我们来介绍最常见的并进行比较。
升级方式
透明代理
透明代理模式旨在区分管理员和普通用户。它通过使用两个不同的地址来工作:一个用于管理员(可以升级合约),另一个用于普通用户(可以与合约的函数交互)。代理合约包括了区分管理员调用和普通用户调用的逻辑,防止在常规使用过程中意外执行管理功能。
UUPS 代理
UUPS(通用可升级代理标准)代理是一种更简化和更节省 gas 的方法。在这种模式中,升级功能嵌入在逻辑合约本身中。这种设计减少了对额外'管理员'合约的需求,简化了结构。但是,它也要求逻辑合约在设计时考虑到可升级性,在其中嵌入必要的升级功能。
Beacon 代理
Beacon 代理模式引入了一个中央的“信标(Beacon)”合约,所有代理实例都引用该合约以获取当前逻辑合约的地址。这种设计允许更高效的升级过程,因为在信标中更新逻辑合约地址会自动更新所有关联的代理。在需要保持多个代理合约与同一逻辑合约同步的情况下,这是特别有用的。
要了解更多关于代理的信息,请查看这个 QuickNode 指南[12]和OpenZeppelin 代理[13]。
在本指南的技术演示中,我们将介绍 UUPS 代理方法。
为什么选择 OpenZeppelin?
OpenZeppelin[14]提供了一系列可重用的智能合约,这些合约是安全的并且经过了审计,确保了你的智能合约的基本构建块是安全的。对于可升级性,OpenZeppelin 提供了代理合约,将调用委托给实现合约。这种方法允许开发人员替换实现合约,同时保留代理的存储、地址和余额。
要了解更多关于 OpenZeppelin 及其可升级性插件的信息,请查看这个资源[15] 。
项目条件:创建 RPC 端点
要将智能合约部署到区块链,你需要一个 API 端点来与网络通信。你可以使用公共节点或部署和管理自己的基础设施;但是,如果你希望获得 8 倍更快的响应时间,你可以把繁重的工作交给我们(QuickNode)。在这里[16]注册一个免费账户。
登录后,点击创建端点按钮,然后选择你要部署的区块链和网络。在本指南中,我们将选择以太坊 Sepolia链。
创建端点后,复制 HTTP 提供程序链接并保持方便,因为你将在接下来的部分中需要它。
项目先决条件:为钱包充值
如果你需要在 Sepolia 测试网上获得 ETH,Multi-Chain QuickNode Faucet[17] 可以帮助你轻松获取测试 ETH!
转到 Multi-Chain QuickNode Faucet 并连接你的钱包(例如 MetaMask、Coinbase 钱包)或粘贴你的钱包地址以获取测试 ETH。请注意,以太坊主网需要 0.001 ETH 的余额要求才能使用 EVM 水龙头。你还可以在推特上发布你的请求以获得奖励!
在下一节中,我们将转向创建项目目录并配置项目文件和依赖项。
创建可升级的 ERC-20 代币项目
现在我们对 ERC-20 代币以及以太坊上的可升级性有了很好的基本理解,让我们开始编写一个实际的示例。首先,让我们安装并初始化一个 Foundry 项目。
安装 Foundry
如果你尚未安装 Foundry,请打开你的终端并运行以下命令:
curl -L https://foundry.paradigm.xyz | bash
上面的命令将安装Foundryup。然后,根据屏幕上的指示继续操作,这将使你能够在 CLI 中使用foundryup命令。安装完成后,你可以在终端中运行foundryup -v命令来检查版本并安装最新的(夜间)预编译二进制文件。
提示
如果你使用的是 Windows,你需要安装并使用 Git BASH 或 WSL 作为你的终端,因为 Foundryup 目前不支持 Powershell 或 Cmd。请按照此处[18]的说明进行操作。
或者,如果你使用的是 M1 Mac,并且出现错误:dyld[32719]: Library not loaded: /usr/local/opt/libusb/lib/libusb-1.0.0.dylib;请尝试通过 brew 安装该库:brew install libusb。
配置完成后,使用以下命令初始化一个 Foundry 项目并进入该目录:
forge init erc20_upgradeable && cd erc20_upgradeable
然后,进入erc20_upgradeable目录,你的项目结构应如下所示:
.
├── lib
├── script
├── src
└── test
foundry.toml
你可能会在项目中看到一些现有的示例文件,但你可以忽略它们。
让我们回顾一下这个结构。
lib:存储依赖项的目录
script:部署合约或与现有智能合约交互的目录
src:智能合约的默认目录
test:运行测试的默认目录
foundry.toml:可以修改版本、优化、RPC 网络、合约验证等设置的配置文件。
我们还需要创建项目所需的文件。运行以下命令以创建智能合约文件、测试文件、部署文件和 remappings.txt(我们将使用它来正确映射我们的库依赖项)。
echo > src/MyToken.sol && echo > src/MyTokenV2.sol && echo > test/MyTokenTest.t.sol && echo > script/deployToken.s.sol && echo > script/deployProxy.s.sol && echo > remappings.txt
在下一节中,我们将安装所需的库并设置我们的配置。
配置项目
通过初始化我们的项目,让我们安装本指南中将要使用的 OpenZeppelin 库。在项目的根目录中,在你的终端中运行以下命令:
forge install OpenZeppelin/openzeppelin-contracts --no-commit
forge install OpenZeppelin/openzeppelin-foundry-upgrades --no-commit
forge install OpenZeppelin/openzeppelin-contracts-upgradeable --no-commit
注意末尾的--no-commit标志。这是因为你的项目文件夹已经与 git 存储库关联,所以我们必须指定不提交任何内容。
现在,让我们通过填写我们之前创建的remappings.txt文件来将导入配置到正确的路径。
向文件中添加以下配置:
@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/
@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/
保存文件后,让我们打开foundry.toml文件,并向你的文件添加以下代码:
build_info = true
extra_output = ["storageLayout"]
[rpc_endpoints]
sepolia = "QUICKNODE_ENDPOINT_URL"
前两行(例如,build_info和extra_output)是在使用 OpenZeppelin Foundry Upgrades library[19](感谢 ericglau!)时所需的配置。此外,由于我们在本指南中在 Sepolia 测试网上部署,我们将把这个端点命名为sepolia。如果你在其他网络上部署,可以更改名称。注意,请记住将QUICKNODE_ENDPOINT_URL占位符替换为你之前创建的实际 QuickNode HTTP 提供程序 URL。
最后,让我们在环境中设置我们的私钥,使用以下变量名和你的私钥。在你的终端中运行以下命令,并将YOUR_PRVATE_KEY占位符更新为你的实际私钥。
export PRIVATE_KEY=YOUR_PRIVATE_KEY
配置设置完成后,让我们继续创建可升级的 ERC-20 代币。
创建可升级的 ERC-20 代币智能合约
是时候为可升级的 ERC-20 代币合约构建逻辑了。在我们开始编写代码之前,让我们先了解一下我们的 ERC-20 代币将具有的确切功能。
我们将在 ERC-20 代币中继承不同的智能合约:
ERC20Upgradeable - 包含可升级功能的 ERC-20 代币
OwnableUpgradeable - 仅允许所有者执行某些功能(所有者可以被转移)
ERC20PermitUpgradeable - 添加了一个许可功能,用户可以使用它来节省离线批准的成本
Initializable - 类似于构造函数,我们将使用它来设置代币的初始参数
UUPSUpgradeable - 我们的 ERC-20 代币将继承的通用可升级代理标准模式逻辑
现在,进入你的src文件夹,并打开MyToken.sol文件。更新文件内容以包括:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "openzeppelin-contracts-upgradeable/contracts/token/ERC20/ERC20Upgradeable.sol";
import "openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol";
import "openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/ERC20PermitUpgradeable.sol";
import "openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol";
import "openzeppelin-contracts-upgradeable/contracts/proxy/utils/UUPSUpgradeable.sol";
contract MyToken is Initializable, ERC20Upgradeable, OwnableUpgradeable, ERC20PermitUpgradeable, UUPSUpgradeable {
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
function initialize(address initialOwner) initializer public {
__ERC20_init("MyToken", "MTK");
__Ownable_init(initialOwner);
__ERC20Permit_init("MyToken");
__UUPSUpgradeable_init();
_mint(msg.sender, 1000000 * 10 ** decimals());
}
function mint(address to, uint256 amount) public onlyOwner {
_mint(to, amount);
}
function _authorizeUpgrade(address newImplementation)
internal
onlyOwner
override
{}
}
为了下次轻松部署,请查看Remix.IDE[20]
记得保存文件。让我们回顾一下代码。
如上所述,在我们的 ERC-20 代币中继承了不同的智能合约。然后,在合约的constructor中,我们通过调用_disableInitializers()确保初始化方法只运行一次,以防止意外重新初始化。中间的initialize函数设置了代币的名称为"MyToken"和符号为"MTK",将所有权分配给提供的initialOwner,并激活了增强的授权机制和可升级功能。还向调用此函数的用户铸造了初始代币供应。此外,合约提供了一个仅限所有者的mint函数,允许创建新代币。通过内部的_authorizeUpgrade方法,确保了安全的合约升级,只允许所有者授权新的合约版本。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "openzeppelin-contracts-upgradeable/contracts/token/ERC20/ERC20Upgradeable.sol";
import "openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol";
import "openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/ERC20PermitUpgradeable.sol";
import "openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol";
import "openzeppelin-contracts-upgradeable/contracts/proxy/utils/UUPSUpgradeable.sol";
/// @custom:oz-upgrades-from MyToken
contract MyTokenV2 is Initializable, ERC20Upgradeable, OwnableUpgradeable, ERC20PermitUpgradeable, UUPSUpgradeable {
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
function initialize(address initialOwner) initializer public {
__ERC20_init("MyTokenV2", "MTKV2");
__Ownable_init(initialOwner);
__ERC20Permit_init("MyTokenV2");
__UUPSUpgradeable_init();
_mint(msg.sender, 1000000 * 10 ** decimals());
}
function mint(address to, uint256 amount) public onlyOwner {
_mint(to, amount);
}
function _authorizeUpgrade(address newImplementation)
internal
onlyOwner
override
{}
}
总的来说,上面的 ERC-20 智能合约与MyToken.sol非常相似,但存在差异,例如不同的合约名称、符号,并包含升级我们的合约所需的 Foundry/OpenZepplin 注释(例如,/// @custom:oz-upgrades-from MyToken)。
现在,让我们进行编译和测试。
编译和测试可升级的 ERC-20 代币
有了我们编写的智能合约,让我们尝试编译合约并测试可升级的 ERC-20 代币逻辑的行为。
我们将测试以下功能:
检查我们合约的铸造功能(请注意,这仅限于Owner)
测试并验证我们的 ERC-20 代币的可升级性
现在,转到test文件夹并打开MyTokenTest.t.sol文件。正如你可能已经猜到的那样,Foundry 中的测试是用 Solidity 编写的。更新文件的内容以包含以下内容:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "forge-std/Test.sol";
import "../src/MyToken.sol";
import "forge-std/console.sol";
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol";
import { Upgrades } from "openzeppelin-foundry-upgrades/Upgrades.sol";
contract MyTokenTest is Test {
MyToken myToken;
ERC1967Proxy proxy;
address owner;
address newOwner;
// Set up the test environment before running tests
function setUp() public {
// 部署实现
MyToken implementation = new MyToken();
// Define the owner address
owner = vm.addr(1);
// Deploy the proxy and initialize the contract through the proxy
proxy = new ERC1967Proxy(address(implementation), abi.encodeCall(implementation.initialize, owner));
// 用代理关联 MyToken 接口
myToken = MyToken(address(proxy));
// Define a new owner address for upgrade tests
newOwner = address(1);
// Emit the owner address for debugging purposes
emit log_address(owner);
}
// Test the basic ERC20 functionality of the MyToken contract
function testERC20Functionality() public {
// Impersonate the owner to call mint function
vm.prank(owner);
// Mint tokens to address(2) and assert the balance
myToken.mint(address(2), 1000);
assertEq(myToken.balanceOf(address(2)), 1000);
}
// 测试升级
function testUpgradeability() public {
// Upgrade the proxy to a new version; MyTokenV2
Upgrades.upgradeProxy(address(proxy), "MyTokenV2.sol:MyTokenV2", "", owner);
}
}
测试代码相当长,但我们已添加了注释,以便你更好地理解每个测试用例的发生情况。
现在,要编译我们的合约并执行测试,请在终端中运行以下命令:
forge build && forge test --ffi
包括--ffi标志是为了运行我们的代码需要访问的外部脚本。
你可能会收到一些警告,例如“源文件未指定所需的编译器版本!”但这可以忽略。
你将看到类似以下的输出:
[⠢] Compiling...
[⠃] Compiling 62 files with 0.8.22
[⠰] Solc 0.8.22 finished in 3.79s
Compiler run successful with warnings:
Warning (3420): Source file does not specify required compiler version! Consider adding "pragma solidity ^0.8.22;"
--> script/deployProxy.s.sol
Warning (3420): Source file does not specify required compiler version! Consider adding "pragma solidity ^0.8.22;"
--> script/deployToken.s.sol
[⠢] Compiling...
No files changed, compilation skipped
Running 2 tests for test/MyTokenTest.t.sol:MyTokenTest
[PASS] testERC20Functionality() (gas: 48673)
[PASS] testUpgradeability() (gas: 1642043)
Test result: ok. 2 passed; 0 failed; 0 skipped; finished in 2.43s
Running 2 tests for test/Counter.t.sol:CounterTest
[PASS] testFuzz_SetNumber(uint256) (runs: 256, μ: 27709, ~: 28409)
[PASS] test_Increment() (gas: 28379)
Test result: ok. 2 passed; 0 failed; 0 skipped; finished in 2.43s
Ran 2 test suites: 4 tests passed, 0 failed, 0 skipped (4 total tests)
注意:如果你在测试中遇到错误,你可能需要运行命令 - forge clean && forge build && forge test --ffi 以删除构建工件和缓存目录,然后重新编译并运行测试。
此外,你将注意到两个新目录;out目录包含合约工件,例如 ABI,而cache文件夹被 forge 用于重新编译必要的内容。
唯一剩下的就是部署可升级的 ERC-20 代币。让我们开始吧!
部署可升级的 ERC-20 代币
Foundry 通过使用forge create命令使通过 CLI 轻松部署智能合约;但是,你也可以使用脚本进行部署。请注意,Foundry 一次只能部署一个合约,但这对我们目前来说并不构成障碍。
要部署 ERC-20 代币,让我们使用一个脚本。打开我们之前创建的scripts/deployToken.s.sol文件,并更新文件以使用以下代码:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "../src/MyToken.sol";
import "forge-std/Script.sol";
contract DeployTokenImplementation is Script {
function run() public {
// Use address provided in config to broadcast transactions
vm.startBroadcast();
// Deploy the ERC-20 token
MyToken implementation = new MyToken();
// Stop broadcasting calls from our address
vm.stopBroadcast();
// Log the token address
console.log("Token Implementation Address:", address(implementation));
}
}
记得保存文件!剩下的就是执行脚本。
forge script script/DeployToken.s.sol --rpc-url sepolia --private-key $PRIVATE_KEY --broadcast
上述命令使用我们在foundry.toml文件中配置的sepolia RPC URL 执行脚本。--private-key标志设置我们用于交易的账户,--broadcast命令用于将它们广播到网络中。
提示
如果你想要验证你的合约在 Etherscan 上,以便让你和其他人能够从区块浏览器读取和写入你的智能合约,你将需要在上述命令的末尾添加--etherscan-api-key YOUR_ETHERSCAN_API_KEY --verify标志。在本指南的结尾,我们将演示如何从代理中读取,因此如果你想执行该步骤,这将是必需的。
成功后,你将看到如下输出:
== Logs ==
Token Implementation Address: 0x195136BA4F105dAe042F96a59E4dbeF9DCAdE773
...
...
✅ [Success]Hash: 0xe097b9397cd7d36bcf8dc379c95b511746b8d6802e4794e4b0b1125e36bf75bf
Contract Address: 0x5FbDB2315678afecb367f032d93F642f64180aa3
Block: 1
Paid: 0.00673602 ETH (1684005 gas * 4 gwei)
接下来,让我们部署代理合约。
打开scripts/deployProxy.s.sol文件并输入以下代码:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "../src/MyToken.sol";
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import "forge-std/Script.sol";
contract DeployUUPSProxy is Script {
function run() public {
address _implementation = YOUR_DEPLOYED_SMART_CONTRACT_ADDRESS; // Replace with your token address
vm.startBroadcast();
// Encode the initializer function call
bytes memory data = abi.encodeWithSelector(
MyToken(_implementation).initialize.selector,
msg.sender // Initial owner/admin of the contract
);
// Deploy the proxy contract with the implementation address and initializer
ERC1967Proxy proxy = new ERC1967Proxy(_implementation, data);
vm.stopBroadcast();
// Log the proxy address
console.log("UUPS Proxy Address:", address(proxy));
}
}
重要提示:现在,在运行下一个命令之前,你需要使用你从上一步骤部署的智能合约地址(例如,代币地址)更新_implementation变量。记得保存文件。
然后,要部署代理,请运行以下命令:
forge script script/deployProxy.s.sol:DeployUUPSProxy --rpc-url sepolia --private-key $PRIVATE_KEY --broadcast
请记住,可选地,你还可以在上述命令的末尾添加--etherscan-api-key YOUR_ETHERSCAN_API_KEY --verify标志以验证你的合约。如果你想要在接下来的步骤中与你的智能合约交互,这将是必需的。
花点时间通过查看 Etherscan 来验证你的智能合约是否已部署。你可以通过 Etherscan 验证合约是否是代理,方法是导航到Code选项卡,单击More Options下拉菜单,然后选择Is this a proxy?。你将被提示验证地址(单击继续),然后导航回 Code 选项卡,你应该会看到两个新选项卡,Read as Proxy和Write as Proxy。如果需要,你可以通过 Etherscan 在这些选项卡上与你的 ERC-20 代币合约进行交互。
例如,让我们使用Read as Proxy选项卡查看地址的 ERC-20 代币余额:
在上面的图像中,我们正在检查所有者的余额,因为我们在部署时向其铸造了代币。
你现在可以采取的下一步是与你的智能合约进行交互。由于我们在测试部分已经涵盖了交互,所以我们将暂时跳过这部分。
使用 QuickNode 的 Token API 获取代币数据
在结束本教程之前,让我们看看如何可以使用 QuickNode 的 Token API[21] 轻松获取 ERC-20 代币元数据和交易。
要使用 Token API,你可以使用 QuickNode SDK[22] 或在你喜欢的 web3 SDK(如 ethers.js 和 Eth.go)中实现它(在此处查看文档[23] )。
以下是一个快速示例,演示如何使用 cURL 获取你的 ERC-20 代币的元数据:
curl QUICKNODE_ENDPOINT_URL \
-X POST \
-H "Content-Type: application/json" \
--data '{
"id":67,
"jsonrpc":"2.0",
"method":"qn_getTokenMetadataByContractAddress",
"params": [{
"contract": "YOUR_TOKEN_ADDRESS"
}]
}'
只需将代码粘贴到你的终端,并记得用你的实际 HTTP 提供程序 URL 和代币地址替换QUICKNODE_ENDPOINT_URL和YOUR_TOKEN_ADDRESS。
通过在我们的 ERC-20 代币上调用qn_getTokenMetadataByContractAddress RPC 方法,我们可以返回诸如其元数据和交易信息(例如创建代币的创世块)之类的代币详细信息。
示例响应:
{
"jsonrpc": "2.0",
"id": 67,
"result": {
"name": "MyToken",
"symbol": "MTK",
"contractAddress": "0xc731bc16e15e97687130f4c9a7232781ea060040",
"decimals": "18",
"genesisBlock": "4701990",
"genesisTransaction": "0xa8c93e0c5108f73a039e1537b02f94e871398b6b3fe3f4efafc97c8782965b8a"
}
}
QuickNode 还提供 NFT API[24],允许你检索聚合的 NFT 数据,例如集合详细信息、转移历史、元数据等。这两个 API 都受 QuickNode 的 Graph API[25] 支持,该 API 允许你查询相同的数据,但以灵活的响应形式,并支持其他聚合数据,例如历史交易数据(例如 OHLC)和频繁更改的数据的实时订阅。
结语
给自己一个鼓励吧!你已经完成了这篇关于创建和部署可升级 ERC-20 代币的技术指南。在这个过程中,你回顾了可升级智能合约的概念以及它们的不同类型,然后设置了一个智能合约环境来创建、测试和部署你的可升级 ERC-20 代币。
本翻译由 DeCert.me[26] 协助支持, 在 DeCert 构建可信履历,为自己码一个未来。
参考资料
[1]
Deploy an Upgradeable ERC20 Token: https://www.quicknode.com/guides/ethereum-development/smart-contracts/how-to-create-and-deploy-an-upgradeable-erc20-token#create-the-erc-20-upgradeable-token-smart-contract
[2]
登链翻译计划: https://github.com/lbc-team/Pioneer
[3]
翻译小组: https://learnblockchain.cn/people/412
[4]
Tiny 熊: https://learnblockchain.cn/people/15
[5]
QuickNode: https://www.quicknode.com/signup?utm_source=internal&utm_campaign=guides&utm_content=how-to-create-and-deploy-an-upgradeable-erc20-token
[6]
OpenZeppelin: https://www.openzeppelin.com/
[7]
Foundry: https://book.getfoundry.sh/getting-started/installation
[8]
对以太坊和智能合约的基本理解: https://decert.me/tutorials
[9]
了解 ERC-20 代币标准: https://learnblockchain.cn/tags/ERC20
[10]
安装: https://nodejs.org/en
[11]
ERC-20 代币标准: https://learnblockchain.cn/docs/eips/eip-20.html
[12]
QuickNode 指南: https://www.quicknode.com/guides/ethereum-development/smart-contracts/an-introduction-to-upgradeable-smart-contracts
[13]
OpenZeppelin 代理: https://docs.openzeppelin.com/contracts/5.x/api/proxy
[14]
OpenZeppelin: https://www.openzeppelin.com/
[15]
资源: https://docs.openzeppelin.com/upgrades-plugins/
[16]
这里: https://www.quicknode.com/signup?utm_source=internal&utm_campaign=guides&utm_content=how-to-create-and-deploy-an-upgradeable-erc20-token
[17]
Multi-Chain QuickNode Faucet: https://faucet.quicknode.com/?utm_source=internal&utm_campaign=guides
[18]
此处: https://book.getfoundry.sh/getting-started/installation
[19]
library: https://github.com/OpenZeppelin/openzeppelin-foundry-upgrades
[20]
Remix.IDE: https://remix.ethereum.org/?#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmltcG9ydCAiQG9wZW56ZXBwZWxpbi9jb250cmFjdHMtdXBncmFkZWFibGVANS4wLjAvdG9rZW4vRVJDMjAvRVJDMjBVcGdyYWRlYWJsZS5zb2wiOwppbXBvcnQgIkBvcGVuemVwcGVsaW4vY29udHJhY3RzLXVwZ3JhZGVhYmxlQDUuMC4wL2FjY2Vzcy9Pd25hYmxlVXBncmFkZWFibGUuc29sIjsKaW1wb3J0ICJAb3BlbnplcHBlbGluL2NvbnRyYWN0cy11cGdyYWRlYWJsZUA1LjAuMC9wcm94eS91dGlscy9Jbml0aWFsaXphYmxlLnNvbCI7CmltcG9ydCAiQG9wZW56ZXBwZWxpbi9jb250cmFjdHMtdXBncmFkZWFibGVANS4wLjAvcHJveHkvdXRpbHMvVVVQU1VwZ3JhZGVhYmxlLnNvbCI7Cgpjb250cmFjdCBNeVRva2VuIGlzIEluaXRpYWxpemFibGUsIEVSQzIwVXBncmFkZWFibGUsIE93bmFibGVVcGdyYWRlYWJsZSwgVVVQU1VwZ3JhZGVhYmxlIHsKICAgIC8vLyBAY3VzdG9tOm96LXVwZ3JhZGVzLXVuc2FmZS1hbGxvdyBjb25zdHJ1Y3RvcgogICAgY29uc3RydWN0b3IoKSB7CiAgICAgICAgX2Rpc2FibGVJbml0aWFsaXplcnMoKTsKICAgIH0KCiAgICBmdW5jdGlvbiBpbml0aWFsaXplKGFkZHJlc3MgaW5pdGlhbE93bmVyKSBpbml0aWFsaXplciBwdWJsaWMgewogICAgICAgIF9fRVJDMjBfaW5pdCgiTXlUb2tlbiIsICJNVEsiKTsKICAgICAgICBfX093bmFibGVfaW5pdChpbml0aWFsT3duZXIpOwogICAgICAgIF9fVVVQU1VwZ3JhZGVhYmxlX2luaXQoKTsKICAgIH0KCiAgICBmdW5jdGlvbiBtaW50KGFkZHJlc3MgdG8sIHVpbnQyNTYgYW1vdW50KSBwdWJsaWMgb25seU93bmVyIHsKICAgICAgICBfbWludCh0bywgYW1vdW50KTsKICAgIH0KCiAgICBmdW5jdGlvbiBfYXV0aG9yaXplVXBncmFkZShhZGRyZXNzIG5ld0ltcGxlbWVudGF0aW9uKQogICAgICAgIGludGVybmFsCiAgICAgICAgb25seU93bmVyCiAgICAgICAgb3ZlcnJpZGUKICAgIHt9Cn0K&deployProxy=true
[21]
QuickNode 的 Token API: https://www.quicknode.com/token-api
[22]
QuickNode SDK: https://www.quicknode.com/docs/quicknode-sdk/getting-started
[23]
文档: https://www.quicknode.com/docs/ethereum/qn_getTokenMetadataByContractAddress_v2
[24]
NFT API: https://www.quicknode.com/nft-api?utm_source=internal&utm_campaign=guides
[25]
QuickNode 的 Graph API: https://www.quicknode.com/graph-api?utm_source=internal&utm_campaign=guides
[26]
DeCert.me: https://decert.me/
声明:本网站所有相关资料如有侵权请联系站长删除,资料仅供用户学习及研究之用,不构成任何投资建议!