本文介绍了Blast L2区块链项目,它通过为ETH和稳定币存款提供原生收益而闻名。文章详细讲解了如何在Blast上创建、部署自动生息的保险库合约,包括Blast的独特功能、开发者设置、智能合约开发和部署,以及如何与已部署的保险库合约进行交互。
目前大多数区块链都要求用户质押他们的代币或运行验证器,以便从协议中获得原生收益。Blast 是一个 Layer 2 (L2) 区块链项目,以其为已存入的 ETH 和稳定币提供原生收益的创新方法而闻名。在本指南中,你将了解更多关于 Blast 的信息,然后学习如何使用 Hardhat 在 Blast 上创建、部署和交互自动收益保管库合约。
Blast 是一个 EVM 兼容的、乐观 rollup 的 L2 区块链。它的独特之处在于原生整合了 ETH 质押和真实世界资产 (RWA) 协议的收益,为 ETH 提供 4% 的基准收益,为稳定币提供 5% 的基准收益。这种收益整合旨在抵消通货膨胀损失,并支持在其他 L2 上不可行的新型 DApp 商业模式。
让我们深入了解 Blast 的运作方式,以及它为何成为开发者和投资者的首选。
自动 Rebase: Blast 在其 L2 平台上为 ETH、WETH (Wrapped ETH) 和 USDB (Blast 的原生稳定币) 具有独特的自动 rebase 功能。这种 rebase 使这些资产能够无缝地从收益生成中受益,无论对于外部拥有的账户 (EOA) 还是智能合约。与 ETH 相比,ETH 的合约默认禁用收益,而 WETH 和 USDB 账户默认自动为 EOA 和智能合约生成收益。
L1 质押收益: 在以太坊上海升级之后,Blast 利用来自 L1 质押的 ETH 收益(最初通过 Lido),并通过在 L2 上 rebase ETH 将其转移给用户。
稳定币的 T-Bill 收益: 桥接到 Blast 的稳定币将转换为 USDB,后者从 MakerDAO 的 T-Bill 协议中获得收益。这种机制允许生成稳定币收益。
Gas 收入分享: 与其他 L2 不同,Blast 与 DApp 开发者分享净 gas 收入,提供额外的收入来源或补贴用户 gas 费用的选项。
你需要一个 API 端点来与 Blast 区块链通信。为此,与公共 API 端点相比,QuickNode 等服务提供更快、更可靠的 RPC 连接。在此处免费注册 (here),并为 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 提示时选择 Create a TypeScript project。此外,当被要求安装 @nomicfoundation/hardhat-toolbox 时,请说 Yes。
在你的项目目录中创建一个 .env
文件。
环境变量用于存储敏感数据,例如密码、API 凭据和其他不应直接写入代码的信息。
echo > .env
如下修改你的 .env
文件。
将 YOUR_PRIVATE_KEY 和 YOUR_QUICKNODE_BLAST_SEPOLIA_ENDPOINT_URL 占位符替换为你的钱包的私钥和你的 QuickNode Blast Sepolia 端点 HTTP URL。
PRIVATE_KEY="YOUR_PRIVATE_KEY"
QUICKNODE_ENDPOINT="YOUR_QUICKNODE_BLAST_SEPOLIA_ENDPOINT_URL"
如果你不知道如何获取你的私钥,请点击 here。
此说明是为 MetaMask 准备的。
找你的私钥:
然后,如下配置你的 hardhat.config.ts
文件。任何与 Hardhat 相关的设置,例如网络、账户和 Solidity 版本,都在此文件中定义。
要阅读代码的解释 (强烈推荐),请点击 here
此代码是为 Blast 区块链量身定制的 Hardhat 项目的配置设置。
网络配置: networks 属性定义了两个环境 - 用于 Sepolia 测试网的 blast_sepolia 和使用分叉的本地开发环境的 hardhat。Sepolia 配置包括用于交易的 QuickNode 端点 URL 和私钥,以及指定的 gas 价格。本地环境配置 (hardhat) 设置了从特定区块号使用相同的 QuickNode 端点进行分叉。
Etherscan 集成: 在 etherscan 下,虽然不需要唯一的 API 密钥,但它必须有一个值。因此,blast_sepolia 网络的 API 密钥设置为占位符。customChains 数组包括 blast_sepolia 网络的自定义配置,指定其链 ID 和 API 和区块浏览器的 URL。具体来说,customChains 中的 apiURL 指定了 API 服务的端点(在本例中为 https://api.routescan.io),Hardhat 可以使用该端点与指定的网络(此处为 blast_sepolia 测试网)进行交互。这允许与区块链进行无缝交互,并通过 Hardhat 验证 Blast 测试网上的合约。
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', // although a unique API key is not required, it must have a value, so just set a placeholder
},
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 收益,但智能合约具有三种用于 rebase 的收益模式。
在本指南中,我们将选择收益模式为 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
文件并如下修改。
// 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
文件并如下修改。
要阅读代码的解释 (强烈推荐),请点击 here
此代码定义了一个名为 Vault 的智能合约,该合约旨在管理 ETH 的存款和取款,同时利用 Blast 的自动收益功能。
合约初始化: 构造函数接受 Blast 合约的地址 (_blast),并对其进行初始化。它使用 IBlast 接口来配置自动收益。
铸造和销毁份额: _mint 和 _burn 内部函数管理合约的份额代币。当用户存入 ETH 时,会铸造份额,当他们取款时,会销毁份额。这种机制有助于跟踪每个用户在合约总 ETH 池中的份额。
ETH 存款和取款: deposit 函数允许用户将 ETH 发送到合约,以换取基于当前 ETH 余额和份额总供应量的份额。相反,withdraw 函数允许用户以按比例的 ETH 赎回他们的份额,从而减少他们在总池中的份额。
检查余额和回退机制: getBalance 提供特定地址的以份额表示的余额。该合约还包括一个回退函数 (receive),用于处理直接 ETH 转账,当 ETH 直接发送到合约地址时,会自动调用 deposit 函数。
该合约是 Blast 生态系统的重要组成部分,使用户能够存入 ETH、自动赚取收益,并以公平的资产总额份额提取资金。
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
import "./interfaces/IBlast.sol";
// Custom errors for better readability and debugging
error InsufficientShares();
error AmountMustBePositive();
error FailedToSendEther();
error InvalidYieldMode();
contract Vault {
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
// IBlast interface for enabling automatic yield collection
constructor(address _blast) {
// Initialize the IBlast contract
IBlast blast = IBlast(_blast);
// The contract balance will grow automatically over time due to yield collection
blast.configureAutomaticYield();
}
// Internal function to mint shares
function _mint(address _to, uint256 _shares) private {
totalSupply += _shares;
balanceOf[_to] += _shares;
}
// Internal function to burn shares
function _burn(address _from, uint256 _shares) private {
totalSupply -= _shares;
balanceOf[_from] -= _shares;
}
// Function to deposit ETH into the contract
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);
}
// Function to withdraw ETH from the contract
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 to get the balance of a specific address
function getBalance(address _address) public view returns (uint256) {
return balanceOf[_address];
}
// Fallback function to allow direct ETH transfers to the contract
receive() external payable {
deposit();
}
}
现在,让我们将我们的合约部署到 Blast Sepolia 测试网。
在你的 scripts 文件夹中创建一个名为 deploy.ts
的文件:
echo > scripts/deploy.ts
如下修改它。
要阅读代码的解释 (强烈推荐),请点击 here
此 TypeScript 脚本旨在部署和验证使用 Hardhat 框架的 Vault 智能合约。
部署 Vault 合约: 该脚本首先定义 Blast 合约地址。然后,它部署 Vault 合约,并将 Blast 合约地址作为构造函数参数传递。await vault.waitForDeployment()
调用确保在继续之前完成部署过程。
控制台日志记录和合约验证: 部署后,脚本会记录已部署的 Vault 合约的地址。然后,它继续使用 Hardhat 的 run 函数和 verify:verify 任务在区块链上验证合约,确保合约的源代码和部署参数可公开访问和验证。
读取和记录收益配置: 该脚本通过获取新部署的 Vault 合约的收益配置来与已部署的 Blast 合约进行交互。此步骤对于确认 Vault 合约已正确设置为与 Blast 协议的收益生成功能进行交互至关重要。
错误处理: 该脚本包括一个用于错误处理的 catch 块,确保记录执行期间抛出的任何异常,并且该过程以适当的错误代码退出。
总而言之,此脚本自动化了 Blast 区块链上 Vault 合约的部署和验证过程,以及确认其与 Blast 收益配置的集成。这种自动化简化了开发工作流程,并确保了智能合约部署的透明性和可靠性。
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);
}
// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
通过运行以下命令部署合约:
npx hardhat run --network blast_sepolia scripts/deploy.ts
请注意,我们使用 blast_sepolia,因为我们在
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
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 占位符。
此外,此脚本文件用于将 0.001 ETH 存入 Vault 合约。如果要更改要存入的 ETH 金额,请更改高亮显示行中的金额。
要阅读代码的解释 (强烈推荐),请点击 here
此 TypeScript 脚本的开发目的是将 ETH 存入 Blast 区块链上的 Vault 智能合约,并利用 Hardhat 框架。
设置合约交互: 该脚本首先指定已部署的 Vault 合约的地址。用户需要将 ' YOUR_VAULT_CONTRACT_ADDRESS' 替换为实际合约地址。
定义存款金额: ethAmountToDeposit 变量使用 ethers.parseEther('0.001') 设置为特定的 ETH 金额。这会将 ETH 金额的字符串表示形式转换为 Ethereum 区块链可以理解的格式,在本例中为 0.001 ETH。
合约交互进行存款: 该脚本使用 getContractAt 和指定的合约地址获取 Vault 合约实例。然后,它调用 Vault 合约的 deposit 函数,并传递要存入的 ETH 金额。此交易触发智能合约中的存款操作。
交易确认和日志记录: 发送交易后,脚本会等待使用 tx.wait()
挖掘交易。挖掘完成后,它会记录一条带有交易哈希的消息,并提供一个链接,以在 Blast 区块链浏览器上查看交易状态。
错误处理: 使用标准错误处理模式来捕获脚本执行期间的任何异常,记录错误,并设置退出代码以指示失败。
该脚本是用户或开发者与 Vault 合约交互的实用工具,使他们能够轻松存入 ETH 并参与 Blast 区块链的收益生成机制。
import { ethers } from 'hardhat'
async function main() {
const vaultAddress: string = 'YOUR_VAULT_CONTRACT_ADDRESS' // 👈 UPDATE HERE
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}`
);
}
// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
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
你可以通过单击该链接来检查交易详细信息。
作为一种替代方法,由于我们的合约已获得批准,因此可以通过浏览器与其进行交互。
就这样!你刚刚使用 Hardhat 和 QuickNode 在 Blast Sepolia 测试网上创建了一个保管库智能合约。此外,你设置了收益赚取模式并运行了一个脚本来存入一些 ETH。
要验证自动收益机制,我们可以随着时间的推移监控合约的 ETH 余额。在没有额外存款的情况下,余额的增加表明成功的自主原生收益生成。此验证确保了自动收益机制的功能。
最简单的方法是从 Blast Sepolia 浏览器 上的合约页面检查余额。如你所见,虽然总存款金额为 0.001 ETH,但 Vault 合约的 ETH 余额略高于该值。
由于收益,余额多久更新一次?
在主网上,ETH 余额将大约每天更新一次。在测试网上,ETH 余额将每小时更新一次,速率约为每天 0.01%。
来源:Blast 文档
如果你想继续了解 Blast 和智能合约,请查看以下资源:
🎉 恭喜!在此过程中,你已经了解了 Blast,部署了一个智能合约,并创建了与智能合约交互的脚本。
如果你有任何问题或需要更多帮助,请随时加入我们的 Discord 服务器或使用下面的表格提供反馈。请在 Twitter (@QuickNode) 和 Telegram 公告频道 上关注我们,以了解最新信息。
如果你有任何反馈或对新主题的要求,请 告诉我们。我们很乐意收到你的来信。
- 原文链接: quicknode.com/guides/bla...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!