本文详细介绍了如何在Blast区块链上创建和部署自动收益Vault智能合约,涵盖了Blast的特性、所需的工具、合约开发、部署及交互流程,适合有一定编程基础的开发者。通过该指南,读者可以了解如何利用Blast的自动收益功能来管理ETH存款和提现,同时学习到使用Hardhat框架进行智能合约开发和部署的实用技巧。
目前大多数区块链要求用户质押他们的代币或运行验证者,以便从协议中获得原生收益。Blast 是一个 Layer 2 (L2) 区块链项目,以其为存入的 ETH 和稳定币提供原生收益的创新方法而闻名。在本指南中,你将学习更多关于 Blast 的信息,并学习如何使用 Hardhat 创建、部署并与一个自动收益的金库合约进行交互。
Blast 是一个与 EVM 兼容的乐观 Rollup L2 区块链。它通过原生整合 ETH 质押和现实世界资产 (RWA) 协议的收益,使自己与众不同,为 ETH 提供 4% 的基线收益,为稳定币提供 5% 的基线收益。这样的收益整合旨在对抗通货膨胀损失,并支持在其他 L2 上不可行的新 DApps 商业模式。
让我们深入了解 Blast 的运行方式以及它为什么是开发者和投资者的首选。
自动再基准: Blast 在其 L2 平台上为 ETH、WETH(Wrapped ETH)和 USDB(Blast 的原生稳定币)具有独特的自动再基准特性。这种再基准使这些资产能够无缝受益于收益生成,适用于外部拥有账户 (EOA) 和智能合约。与不可默认产生收益的 ETH 合同不同,WETH 和 USDB 账户自动为 EOs 和智能合约生成收益。
L1 质押收益: 在以太坊上海升级后,Blast 利用来自 L1 质押的 ETH 收益(最初通过 Lido)并通过再基准 ETH 将其转移到用户 L2。
稳定币的 T-Bill 收益: 在 Blast 上桥接的稳定币转换为 USDB,后者从 MakerDAO 的 T-Bill 协议中赚取收益。这种机制允许稳定币的收益生成。
Gas收入分享: 与其他 L2 不同,Blast 与 DApp 开发者分享净Gas收入,提供额外收入来源或补贴用户的Gas费用。
你需要一个 API 端点与 Blast 区块链进行通信。为此,像 QuickNode 这样的服务提供比公共 API 端点更快、更可靠的 RPC 连接。请点击 这里 免费注册,并为 Blast Sepolia 测试网创建一个端点。
请保留 HTTP Provider URL 以便在合约部署时使用。
在本指南中,我们将使用 Blast Sepolia 测试网。因此,你需要获取一些测试 ETH。
如果你使用 QuickNode 账户登录或发送推文,你可以获得额外的 ETH。
在下一部分中,我们将开始使用 Hardhat 开发我们的自动收益金库合约。
创建一个名为 Vault 的目录并安装所需的依赖项:
mkdir Vault && cd Vault
npm init -y
npm install --save-dev hardhat
npm install dotenv @nomicfoundation/hardhat-verify
npx hardhat init
在 Hardhat 提示时选择 创建 TypeScript 项目。同时,当被问及是否安装 @nomicfoundation/hardhat-toolbox 时,请回答 是。
在项目目录中创建一个 .env
文件。
环境变量用于存储敏感数据,如密码、API 凭据以及其他不应直接写入代码的信息。
echo > .env
将你的 .env
文件修改为如下。
用你钱包的私钥以及 QuickNode Blast Sepolia 端点的 HTTP URL 替换 YOUR_PRIVATE_KEY 和 YOUR_QUICKNODE_BLAST_SEPOLIA_ENDPOINT_URL 占位符。
PRIVATE_KEY="YOUR_PRIVATE_KEY"
QUICKNODE_ENDPOINT="YOUR_QUICKNODE_BLAST_SEPOLIA_ENDPOINT_URL"
如果你不知道如何获取你的私钥,可以点击这里。
此说明是为 MetaMask 准备的。
要获取你的私钥:
接着,将你的 hardhat.config.ts
文件配置如下。任何与 Hardhat 相关的设置,如网络、账户和 Solidity 版本,都定义在此文件中。
要阅读代码的解释 (强烈推荐), 点击此处。
这段代码是为 Blast 区块链量身定制的 Hardhat 项目的配置设置。
网络配置: networks 属性定义了两个环境 - blast_sepolia 用于 Sepolia 测试网,hardhat 用于使用分叉的本地开发环境。Sepolia 配置包括 QuickNode 端点 URL 和事务的私钥,以及指定的Gas价格。 本地环境配置(hardhat)设置了使用相同 QuickNode 端点的特定块号进行分叉。
Etherscan 集成: 在 etherscan 下,虽然不需要唯一的 API 密钥,但必须有一个值。因此,将 blast_sepolia 网络的 API 密钥设置为占位符。customChains 数组包括 blast_sepolia 网络的自定义配置,指定其链 ID 及 API 和区块浏览器的 URL。特别是 customChains 中的 apiURL 指定 Hardhat 可以用来与指定网络(此处为 blast_sepolia 测试网)交互的 API 服务的端点(在这种情况下为 https://api.routescan.io)。这允许与区块链无缝交互,并通过 Hardhat 验证 Blast 测试网上的合约。
hardhat.config.ts
import { HardhatUserConfig } from 'hardhat/config'
import '@nomicfoundation/hardhat-toolbox'
import '@nomicfoundation/hardhat-verify'
require('dotenv').config()
const config: HardhatUserConfig = {
solidity: '0.8.20',
networks: {
// for Sepolia testnet
blast_sepolia: {
url: process.env.QUICKNODE_ENDPOINT as string,
accounts: [process.env.PRIVATE_KEY as string],
gasPrice: 1000000000,
},
// for local dev environment
hardhat: {
forking: {
enabled: true,
url: process.env.QUICKNODE_ENDPOINT as string,
blockNumber: 423000,
},
},
},
etherscan: {
apiKey: {
blast_sepolia: 'blast_sepolia', // 虽然不需要唯一的 API 密钥,但必须有一个值,因此只需设置占位符
},
customChains: [\
{\
network: 'blast_sepolia',\
chainId: 168587773,\
urls: {\
apiURL:\
'https://api.routescan.io/v2/network/testnet/evm/168587773/etherscan',\
browserURL: 'https://testnet.blastscan.io',\
},\
},\
],
},
}
export default config
现在我们具备基础知识,让我们开始为 Blast 区块链构建我们的自动收益金库智能合约。如果你是 Solidity 新手,请查看我们的 全面的适合新手的 Solidity 指南。
用户的 ETH 余额自动获得 ETH 收益,而智能合约有三种收益模式用于再基准。
在本指南中,我们将选择收益模式为 automatic。因此,由于收益将被自动添加,合约的 ETH 余额将自动增加。
智能合约必须与位于 0x4300000000000000000000000000000000000002
的 Blast 收益合约交互以更改其收益模式 [ source]。由于我们与 Blast 智能合约交互,因此需要将 Blast 智能合约的功能定义为一个 接口。为此,让我们在 contracts 目录下创建一个文件夹 interfaces 和一个文件 IBlast.sol。
在 Solidity 中,前缀 I 被用来标识 Solidity 文件作为 接口。所以,IBlast 文件是 Blast 合约的 接口 文件。
mkdir contracts/interfaces
echo > contracts/interfaces/IBlast.sol
打开 IBlast.sol
文件并将其修改如下。
contracts/interfaces/IBlast.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
enum YieldMode {
AUTOMATIC,
VOID,
CLAIMABLE
}
enum GasMode {
VOID,
CLAIMABLE
}
interface IBlast{
// configure
function configureContract(address contractAddress, YieldMode _yield, GasMode gasMode, address governor) external;
function configure(YieldMode _yield, GasMode gasMode, address governor) external;
// base configuration options
function configureClaimableYield() external;
function configureClaimableYieldOnBehalf(address contractAddress) external;
function configureAutomaticYield() external;
function configureAutomaticYieldOnBehalf(address contractAddress) external;
function configureVoidYield() external;
function configureVoidYieldOnBehalf(address contractAddress) external;
function configureClaimableGas() external;
function configureClaimableGasOnBehalf(address contractAddress) external;
function configureVoidGas() external;
function configureVoidGasOnBehalf(address contractAddress) external;
function configureGovernor(address _governor) external;
function configureGovernorOnBehalf(address _newGovernor, address contractAddress) external;
// claim yield
function claimYield(address contractAddress, address recipientOfYield, uint256 amount) external returns (uint256);
function claimAllYield(address contractAddress, address recipientOfYield) external returns (uint256);
// claim gas
function claimAllGas(address contractAddress, address recipientOfGas) external returns (uint256);
function claimGasAtMinClaimRate(address contractAddress, address recipientOfGas, uint256 minClaimRateBips) external returns (uint256);
function claimMaxGas(address contractAddress, address recipientOfGas) external returns (uint256);
function claimGas(address contractAddress, address recipientOfGas, uint256 gasToClaim, uint256 gasSecondsToConsume) external returns (uint256);
// read functions
function readClaimableYield(address contractAddress) external view returns (uint256);
function readYieldConfiguration(address contractAddress) external view returns (uint8);
function readGasParams(address contractAddress) external view returns (uint256 etherSeconds, uint256 etherBalance, uint256 lastUpdated, GasMode);
}
在 contracts 文件夹中创建一个名为 Vault.sol
的文件:
echo > contracts/Vault.sol
在 contracts 文件夹中,可能会自动生成其他文件;你可以自由删除它们。
打开 Vault.sol
文件并将其修改如下。
要阅读代码的解释 (强烈推荐), 点击这里。
这段代码定义了一个名为 Vault 的智能合约,旨在管理 ETH 的存款和提款,同时利用 Blast 的自动收益特性。
合约初始化: 构造函数接受一个 Blast 合约的地址( _blast),并对它进行初始化。它使用 IBlast 接口配置自动收益。
铸造与销毁份额: _mint 和 _burn 内部函数管理合约的份额代币。当用户存入 ETH 时,铸造份额,而当他们提取时,销毁份额。这种机制有助于跟踪每个用户在合约的总 ETH 池中的份额。
ETH 存款和提款: deposit 函数允许用户向合约发送 ETH,换取基于当前 ETH 余额和总份额供给的份额。反之,withdraw 函数允许用户用相应的 ETH 额度赎回他们的份额,从而减少他们在总池中的份额。
检查余额和后备机制: getBalance 提供特定地址的份额余额。合约还包含一个后备函数 ( receive) 以处理直接 ETH 转账,当 ETH 直接发送到合约地址时,自动调用 deposit 函数。
本合约是 Blast 生态系统的基础部分,使用户能够存入 ETH,自动获得收益,并以公平的份额提取他们的资金。
contracts/Vault.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
import "./interfaces/IBlast.sol";
// 自定义错误以提高可读性和调试
error InsufficientShares();
error AmountMustBePositive();
error FailedToSendEther();
error InvalidYieldMode();
contract Vault {
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
// IBlast 接口以启用自动收益收集
constructor(address _blast) {
// 初始化 IBlast 合约
IBlast blast = IBlast(_blast);
// 合约余额将随着收益收集而自动增加
blast.configureAutomaticYield();
}
// 内部函数以铸造份额
function _mint(address _to, uint256 _shares) private {
totalSupply += _shares;
balanceOf[_to] += _shares;
}
// 内部函数以销毁份额
function _burn(address _from, uint256 _shares) private {
totalSupply -= _shares;
balanceOf[_from] -= _shares;
}
// 向合约存入 ETH 的函数
function deposit() public payable {
if (msg.value == 0) {
revert AmountMustBePositive();
}
uint256 shares;
if (totalSupply == 0) {
shares = msg.value;
} else {
shares = (msg.value * totalSupply) / address(this).balance;
}
_mint(msg.sender, shares);
}
// 从合约提取 ETH 的函数
function withdraw(uint256 _shares) public {
if (balanceOf[msg.sender] < _shares) {
revert InsufficientShares();
}
uint256 amount = (_shares * address(this).balance) / totalSupply;
_burn(msg.sender, _shares);
(bool sent,) = payable(msg.sender).call{value: amount}("");
if (!sent) {
revert FailedToSendEther();
}
}
// 获取特定地址余额的函数
function getBalance(address _address) public view returns (uint256) {
return balanceOf[_address];
}
// 后备函数以允许直接向合约转账 ETH
receive() external payable {
deposit();
}
}
现在,让我们将合约部署到 Blast Sepolia 测试网。
在 scripts 文件夹中创建一个名为 deploy.ts
的文件:
echo > scripts/deploy.ts
将其修改如下。
要阅读代码的解释 (强烈推荐), 点击此处。
这个 TypeScript 脚本旨在使用 Hardhat 框架部署和验证一个 Vault 智能合约。
部署 Vault 合约: 脚本首先定义了 Blast 合约地址。然后部署 Vault 合约,将 Blast 合约地址作为构造函数参数传递。await vault.waitForDeployment()
调用确保部署过程完成,然后再继续。
控制台日志和合约验证: 在部署后,脚本记录了已部署的 Vault 合约地址。然后继续使用 Hardhat 的 run 函数和 verify:verify 任务来验证合约,确保合约的源代码和部署参数可公开访问和验证。
读取并记录收益配置: 脚本通过获取新部署的 Vault 合约的收益配置来与已部署的 Blast 合约进行交互。这一步对确认 Vault 合约正确设置以与 Blast 协议的收益生成特性进行交互至关重要。
错误处理: 脚本包含一个 catch 块进行错误处理,确保在执行期间出现的异常被记录,并且该过程以适当的错误代码退出。
总之,这个脚本自动化了 Vault 合约在 Blast 区块链上的部署和验证过程,同时确认了与 Blast 收益配置的集成。这种自动化简化了开发工作流程,并确保智能合约部署的透明度和可靠性。
scripts/deploy.ts
import { ethers, run } from "hardhat";
async function main() {
const blastAddress: string = "0x4300000000000000000000000000000000000002";
const vault = await ethers.deployContract("Vault", [\
blastAddress,\
]);
await vault.waitForDeployment();
console.log(`Vault contract deployed to ${vault.target}`);
await run("verify:verify", {
address: vault.target,
constructorArguments: [blastAddress],
});
const blast = await ethers.getContractAt("IBlast", blastAddress);
const configuration = await blast.readYieldConfiguration(
vault.target
);
console.log(`Yield Configuration for Vault (${vault.target})`);
console.log(configuration);
}
// 我们建议使用这种模式以便在各处使用 async/await
// 正确处理错误。
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
通过运行以下命令部署合约:
npx hardhat run --network blast_sepolia scripts/deploy.ts
请注意,由于我们在
hardhat.config.ts
的 networks 设置中将 Blast Sepolia 测试网定义为 blast_sepolia。
部署成功后,你将在输出中看到合约的地址。
Vault contract deployed to 0xB2b68B2ad7cc81841D92f721104E6FdB5dbB78F3
Successfully submitted source code for contract
contracts/Vault.sol:Vault at 0xB2b68B2ad7cc81841D92f721104E6FdB5dbB78F3
for verification on the block explorer. Waiting for verification result...
Successfully verified contract Vault on the block explorer.
https://testnet.blastscan.io/address/0xB2b68B2ad7cc81841D92f721104E6FdB5dbB78F3#code
Yield Configuration for Vault (0xB2b68B2ad7cc81841D92f721104E6FdB5dbB78F3)
0n
Yield 配置值为 Vault 合约的 0 表示处于 "AUTOMATIC" 模式,因为 YieldMode 在合约中定义如下,表明自动生成原生收益而无需人工干预。
YieldMode 枚举
enum YieldMode {
AUTOMATIC, // 0
VOID, // 1
CLAIMABLE // 2
}
导航至 Blast Sepolia 测试网的 区块浏览器 以验证智能合约是否已部署,通过输入从上面的部署脚本返回的地址。
请注意,由于在部署脚本中的验证步骤,智能合约在区块浏览器上已经过验证。
要与合约交互,请在 scripts 目录中创建另一个脚本,名为 depositEth.ts:
echo > scripts/depositEth.ts
然后打开文件并输入以下代码。
请记得用你的 Vault 合约地址替换 YOUR_VAULT_CONTRACT_ADDRESS 占位符。
此外,此脚本文件用于向 Vault 合约存入 0.001 ETH。如果你想更改存入的 ETH 数量,请更改高亮行中的数量。
要阅读代码的解释 (强烈推荐), 点击这里。
这个 TypeScript 脚本旨在向 Blast 区块链上的 Vault 智能合约存入 ETH,利用 Hardhat 框架。
设置合约交互: 脚本首先指定已部署的 Vault 合约的地址。用户需要用实际合约地址替换 'YOUR_VAULT_CONTRACT_ADDRESS'。
定义存款金额: ethAmountToDeposit 变量被设置为特定的 ETH 数量,使用 ethers.parseEther('0.001')。这将 ETH 数量的字符串表示转换为以 Ethereum 区块链可以理解的格式,此例中为 0.001 ETH。
合约交互以存款: 脚本使用 getContractAt 和指定的合约地址获取 Vault 合约实例。然后,它调用 Vault 合约的 deposit 函数,传递要存入的 ETH 数量。该交易触发合约中的存款操作。
交易确认和日志记录: 发送交易后,脚本使用 tx.wait()
等待交易被挖掘。一旦挖掘成功,它将记录一条消息并附上交易哈希,提供链接以查看在 Blast 区块链上的交易状态。
错误处理: 使用标准错误处理模式,捕获脚本执行期间的任何异常,记录错误,以及设置退出代码以指示失败。
这个脚本是一个实用工具,供用户或开发人员与 Vault 合约交互,使他们能够轻松存入 ETH 并参与 Blast 区块链的收益生成机制。
scripts/depositEth.ts
import { ethers } from 'hardhat'
async function main() {
const vaultAddress: string = 'YOUR_VAULT_CONTRACT_ADDRESS' // 👈 更新此处
const ethAmountToDeposit: bigint = ethers.parseEther('0.001')
const vault = await ethers.getContractAt(
"Vault",
vaultAddress
);
const tx = await vault.deposit({ value: ethAmountToDeposit });
tx.wait();
console.log(
`Transaction to deposit ETH is sent to the blockchain. Check your transaction status: https://testnet.blastscan.io/tx/${tx.hash}`
);
}
// 我们建议使用这种模式以便在各处使用 async/await
// 正确处理错误。
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
要运行脚本,请使用以下 hardhat 命令:
npx hardhat run scripts/depositEth.ts --network blast_sepolia
控制台输出应如下所示。
Transaction to deposit ETH is sent to the blockchain. Check your transaction status: https://testnet.blastscan.io/tx/0x34edf8b98a57bf2d127d7b5c96737e9edec1256088310775524b462acfe2f88f
你可以通过点击链接检查交易详情。
作为替代方法,由于我们的合约已获得批准,你可以通过浏览器与其交互。
就这样!你刚刚在 Blast Sepolia 测试网上使用 Hardhat 和 QuickNode 创建了一个金库智能合约。此外,你设置了收益模式,并运行了脚本以存入一些 ETH。
要验证自动收益机制,我们可以随着时间推移监控合约的 ETH 余额。余额的增加而没有额外存款表明自动原生收益生成成功。这种验证确保了自动收益机制的功能。
最简单的方法是从 Blast Sepolia Explorer 的合约页面检查余额。如你所见,尽管总存入金额为 0.001 ETH,但金库合约的 ETH 余额要稍微高一些。
收益是多久更新一次的?
在主网,ETH 余额大约每天更新一次。在测试网,ETH 余额将每小时更新一次,更新率约为每日 ~0.01%。
来源: Blast 文档
如果你想继续学习关于 Blast 和智能合约的知识,可以查看以下资源:
🎉 恭喜你!在这个旅程中,你了解了 Blast,部署了智能合约,并创建了与智能合约交互的脚本。
如果你有任何问题或需要进一步的帮助,请随时加入我们的 Discord 服务器,或使用下面的表单提供反馈。通过关注我们的 Twitter(@QuickNode)和 Telegram 公告渠道 了解最新动态。
请告诉我们 如果你有任何反馈或对新主题的请求。我们期待你的意见。
- 原文链接: quicknode.com/guides/oth...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!