本文指南提供了如何创建和部署自己的超额抵押稳定币的详细步骤,使用Foundry作为智能合约开发工具,结合OpenZeppelin和Chainlink。内容涵盖了合约的核心功能、抵押品管理、清算机制及相关测试,适合有基本Solidity和智能合约知识的开发者。
警告
本指南中的代码仅用于教育和演示目的。它是非生产就绪的,不应在实时环境中使用。
虽然以 USDC 和 USDT 为代表的中心化稳定币在市场上占据主导地位(数据源:Ethereum,Solana),并且今天在区块链交易量中占有重要份额,但对去中心化替代品的需求持续增长。本指南将引导你使用 Foundry v1.0 作为我们的智能合约开发工具包,OpenZeppelin 为标准化的代币合约,以及 Chainlink 作为我们的价格预言机,创建、测试、部署和与你自己的超抵押稳定币进行交互。
让我们开始吧!
Foundry 是一个用于在 EVM 区块链上构建和部署智能合约的开发框架。它旨在使各级开发者更容易创建和部署安全高效的智能合约。
最近,Foundry 发布了 v1.0,它代表了以太坊开发工具的一个重要里程碑,为我们构建和测试智能合约的方法带来了更多的效率和稳定性。
提示
如果你是 Foundry 的新手,可以跳过此部分,因为它与你将在未来进行的智能合约开发工作无关。
Foundry v1.0 对我们开发智能合约的方式进行了更改。主要更改包括:
Solc 优化器更改:默认情况下禁用优化器以防止潜在的优化错误。这意味着你需要在 foundry.toml
中显式启用它。
测试框架更新:
testFail
前缀的支持(请使用 vm.expectRevert()
)expectRevert
的行为重新映射和依赖性:
你无需担心在本指南中迁移代码,因为所有代码都将符合 v1.0。要了解更多信息,请查看 Foundry 的这篇迁移 文章。
要与区块链进行通信,你需要访问节点。虽然我们可以运行自己的节点,但在 QuickNode,我们使快速启动区块链节点变得简单易行。你可以在 这里注册账户。
登录后,创建以太坊 Sepolia 测试网区块链的端点。保存 HTTP URL,它应该看起来像这样:
提示
本指南是 EVM 兼容的。如果你想在其他链上部署代币,选择其他 EVM 兼容链(例如:Optimism、Arbitrum 等),并相应更新钱包和 RPC URL。你还可以将 Chain Prism 附加组件添加到你的端点,以便在同一端点内访问多个区块链 RPC URL。
为了在链上进行活动,你需要 ETH 来支付交易费用。由于我们使用的是 Sepolia 测试网,我们可以从 多链 QuickNode 水龙头 获取一些测试 ETH。
导航到 多链 QuickNode 水龙头 连接你的钱包(例如:MetaMask、Coinbase Wallet),或者粘贴你的钱包地址以提取测试 ETH。请注意,要使用 EVM 水龙头,以太坊主网需要维持 0.001 ETH 的主网余额要求。你还可以通过推特或使用你的 QuickNode 账户登录以获得奖励!
稳定币已经从简单的法币支持代币,例如 USDT(2014),演变为更复杂的机制,例如 FRAX(基于算法的)。虽然 USDC 和 USDT 在市场份额中仍占主导地位(数据源:Ethereum,Solana),去中心化替代品如 DAI(2017;现在为 USDS)开创了加密抵押的新天地。值得注意的是,其他基于算法的实验,如 UST(2020),在 2022 年崩溃后展示了未经检验的稳定机制的风险。
稳定币通常通过抵押(如 USDC 的 1:1 美元支持)、超抵押(如 DAI 的 150% ETH 支持)或算法(例如 FRAX)方法保持其挂钩。每种方法在去中心化、资本效率和稳定性风险之间进行取舍。
现在,让我们回顾一下今天常见的稳定币类型。
FRAX 引入了一种混合方法,结合了抵押和算法稳定机制,其中:
在本指南中,我们将演示如何创建一个简单版本的超抵押稳定币。该稳定币将具有以下特征:
现在让我们进入指南的技术编码部分。
现在我们了解了 Foundry v1.0,让我们开始编码。
如果你尚未安装 Foundry,请立即安装。你可以运行 foundryup
命令安装最新稳定版本。
接下来,在你选择的目录中打开终端命令窗口,运行以下命令:
forge init my-foundry-project
cd my-foundry-project
这将创建以下目录结构:
.
├── README.md
├── foundry.toml
├── lib
├── script
├── src
└── test
其中:
foundry.toml
:作为配置文件lib
:存放如 @openzeppelin 的库script
:存储脚本,例如智能合约交互、部署等src
:智能合约的源代码(例如,使用 Solidity、Yul 编写)test
:存储和运行测试(这是最重要的步骤之一!)让我们安装所需的库依赖项:
forge install foundry-rs/forge-std --no-commit
forge install OpenZeppelin/openzeppelin-foundry-upgrades --no-commit
forge install OpenZeppelin/openzeppelin-contracts-upgradeable --no-commit
forge install smartcontractkit/chainlink-brownie-contracts@1.1.1 --no-commit
然后,在项目的主目录中创建一个名为 remappings.txt
的文件并设置以下值:
@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/
@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/
@chainlink/contracts/=lib/chainlink-brownie-contracts/contracts/
现在,在我们开始编码之前,让我们明确接下来要构建的内容。
信息
本指南中演示的稳定币智能合约不适合生产使用。使用风险自负!强烈建议你在将任何智能合约代码部署到生产环境之前对其进行审计。
现在,让我们开始构建。导航到你的 src
文件夹并创建一个名为 Stablecoin.sol 的文件。
让我们开始添加每个代码块,同时进行解释。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol";
我们使用 OpenZeppelin 的智能合约代码,包括 ERC-20
实现和 ReentrancyGuard
以防止重入攻击。我们还导入了 Chainlink 的 AggregatorV3Interface
以获取 ETH/USD 的价格数据。
在我们的合约初始化(即 contract SimpleStablecoin
)中,我们通过从 ERC20
和 ReentrancyGuard
继承,设置基本结构。我们声明 Chainlink 价格预言机接口,并定义用于抵押和清算阈值的核心参数。Vault
结构跟踪每个用户的抵押品和债务位置。
contract SimpleStablecoin is ERC20, ReentrancyGuard {
AggregatorV3Interface public priceFeed;
uint256 public constant COLLATERAL_RATIO = 15000; // 150%
uint256 public constant RATIO_PRECISION = 10000; // 100%
uint256 public constant MIN_COLLATERAL = 0.1 ether;
uint256 public constant LIQUIDATION_THRESHOLD = 13000; // 130%
struct Vault {
uint256 collateralAmount;
uint256 debtAmount;
}
mapping(address => Vault) public vaults;
event VaultUpdated(address indexed user, uint256 collateral, uint256 debt);
event Liquidated(address indexed user, address indexed liquidator, uint256 debt, uint256 collateralSeized);
constructor(address _priceFeed) ERC20("Simple USD", "sUSD") {
priceFeed = AggregatorV3Interface(_priceFeed);
}
}
getEthPrice
函数查询 Chainlink 的价格预言机以获取最新的 ETH/USD 价格。
// 从 Chainlink 获取 ETH/USD 价格
function getEthPrice() public view returns (uint256) {
(, int256 price, , , ) = priceFeed.latestRoundData();
require(price > 0, "无效价格");
return uint256(price);
}
mint
函数允许用户通过存入 ETH 作为抵押来创建新的稳定币。它确保满足最低抵押要求,并计算可以铸造的稳定币的最大安全数量,同时保持所需的抵押比率。
// 通过存入 ETH 铸造稳定币
function mint() external payable nonReentrant {
require(msg.value >= MIN_COLLATERAL, "低于最低抵押");
Vault storage vault = vaults[msg.sender];
uint256 ethPrice = getEthPrice();
uint256 newCollateral = vault.collateralAmount + msg.value;
uint256 collateralValue = (newCollateral * ethPrice) / 1e8;
uint256 maxSafeDebt = (collateralValue * RATIO_PRECISION) / COLLATERAL_RATIO;
uint256 additionalDebt = maxSafeDebt;
if (vault.debtAmount > 0) {
require(maxSafeDebt > vault.debtAmount, "没有额外的债务可用");
additionalDebt = maxSafeDebt - vault.debtAmount;
}
vault.collateralAmount = newCollateral;
vault.debtAmount += additionalDebt;
_mint(msg.sender, additionalDebt);
emit VaultUpdated(msg.sender, newCollateral, vault.debtAmount);
}
repay
函数允许用户偿还其债务并检索其抵押品。用户可以进行部分还款,如果他们偿还了所有债务,将返回其全部抵押品。
// 偿还稳定币债务
function repay(uint256 amount) external nonReentrant {
Vault storage vault = vaults[msg.sender];
require(vault.debtAmount >= amount, "偿还过多");
require(balanceOf(msg.sender) >= amount, "余额不足");
_burn(msg.sender, amount);
vault.debtAmount -= amount;
if (vault.debtAmount == 0) {
uint256 collateralToReturn = vault.collateralAmount;
vault.collateralAmount = 0;
(bool success, ) = msg.sender.call{value: collateralToReturn}("");
require(success, "ETH 转账失败");
}
emit VaultUpdated(msg.sender, vault.collateralAmount, vault.debtAmount);
}
清算函数对维护系统偿付能力至关重要。它允许任何人通过偿还用户的债务以市场价格获取其抵押品,来清算一个抵押不足的位置。
// 清算抵押不足的用户
function liquidate(address user) external nonReentrant {
Vault storage vault = vaults[user];
require(vault.debtAmount > 0, "没有债务可清算");
require(getCurrentRatio(user) < LIQUIDATION_THRESHOLD, "位置不可清算");
uint256 debtToRepay = vault.debtAmount;
require(balanceOf(msg.sender) >= debtToRepay, "清算余额不足");
uint256 ethPrice = getEthPrice();
uint256 collateralToSeize = (debtToRepay * 1e8) / ethPrice;
require(collateralToSeize <= vault.collateralAmount, "抵押品不足");
vault.collateralAmount = 0;
vault.debtAmount = 0;
_burn(msg.sender, debtToRepay);
(bool success, ) = msg.sender.call{value: collateralToSeize}("");
require(success, "ETH 转账失败");
emit Liquidated(user, msg.sender, debtToRepay, collateralToSeize);
emit VaultUpdated(user, 0, 0);
}
getCurrentRatio
函数计算用户保险库的当前抵押比率,这对于确定一个位置是否可以被清算至关重要。
// 获取抵押的当前比率
function getCurrentRatio(address user) public view returns (uint256) {
Vault storage vault = vaults[user];
if (vault.debtAmount == 0) return type(uint256).max;
uint256 ethPrice = getEthPrice();
uint256 collateralValue = (vault.collateralAmount * ethPrice) / 1e8;
return (collateralValue * RATIO_PRECISION) / vault.debtAmount;
}
最后,我们实现一个接收函数,使我们的合约能够接受 ETH 转账,这对于处理抵押品存入是必要的。
receive() external payable {}
这完成了我们的抵押稳定币实现。该智能合约通过超抵押和清算机制维持稳定,同时为用户提供铸造、偿还和管理其头寸的能力。再一次,这段代码并不是准备好用于生产,而是作为开始进行稳定币开发的简单示例。
接下来,让我们调用构建命令以编译合约:
forge build
之后,我们将编写测试(非常重要!)以确保所有功能和安全措施按预期工作。
在你的 test 目录中创建一个名为 Stablecoin.t.sol 的文件,并按顺序输入以下代码片段:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "forge-std/Test.sol";
import "../src/Stablecoin.sol";
import "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol";
contract MockV3Aggregator is AggregatorV3Interface {
int256 private _price;
uint8 private _decimals;
constructor(uint8 decimals_, int256 initialPrice) {
_decimals = decimals_;
_price = initialPrice;
}
function setPrice(int256 price) external {
_price = price;
}
function decimals() external view override returns (uint8) {
return _decimals;
}
function description() external pure override returns (string memory) {
return "Mock V3 Aggregator";
}
function version() external pure override returns (uint256) {
return 1;
}
function getRoundData(uint80) external view override returns (uint80, int256, uint256, uint256, uint80) {
return (0, _price, block.timestamp, block.timestamp, 0);
}
function latestRoundData() external view override returns (uint80, int256, uint256, uint256, uint80) {
return (0, _price, block.timestamp, block.timestamp, 0);
}
}
contract SimpleStablecoinTest is Test {
SimpleStablecoin public stablecoin;
MockV3Aggregator public mockPriceFeed;
address public user1 = address(1);
address public user2 = address(2);
address public liquidator = address(3);
uint8 public constant DECIMALS = 8;
int256 public constant INITIAL_PRICE = 2000e8; // 每 ETH 2000 美元
uint256 public constant INITIAL_ETH_BALANCE = 100 ether;
event VaultUpdated(address indexed user, uint256 collateral, uint256 debt);
event Liquidated(address indexed user, address indexed liquidator, uint256 debt, uint256 collateralSeized);
function setUp() public {
// 部署模拟价格预言机和稳定币
mockPriceFeed = new MockV3Aggregator(DECIMALS, INITIAL_PRICE);
stablecoin = new SimpleStablecoin(address(mockPriceFeed));
// 设置测试账户
vm.deal(user1, INITIAL_ETH_BALANCE);
vm.deal(user2, INITIAL_ETH_BALANCE);
vm.deal(liquidator, INITIAL_ETH_BALANCE);
}
function test_InitialState() public view {
assertEq(stablecoin.name(), "Simple USD");
assertEq(stablecoin.symbol(), "sUSD");
assertEq(address(stablecoin.priceFeed()), address(mockPriceFeed));
}
function test_Mint() public {
uint256 ethToMint = 1 ether;
// 计算预期代币:
// 1 ETH = $2000
// 在 150% 的抵押比率下,最大债务为:
// (2000 * 10000) / 15000 = 1333.33...
uint256 collateralValue = (ethToMint * uint256(INITIAL_PRICE)) / 1e8;
uint256 expectedTokens = (collateralValue * stablecoin.RATIO_PRECISION()) / stablecoin.COLLATERAL_RATIO();
vm.startPrank(user1);
stablecoin.mint{value: ethToMint}();
(uint256 collateral, uint256 debt) = stablecoin.vaults(user1);
assertEq(collateral, ethToMint);
assertEq(debt, expectedTokens);
assertEq(stablecoin.balanceOf(user1), expectedTokens);
vm.stopPrank();
}
function test_MultipleVaultOperations() public {
vm.startPrank(user1);
// 初始铸造 1 ETH
stablecoin.mint{value: 1 ether}();
uint256 firstMintAmount = stablecoin.balanceOf(user1);
// 添加更多抵押品(0.5 ETH)
stablecoin.mint{value: 0.5 ether}();
uint256 secondMintAmount = stablecoin.balanceOf(user1) - firstMintAmount;
// 验证总头寸
(uint256 collateral, uint256 debt) = stablecoin.vaults(user1);
assertEq(collateral, 1.5 ether);
assertEq(debt, firstMintAmount + secondMintAmount);
vm.stopPrank();
}
function test_Liquidation() public {
// 1. 用户 1 创建一个 1 ETH 的保险库(神知道我们什么时候能到 10000...)
vm.startPrank(user1);
stablecoin.mint{value: 1 ether}();
uint256 mintedAmount = stablecoin.balanceOf(user1);
vm.stopPrank();
// 2. 将代币转移给清算者
vm.prank(user1);
stablecoin.transfer(liquidator, mintedAmount);
// 3. 将 ETH 价格降低到 1500 美元(低于清算阈值)
mockPriceFeed.setPrice(1500e8);
// 4. 检查头寸现在是否能被清算
uint256 currentRatio = stablecoin.getCurrentRatio(user1);
assertTrue(currentRatio < stablecoin.LIQUIDATION_THRESHOLD());
// 5. 清算者执行清算
vm.startPrank(liquidator);
stablecoin.liquidate(user1);
// 6. 验证清算结果
(uint256 collateral, uint256 debt) = stablecoin.vaults(user1);
assertEq(debt, 0, "债务应为零");
assertEq(collateral, 0, "抵押品应为零");
vm.stopPrank();
}
function test_FullRepayment() public {
// 设置:创建保险库并铸造代币
vm.startPrank(user1);
stablecoin.mint{value: 1 ether}();
uint256 initialDebt = stablecoin.balanceOf(user1);
// 偿还全部债务
stablecoin.repay(initialDebt);
// 验证全部还款和抵押品归还
(uint256 collateral, uint256 debt) = stablecoin.vaults(user1);
assertEq(debt, 0);
assertEq(collateral, 0);
assertEq(stablecoin.balanceOf(user1), 0);
vm.stopPrank();
}
function test_RevertWhen_MintingBelowMinCollateral() public {
vm.startPrank(user1);
vm.expectRevert("低于最低抵押");
stablecoin.mint{value: 0.09 ether}();
vm.stopPrank();
}
function test_LiquidationPrice() public {
vm.startPrank(user1);
// 创建一个 1 ETH 的头寸,价格为 2000 美元
stablecoin.mint{value: 1 ether}();
(uint256 collateral, uint256 debt) = stablecoin.vaults(user1);
// 计算清算价格
uint256 liquidationPrice = (debt * stablecoin.LIQUIDATION_THRESHOLD() * 1e8) /
(collateral * stablecoin.RATIO_PRECISION());
// 将代币转移给清算者进行清算
vm.stopPrank();
vm.prank(user1);
stablecoin.transfer(liquidator, debt);
// 价格刚好高于清算 - 应该失败
mockPriceFeed.setPrice(int256(liquidationPrice + 1e8));
vm.prank(liquidator);
vm.expectRevert("位置不可清算");
stablecoin.liquidate(user1);
// 价格低于清算 - 应该成功
mockPriceFeed.setPrice(int256(liquidationPrice - 1e8));
vm.prank(liquidator);
stablecoin.liquidate(user1);
}
function test_PartialRepayment() public {
// 设置:创建保险库并铸造代币
vm.startPrank(user1);
stablecoin.mint{value: 1 ether}();
uint256 initialDebt = stablecoin.balanceOf(user1);
// 偿还一半的债务
uint256 repayAmount = initialDebt / 2;
stablecoin.repay(repayAmount);
// 验证部分还款
(uint256 collateral, uint256 debt) = stablecoin.vaults(user1);
assertEq(debt, initialDebt - repayAmount);
assertEq(collateral, 1 ether); // 抵押应保持不变
vm.stopPrank();
}
}
这个测试文件相当长,因此确保你回顾每个函数及其注释,以更好地理解其测试逻辑。
要运行测试,运行以下命令:
forge test
测试结果:
Ran 8 tests for test/Stablecoin.t.sol:SimpleStablecoinTest
[PASS] test_FullRepayment() (gas: 119625)
[PASS] test_InitialState() (gas: 25080)
[PASS] test_Liquidation() (gas: 158381)
[PASS] test_LiquidationPrice() (gas: 160892)
[PASS] test_Mint() (gas: 132465)
[PASS] test_MultipleVaultOperations() (gas: 148648)
[PASS] test_PartialRepayment() (gas: 136783)
[PASS] test_RevertWhen_MintingBelowMinCollateral() (gas: 23629)
Suite result: ok. 8 passed; 0 failed; 0 skipped; finished in 5.62ms (2.89ms CPU time)
现在我们的合约按预期工作,让我们将它们部署到像 Sepolia 这样的测试网。
为了将其部署到像 Sepolia 这样的远程测试网,首先需要配置一些东西。
接下来,在你的 script 文件夹中创建一个名为 DeployStablecoin.s.sol 的文件,并添加以下代码:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "forge-std/Script.sol";
import "../src/Stablecoin.sol";
contract DeployStablecoin is Script {
function run() external {
// Sepolia ETH/USD 价格预言机
address priceFeedAddress = 0x694AA1769357215DE4FAC081bf1f309aDC325306;
// 开始广播交易
vm.broadcast();
// 部署合约
SimpleStablecoin stablecoin = new SimpleStablecoin(priceFeedAddress);
console.log("稳定币部署到:", address(stablecoin));
console.log("价格预言机地址:", priceFeedAddress);
}
}
这个脚本使用 Chainlink 的价格预言机,并将合约部署到 Sepolia 测试网。
要部署合约,请运行以下命令:
forge script script/DeployStablecoin.s.sol:DeployStablecoin --rpc-url your_rpc_url --private-key your_private_key_here --broadcast -vvvv
-vvvv
选项用于更为详细的日志记录
最后,你将看到类似的输出:
##### sepolia
✅ [Success] Hash: 0xb9a5008e8acf16d72afa53f381c742bf1539cb610bf7dc9db6e23174c79d438c
Contract Address: 0x244FBFA8b2E02A0c5634d30Bb16E2d9B1B63Cb0d
Block: 7721469
Paid: 0.002110001463996228 ETH (2071014 gas * 1.018825302 gwei)
✅ Sequence #1 on sepolia | Total Paid: 0.002110001463996228 ETH (2071014 gas * avg 1.018825302 gwei)
==========================
链上执行完成且成功。
现在让我们移步到下一个步骤,通过存入 ETH 来铸造 sUSD
。接着,我们将销毁 sUSD
以检索回 ETH。
在你的脚本目录中创建一个名为 VaultOperations.s.sol
的文件,输入以下代码:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "forge-std/Script.sol";
import "forge-std/console.sol";
import "../src/Stablecoin.sol";
contract VaultOperations is Script {
SimpleStablecoin stablecoin;
address constant STABLECOIN_ADDRESS = REPLACE_WITH_YOUR_CONTRACT_ADDRESS; // 用你的合约地址替换
function setUp() public {
stablecoin = SimpleStablecoin(payable(STABLECOIN_ADDRESS));
}
function createAndMint() public {
vm.broadcast();
// 直接铸造抵押(保险库创建在铸造函数中处理)
uint256 collateralAmount = 0.1 ether;
stablecoin.mint{value: collateralAmount}();
// 记录结果
(uint256 collateral, uint256 debt) = stablecoin.vaults(msg.sender);
console.log("创建保险库并存入", collateralAmount, "ETH");
console.log("当前抵押品:", collateral);
console.log("当前债务:", debt);
console.log("当前比率:", stablecoin.getCurrentRatio(msg.sender));
}
function repayAndWithdraw(uint256 amount) public {
(uint256 collateral, uint256 debt) = stablecoin.vaults(msg.sender);
require(debt > 0, "没有债务可偿还");
require(amount <= debt, "金额超出债务");
vm.broadcast();
stablecoin.repay(amount);
// 记录结果
(uint256 newCollateral, uint256 newDebt) = stablecoin.vaults(msg.sender);
console.log("偿还", amount, "代币");
console.log("归还的抵押品:", collateral - newCollateral);
console.log("剩余债务:", newDebt);
}
function checkLiquidation(address user) public view {
(uint256 collateral, uint256 debt) = stablecoin.vaults(user);
if (debt == 0) {
console.log("用户没有活动保险库");
return;
}
uint256 currentRatio = stablecoin.getCurrentRatio(user);
uint256 liquidationThreshold = stablecoin.LIQUIDATION_THRESHOLD();
console.log("当前抵押品:", collateral);
console.log("当前债务:", debt);
console.log("当前比率:", currentRatio);
console.log("清算阈值:", liquidationThreshold);
console.log("可清算:", currentRatio < liquidationThreshold);
}
function liquidatePosition(address user) public {
require(stablecoin.getCurrentRatio(user) < stablecoin.LIQUIDATION_THRESHOLD(), "位置不可清算");
(uint256 collateral, uint256 debt) = stablecoin.vaults(user);
console.log("尝试清算头寸,其抵押品为 %d 和债务 %d", collateral, debt);
vm.broadcast();
stablecoin.liquidate(user);
console.log("头寸成功清算");
}
}
此脚本演示了四个关键的保险库操作:
要使用这些函数,请在项目根目录下运行以下命令:
forge script script/VaultOperations.s.sol:VaultOperations --sig "createAndMint()" \
--rpc-url https://your-quicknode-endpoint \
--private-key your_private_key_here \
--broadcast \
-vvvv
这将创建一个带有 0.1 ETH 抵押的保险库(最低要求金额),并根据当前 ETH 价格(即铸造的代币数量将取决于 ETH 的价格)和抵押比率铸造最大安全金额的 sUSD。
示例交易。
还款金额需要用 wei 指定。以下示例显示了 1 sUSD 的部分还款(1e18 wei)。要获取全部抵押品,你需要偿还完整的债务金额。
forge script script/VaultOperations.s.sol:VaultOperations --sig "repayAndWithdraw(uint256)" 1000000000000000000 \
--rpc-url https://your-quicknode-endpoint \
--private-key your_private_key_here \
--broadcast \
-vvvv
这将还清未偿债务,并在如果债务完全偿还的情况下返回你的抵押品。
示例交易。
forge script script/VaultOperations.s.sol:VaultOperations --sig "checkLiquidation(address)" "TARGET_ADDRESS" \
--rpc-url https://your-quicknode-endpoint \
-vvvv
示例输出:
脚本成功运行。
== 日志 ==
当前抵押品: 100000000000000000
当前债务: 178447799885333333333
当前比率: 15084
清算阈值: 13000
可清算: false
这显示了保险库的当前健康状况,包括抵押比率和清算风险。
forge script script/VaultOperations.s.sol:VaultOperations --sig "liquidatePosition(address)" "TARGET_ADDRESS" \
--rpc-url https://your-quicknode-endpoint \
--private-key your_private_key_here \
--broadcast \
-vvvv
这将清算已降到清算阈值以下的保险库。
示例交易(请注意,此合约使用不同的参数以模拟清算)
信息
请记住:
YOUR_CONTRACT_ADDRESS
your-quicknode-endpoint
TARGET_ADDRESS
替换为你想要清算的保险库的地址如果你想看到此指南的第二部分,涵盖上述一些后续步骤,请在下面留下反馈!
就是这样!我们刚刚向你展示了如何使用 Foundry 创建自己的简单超额抵押稳定币进行智能合约开发和测试。
如果你有任何问题或需要帮助,请随时通过我们的 Discord 或 Twitter 联系我们。
让我们知道 如果你有任何反馈或新主题的请求。我们很想听到你的想法。
- 原文链接: quicknode.com/guides/eth...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!