update lending contract
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -31,7 +31,6 @@ interface ILending {
|
|||||||
function withdraw(uint256 amount) external;
|
function withdraw(uint256 amount) external;
|
||||||
function supplyCollateral(address asset, uint256 amount) external;
|
function supplyCollateral(address asset, uint256 amount) external;
|
||||||
function withdrawCollateral(address asset, uint256 amount) external;
|
function withdrawCollateral(address asset, uint256 amount) external;
|
||||||
function borrow(uint256 amount) external;
|
|
||||||
function absorb(address borrower) external;
|
function absorb(address borrower) external;
|
||||||
function absorbMultiple(address absorber, address[] calldata accounts) external;
|
function absorbMultiple(address absorber, address[] calldata accounts) external;
|
||||||
function buyCollateral(address asset, uint256 minAmount, uint256 baseAmount, address recipient) external;
|
function buyCollateral(address asset, uint256 minAmount, uint256 baseAmount, address recipient) external;
|
||||||
|
|||||||
@@ -68,8 +68,7 @@ contract Configurator is
|
|||||||
|
|
||||||
// 防止修改不可变参数
|
// 防止修改不可变参数
|
||||||
if (oldConfiguration.baseToken != address(0) &&
|
if (oldConfiguration.baseToken != address(0) &&
|
||||||
(oldConfiguration.baseToken != newConfiguration.baseToken ||
|
oldConfiguration.baseToken != newConfiguration.baseToken)
|
||||||
oldConfiguration.trackingIndexScale != newConfiguration.trackingIndexScale))
|
|
||||||
revert ConfigurationAlreadyExists();
|
revert ConfigurationAlreadyExists();
|
||||||
|
|
||||||
// 删除旧的资产配置
|
// 删除旧的资产配置
|
||||||
@@ -87,7 +86,6 @@ contract Configurator is
|
|||||||
configuratorParams[lendingProxy].borrowPerYearInterestRateSlopeHigh = newConfiguration.borrowPerYearInterestRateSlopeHigh;
|
configuratorParams[lendingProxy].borrowPerYearInterestRateSlopeHigh = newConfiguration.borrowPerYearInterestRateSlopeHigh;
|
||||||
configuratorParams[lendingProxy].borrowPerYearInterestRateBase = newConfiguration.borrowPerYearInterestRateBase;
|
configuratorParams[lendingProxy].borrowPerYearInterestRateBase = newConfiguration.borrowPerYearInterestRateBase;
|
||||||
configuratorParams[lendingProxy].storeFrontPriceFactor = newConfiguration.storeFrontPriceFactor;
|
configuratorParams[lendingProxy].storeFrontPriceFactor = newConfiguration.storeFrontPriceFactor;
|
||||||
configuratorParams[lendingProxy].trackingIndexScale = newConfiguration.trackingIndexScale;
|
|
||||||
configuratorParams[lendingProxy].baseBorrowMin = newConfiguration.baseBorrowMin;
|
configuratorParams[lendingProxy].baseBorrowMin = newConfiguration.baseBorrowMin;
|
||||||
configuratorParams[lendingProxy].targetReserves = newConfiguration.targetReserves;
|
configuratorParams[lendingProxy].targetReserves = newConfiguration.targetReserves;
|
||||||
|
|
||||||
|
|||||||
@@ -63,7 +63,6 @@ contract Lending is
|
|||||||
|
|
||||||
// 设置其他参数
|
// 设置其他参数
|
||||||
storeFrontPriceFactor = config.storeFrontPriceFactor;
|
storeFrontPriceFactor = config.storeFrontPriceFactor;
|
||||||
trackingIndexScale = config.trackingIndexScale;
|
|
||||||
baseBorrowMin = config.baseBorrowMin;
|
baseBorrowMin = config.baseBorrowMin;
|
||||||
targetReserves = config.targetReserves;
|
targetReserves = config.targetReserves;
|
||||||
|
|
||||||
@@ -268,49 +267,6 @@ contract Lending is
|
|||||||
emit WithdrawCollateral(msg.sender, msg.sender, asset, amount);
|
emit WithdrawCollateral(msg.sender, msg.sender, asset, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @notice 借款
|
|
||||||
* @dev baseBorrowMin 是用户借款的最小金额,如果用户借款后,余额小于 baseBorrowMin(由正数变为负数同理),则抛出 BorrowTooSmall 错误
|
|
||||||
*/
|
|
||||||
function borrow(uint256 amount) external override nonReentrant whenNotPaused {
|
|
||||||
accrueInterest();
|
|
||||||
|
|
||||||
// 获取用户当前本金
|
|
||||||
UserBasic memory user = userBasic[msg.sender];
|
|
||||||
int104 oldPrincipal = user.principal;
|
|
||||||
|
|
||||||
// 计算当前实际余额(含利息)
|
|
||||||
uint256 index = oldPrincipal >= 0 ? supplyIndex : borrowIndex;
|
|
||||||
int256 oldBalance = LendingMath.principalToBalance(oldPrincipal, index);
|
|
||||||
|
|
||||||
// 计算新余额(减去借款额)
|
|
||||||
int256 newBalance = oldBalance - int256(amount);
|
|
||||||
|
|
||||||
// 检查最小借款额
|
|
||||||
if (newBalance < 0 && uint256(-newBalance) < baseBorrowMin) revert BorrowTooSmall();
|
|
||||||
|
|
||||||
// 转换为新本金(新状态可能从存款变为借款)
|
|
||||||
uint256 newIndex = newBalance >= 0 ? supplyIndex : borrowIndex;
|
|
||||||
int104 newPrincipal = LendingMath.balanceToPrincipal(newBalance, newIndex);
|
|
||||||
|
|
||||||
// 计算提取和借款金额
|
|
||||||
(uint104 withdrawAmount, uint104 borrowAmount) = LendingMath.withdrawAndBorrowAmount(oldPrincipal, newPrincipal);
|
|
||||||
|
|
||||||
// 更新全局状态
|
|
||||||
totalSupplyBase -= withdrawAmount;
|
|
||||||
totalBorrowBase += borrowAmount;
|
|
||||||
|
|
||||||
// 更新用户本金,方便检查更新后的用户本金是否大于还是小于抵押品价值
|
|
||||||
userBasic[msg.sender].principal = newPrincipal;
|
|
||||||
|
|
||||||
// 检查抵押品是否充足
|
|
||||||
if (!_isSolvent(msg.sender)) revert InsufficientCollateral();
|
|
||||||
|
|
||||||
IERC20(baseToken).safeTransfer(msg.sender, amount);
|
|
||||||
|
|
||||||
emit Withdraw(msg.sender, msg.sender, amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @notice 清算不良债务(内部实现)
|
* @notice 清算不良债务(内部实现)
|
||||||
* @dev 当用户抵押品由于乘以liquidateCollateralFactor后,小于债务价值时,会进行清算,清算后,如果实际抵押品价值乘以liquidateCollateralFactor大于债务价值,则将差额部分作为用户本金(本金以baseToken显示),否则将差额部分作为坏账,由协议承担
|
* @dev 当用户抵押品由于乘以liquidateCollateralFactor后,小于债务价值时,会进行清算,清算后,如果实际抵押品价值乘以liquidateCollateralFactor大于债务价值,则将差额部分作为用户本金(本金以baseToken显示),否则将差额部分作为坏账,由协议承担
|
||||||
@@ -338,7 +294,7 @@ contract Lending is
|
|||||||
AssetConfig memory assetConfig = assetConfigs[asset];
|
AssetConfig memory assetConfig = assetConfigs[asset];
|
||||||
uint256 assetPrice = IYTLendingPriceFeed(lendingPriceSource).getPrice(asset);
|
uint256 assetPrice = IYTLendingPriceFeed(lendingPriceSource).getPrice(asset);
|
||||||
|
|
||||||
// 计算抵押品价值(USD,8位精度)- 用于事件记录
|
// 计算抵押品价值-用于事件记录
|
||||||
uint256 assetScale = 10 ** assetConfig.decimals;
|
uint256 assetScale = 10 ** assetConfig.decimals;
|
||||||
uint256 collateralValueUSD = (collateralAmount * assetPrice) / assetScale;
|
uint256 collateralValueUSD = (collateralAmount * assetPrice) / assetScale;
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ contract LendingConfiguration {
|
|||||||
|
|
||||||
// 其他核心参数
|
// 其他核心参数
|
||||||
uint64 storeFrontPriceFactor; // 清算价格折扣
|
uint64 storeFrontPriceFactor; // 清算价格折扣
|
||||||
uint64 trackingIndexScale; // 追踪索引比例
|
|
||||||
uint104 baseBorrowMin; // 最小借款额
|
uint104 baseBorrowMin; // 最小借款额
|
||||||
uint104 targetReserves; // 目标储备金
|
uint104 targetReserves; // 目标储备金
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ abstract contract LendingStorage is LendingConfiguration {
|
|||||||
|
|
||||||
// 清算参数
|
// 清算参数
|
||||||
uint64 public storeFrontPriceFactor;
|
uint64 public storeFrontPriceFactor;
|
||||||
uint64 public trackingIndexScale;
|
|
||||||
uint104 public baseBorrowMin;
|
uint104 public baseBorrowMin;
|
||||||
uint104 public targetReserves;
|
uint104 public targetReserves;
|
||||||
|
|
||||||
|
|||||||
@@ -614,15 +614,16 @@
|
|||||||
│ 计划: 借款 1,000,000 USDC │
|
│ 计划: 借款 1,000,000 USDC │
|
||||||
└────────────────────────────┬────────────────────────────────────────┘
|
└────────────────────────────┬────────────────────────────────────────┘
|
||||||
│
|
│
|
||||||
│ 1. 调用 borrow(1000000e6)
|
│ 1. 调用 withdraw(1000000e6) 进行借款
|
||||||
▼
|
▼
|
||||||
┌─────────────────────────────────────────────────────────────────────┐
|
┌─────────────────────────────────────────────────────────────────────┐
|
||||||
│ Lending.borrow() │
|
│ Lending.withdraw() │
|
||||||
│ ───────────────────────────────────────────────────────────────── │
|
│ ───────────────────────────────────────────────────────────────── │
|
||||||
│ function borrow(uint256 amount) │
|
│ function withdraw(uint256 amount) │
|
||||||
│ • 非重入保护: nonReentrant │
|
│ • 非重入保护: nonReentrant │
|
||||||
│ • 暂停检查: whenNotPaused │
|
│ • 暂停检查: whenNotPaused │
|
||||||
│ • 参数: 1,000,000 USDC (1000000e6) │
|
│ • 参数: 1,000,000 USDC (1000000e6) │
|
||||||
|
│ • 注: withdraw 会自动处理借款逻辑 │
|
||||||
└────────────────────────────┬────────────────────────────────────────┘
|
└────────────────────────────┬────────────────────────────────────────┘
|
||||||
│
|
│
|
||||||
│ 2. 计提利息
|
│ 2. 计提利息
|
||||||
@@ -1824,7 +1825,6 @@ Configuration {
|
|||||||
|
|
||||||
// 清算参数
|
// 清算参数
|
||||||
storeFrontPriceFactor: 0.95e18 // 清算购买折扣 5%
|
storeFrontPriceFactor: 0.95e18 // 清算购买折扣 5%
|
||||||
trackingIndexScale: 1e15 // 追踪索引比例
|
|
||||||
baseBorrowMin: 100e6 // 最小借款 100 USDC
|
baseBorrowMin: 100e6 // 最小借款 100 USDC
|
||||||
targetReserves: 5000000e6 // 目标储备 500万
|
targetReserves: 5000000e6 // 目标储备 500万
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
|||||||
{"abi":[],"bytecode":{"object":"0x608080604052346013576039908160188239f35b5f80fdfe5f80fdfea264697066735822122077cd1a16fabe0cd560a7f2461fc6b4b68370dcbaef48f0fccf2effe4f34afa2464736f6c634300081e0033","sourceMap":"138:1737:11:-:0;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x5f80fdfea264697066735822122077cd1a16fabe0cd560a7f2461fc6b4b68370dcbaef48f0fccf2effe4f34afa2464736f6c634300081e0033","sourceMap":"138:1737:11:-:0;;","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"title\":\"LendingConfiguration\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"notice\":\"\\u501f\\u8d37\\u6c60\\u914d\\u7f6e\\u7ed3\\u6784\\u4f53\\u5b9a\\u4e49\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/ytLending/LendingConfiguration.sol\":\"LendingConfiguration\"},\"evmVersion\":\"prague\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[\":@arbitrum/=node_modules/@arbitrum/\",\":@chainlink/=node_modules/@chainlink/\",\":@ensdomains/=node_modules/@ensdomains/\",\":@eth-optimism/=node_modules/@chainlink/contracts/node_modules/@eth-optimism/\",\":@offchainlabs/=node_modules/@offchainlabs/\",\":@openzeppelin/=node_modules/@openzeppelin/\",\":@scroll-tech/=node_modules/@scroll-tech/\",\":@zksync/=node_modules/@zksync/\",\":forge-std/=lib/forge-std/src/\",\":hardhat/=node_modules/hardhat/\",\":solady/=node_modules/solady/\"],\"viaIR\":true},\"sources\":{\"contracts/ytLending/LendingConfiguration.sol\":{\"keccak256\":\"0xbf3515c0458645c3423e888c0c38e495daf60de795e2a7a9c3db525d77bfb126\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://d20e885e5a57d63cbe240fdb91d09f073e5886233159096ff151692546cd0d72\",\"dweb:/ipfs/QmYCPvxyYrsLka44r3yi7HBrvfBgsQ3zovbTZCNiHHEy1H\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.30+commit.73712a01"},"language":"Solidity","output":{"abi":[],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"remappings":["@arbitrum/=node_modules/@arbitrum/","@chainlink/=node_modules/@chainlink/","@ensdomains/=node_modules/@ensdomains/","@eth-optimism/=node_modules/@chainlink/contracts/node_modules/@eth-optimism/","@offchainlabs/=node_modules/@offchainlabs/","@openzeppelin/=node_modules/@openzeppelin/","@scroll-tech/=node_modules/@scroll-tech/","@zksync/=node_modules/@zksync/","forge-std/=lib/forge-std/src/","hardhat/=node_modules/hardhat/","solady/=node_modules/solady/"],"optimizer":{"enabled":true,"runs":200},"metadata":{"bytecodeHash":"ipfs"},"compilationTarget":{"contracts/ytLending/LendingConfiguration.sol":"LendingConfiguration"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"contracts/ytLending/LendingConfiguration.sol":{"keccak256":"0xbf3515c0458645c3423e888c0c38e495daf60de795e2a7a9c3db525d77bfb126","urls":["bzz-raw://d20e885e5a57d63cbe240fdb91d09f073e5886233159096ff151692546cd0d72","dweb:/ipfs/QmYCPvxyYrsLka44r3yi7HBrvfBgsQ3zovbTZCNiHHEy1H"],"license":"MIT"}},"version":1},"id":11}
|
{"abi":[],"bytecode":{"object":"0x608080604052346013576039908160188239f35b5f80fdfe5f80fdfea2646970667358221220505f442edb372b2168112b3b658b55a2b06b4abff3ee31fd304124bf154531e564736f6c634300081e0033","sourceMap":"138:1659:6:-:0;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x5f80fdfea2646970667358221220505f442edb372b2168112b3b658b55a2b06b4abff3ee31fd304124bf154531e564736f6c634300081e0033","sourceMap":"138:1659:6:-:0;;","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"title\":\"LendingConfiguration\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"notice\":\"\\u501f\\u8d37\\u6c60\\u914d\\u7f6e\\u7ed3\\u6784\\u4f53\\u5b9a\\u4e49\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/ytLending/LendingConfiguration.sol\":\"LendingConfiguration\"},\"evmVersion\":\"prague\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[\":@arbitrum/=node_modules/@arbitrum/\",\":@chainlink/=node_modules/@chainlink/\",\":@ensdomains/=node_modules/@ensdomains/\",\":@eth-optimism/=node_modules/@chainlink/contracts/node_modules/@eth-optimism/\",\":@offchainlabs/=node_modules/@offchainlabs/\",\":@openzeppelin/=node_modules/@openzeppelin/\",\":@scroll-tech/=node_modules/@scroll-tech/\",\":@zksync/=node_modules/@zksync/\",\":forge-std/=lib/forge-std/src/\",\":hardhat/=node_modules/hardhat/\",\":solady/=node_modules/solady/\"],\"viaIR\":true},\"sources\":{\"contracts/ytLending/LendingConfiguration.sol\":{\"keccak256\":\"0x3c6287a9a4dc044ebc3de6b775de2f8804b527e645eef6f2dcea149541ed4bab\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://8f72c84ef7dbf0f9400c1830fa17e4ecd0205391c58c4b9180641af8e40a92bc\",\"dweb:/ipfs/QmPP3NgAwZHt2SvyfyEiayF7svacWfkXhnX3sJr7xoUNBP\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.30+commit.73712a01"},"language":"Solidity","output":{"abi":[],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"remappings":["@arbitrum/=node_modules/@arbitrum/","@chainlink/=node_modules/@chainlink/","@ensdomains/=node_modules/@ensdomains/","@eth-optimism/=node_modules/@chainlink/contracts/node_modules/@eth-optimism/","@offchainlabs/=node_modules/@offchainlabs/","@openzeppelin/=node_modules/@openzeppelin/","@scroll-tech/=node_modules/@scroll-tech/","@zksync/=node_modules/@zksync/","forge-std/=lib/forge-std/src/","hardhat/=node_modules/hardhat/","solady/=node_modules/solady/"],"optimizer":{"enabled":true,"runs":200},"metadata":{"bytecodeHash":"ipfs"},"compilationTarget":{"contracts/ytLending/LendingConfiguration.sol":"LendingConfiguration"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"contracts/ytLending/LendingConfiguration.sol":{"keccak256":"0x3c6287a9a4dc044ebc3de6b775de2f8804b527e645eef6f2dcea149541ed4bab","urls":["bzz-raw://8f72c84ef7dbf0f9400c1830fa17e4ecd0205391c58c4b9180641af8e40a92bc","dweb:/ipfs/QmPP3NgAwZHt2SvyfyEiayF7svacWfkXhnX3sJr7xoUNBP"],"license":"MIT"}},"version":1},"id":6}
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
out/build-info/059f33eca1d35bb3.json
Normal file
1
out/build-info/059f33eca1d35bb3.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"id":"059f33eca1d35bb3","source_id_to_path":{"0":"contracts/interfaces/ILending.sol","1":"contracts/interfaces/IUSDY.sol","2":"contracts/interfaces/IYTAssetVault.sol","3":"contracts/interfaces/IYTLPToken.sol","4":"contracts/interfaces/IYTLendingPriceFeed.sol","5":"contracts/interfaces/IYTPoolManager.sol","6":"contracts/interfaces/IYTPriceFeed.sol","7":"contracts/interfaces/IYTVault.sol","8":"contracts/ytLending/Configurator.sol","9":"contracts/ytLending/ConfiguratorStorage.sol","10":"contracts/ytLending/Lending.sol","11":"contracts/ytLending/LendingConfiguration.sol","12":"contracts/ytLending/LendingFactory.sol","13":"contracts/ytLending/LendingMath.sol","14":"contracts/ytLending/LendingPriceFeed.sol","15":"contracts/ytLending/LendingStorage.sol","16":"contracts/ytLp/core/YTPoolManager.sol","17":"contracts/ytLp/core/YTPriceFeed.sol","18":"contracts/ytLp/core/YTRewardRouter.sol","19":"contracts/ytLp/core/YTVault.sol","20":"contracts/ytLp/tokens/USDY.sol","21":"contracts/ytLp/tokens/YTLPToken.sol","22":"contracts/ytVault/YTAssetFactory.sol","23":"contracts/ytVault/YTAssetVault.sol","24":"lib/forge-std/src/Base.sol","25":"lib/forge-std/src/StdAssertions.sol","26":"lib/forge-std/src/StdChains.sol","27":"lib/forge-std/src/StdCheats.sol","28":"lib/forge-std/src/StdConstants.sol","29":"lib/forge-std/src/StdError.sol","30":"lib/forge-std/src/StdInvariant.sol","31":"lib/forge-std/src/StdJson.sol","32":"lib/forge-std/src/StdMath.sol","33":"lib/forge-std/src/StdStorage.sol","34":"lib/forge-std/src/StdStyle.sol","35":"lib/forge-std/src/StdToml.sol","36":"lib/forge-std/src/StdUtils.sol","37":"lib/forge-std/src/Test.sol","38":"lib/forge-std/src/Vm.sol","39":"lib/forge-std/src/console.sol","40":"lib/forge-std/src/console2.sol","41":"lib/forge-std/src/interfaces/IMulticall3.sol","42":"lib/forge-std/src/safeconsole.sol","43":"node_modules/@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol","44":"node_modules/@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol","45":"node_modules/@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol","46":"node_modules/@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol","47":"node_modules/@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol","48":"node_modules/@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol","49":"node_modules/@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol","50":"node_modules/@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol","51":"node_modules/@openzeppelin/contracts/access/Ownable.sol","52":"node_modules/@openzeppelin/contracts/interfaces/IERC1363.sol","53":"node_modules/@openzeppelin/contracts/interfaces/IERC165.sol","54":"node_modules/@openzeppelin/contracts/interfaces/IERC1967.sol","55":"node_modules/@openzeppelin/contracts/interfaces/IERC20.sol","56":"node_modules/@openzeppelin/contracts/interfaces/draft-IERC1822.sol","57":"node_modules/@openzeppelin/contracts/interfaces/draft-IERC6093.sol","58":"node_modules/@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol","59":"node_modules/@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol","60":"node_modules/@openzeppelin/contracts/proxy/Proxy.sol","61":"node_modules/@openzeppelin/contracts/proxy/beacon/IBeacon.sol","62":"node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol","63":"node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol","64":"node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol","65":"node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol","66":"node_modules/@openzeppelin/contracts/utils/Address.sol","67":"node_modules/@openzeppelin/contracts/utils/Context.sol","68":"node_modules/@openzeppelin/contracts/utils/Errors.sol","69":"node_modules/@openzeppelin/contracts/utils/StorageSlot.sol","70":"node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol","71":"test/YtLending.t.sol","72":"test/YtLp.t.sol","73":"test/YtVault.t.sol"},"language":"Solidity"}
|
||||||
1
out/build-info/3b7265d3b62873e1.json
Normal file
1
out/build-info/3b7265d3b62873e1.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"id":"3b7265d3b62873e1","source_id_to_path":{"0":"contracts/interfaces/ILending.sol","1":"contracts/interfaces/IYTAssetVault.sol","2":"contracts/interfaces/IYTLendingPriceFeed.sol","3":"contracts/ytLending/Configurator.sol","4":"contracts/ytLending/ConfiguratorStorage.sol","5":"contracts/ytLending/Lending.sol","6":"contracts/ytLending/LendingConfiguration.sol","7":"contracts/ytLending/LendingFactory.sol","8":"contracts/ytLending/LendingMath.sol","9":"contracts/ytLending/LendingPriceFeed.sol","10":"contracts/ytLending/LendingStorage.sol","11":"contracts/ytVault/YTAssetFactory.sol","12":"contracts/ytVault/YTAssetVault.sol","13":"lib/forge-std/src/Base.sol","14":"lib/forge-std/src/StdAssertions.sol","15":"lib/forge-std/src/StdChains.sol","16":"lib/forge-std/src/StdCheats.sol","17":"lib/forge-std/src/StdConstants.sol","18":"lib/forge-std/src/StdError.sol","19":"lib/forge-std/src/StdInvariant.sol","20":"lib/forge-std/src/StdJson.sol","21":"lib/forge-std/src/StdMath.sol","22":"lib/forge-std/src/StdStorage.sol","23":"lib/forge-std/src/StdStyle.sol","24":"lib/forge-std/src/StdToml.sol","25":"lib/forge-std/src/StdUtils.sol","26":"lib/forge-std/src/Test.sol","27":"lib/forge-std/src/Vm.sol","28":"lib/forge-std/src/console.sol","29":"lib/forge-std/src/console2.sol","30":"lib/forge-std/src/interfaces/IMulticall3.sol","31":"lib/forge-std/src/safeconsole.sol","32":"node_modules/@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol","33":"node_modules/@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol","34":"node_modules/@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol","35":"node_modules/@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol","36":"node_modules/@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol","37":"node_modules/@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol","38":"node_modules/@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol","39":"node_modules/@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol","40":"node_modules/@openzeppelin/contracts/access/Ownable.sol","41":"node_modules/@openzeppelin/contracts/interfaces/IERC1363.sol","42":"node_modules/@openzeppelin/contracts/interfaces/IERC165.sol","43":"node_modules/@openzeppelin/contracts/interfaces/IERC1967.sol","44":"node_modules/@openzeppelin/contracts/interfaces/IERC20.sol","45":"node_modules/@openzeppelin/contracts/interfaces/draft-IERC1822.sol","46":"node_modules/@openzeppelin/contracts/interfaces/draft-IERC6093.sol","47":"node_modules/@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol","48":"node_modules/@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol","49":"node_modules/@openzeppelin/contracts/proxy/Proxy.sol","50":"node_modules/@openzeppelin/contracts/proxy/beacon/IBeacon.sol","51":"node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol","52":"node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol","53":"node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol","54":"node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol","55":"node_modules/@openzeppelin/contracts/utils/Address.sol","56":"node_modules/@openzeppelin/contracts/utils/Context.sol","57":"node_modules/@openzeppelin/contracts/utils/Errors.sol","58":"node_modules/@openzeppelin/contracts/utils/StorageSlot.sol","59":"node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol","60":"test/YtLending.t.sol"},"language":"Solidity"}
|
||||||
1
out/build-info/ae1b940c327ca4d8.json
Normal file
1
out/build-info/ae1b940c327ca4d8.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"id":"ae1b940c327ca4d8","source_id_to_path":{"0":"contracts/interfaces/ILending.sol","1":"contracts/interfaces/IYTAssetVault.sol","2":"contracts/interfaces/IYTLendingPriceFeed.sol","3":"contracts/ytLending/Configurator.sol","4":"contracts/ytLending/ConfiguratorStorage.sol","5":"contracts/ytLending/Lending.sol","6":"contracts/ytLending/LendingConfiguration.sol","7":"contracts/ytLending/LendingFactory.sol","8":"contracts/ytLending/LendingMath.sol","9":"contracts/ytLending/LendingPriceFeed.sol","10":"contracts/ytLending/LendingStorage.sol","11":"contracts/ytVault/YTAssetFactory.sol","12":"contracts/ytVault/YTAssetVault.sol","13":"lib/forge-std/src/Base.sol","14":"lib/forge-std/src/StdAssertions.sol","15":"lib/forge-std/src/StdChains.sol","16":"lib/forge-std/src/StdCheats.sol","17":"lib/forge-std/src/StdConstants.sol","18":"lib/forge-std/src/StdError.sol","19":"lib/forge-std/src/StdInvariant.sol","20":"lib/forge-std/src/StdJson.sol","21":"lib/forge-std/src/StdMath.sol","22":"lib/forge-std/src/StdStorage.sol","23":"lib/forge-std/src/StdStyle.sol","24":"lib/forge-std/src/StdToml.sol","25":"lib/forge-std/src/StdUtils.sol","26":"lib/forge-std/src/Test.sol","27":"lib/forge-std/src/Vm.sol","28":"lib/forge-std/src/console.sol","29":"lib/forge-std/src/console2.sol","30":"lib/forge-std/src/interfaces/IMulticall3.sol","31":"lib/forge-std/src/safeconsole.sol","32":"node_modules/@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol","33":"node_modules/@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol","34":"node_modules/@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol","35":"node_modules/@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol","36":"node_modules/@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol","37":"node_modules/@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol","38":"node_modules/@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol","39":"node_modules/@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol","40":"node_modules/@openzeppelin/contracts/access/Ownable.sol","41":"node_modules/@openzeppelin/contracts/interfaces/IERC1363.sol","42":"node_modules/@openzeppelin/contracts/interfaces/IERC165.sol","43":"node_modules/@openzeppelin/contracts/interfaces/IERC1967.sol","44":"node_modules/@openzeppelin/contracts/interfaces/IERC20.sol","45":"node_modules/@openzeppelin/contracts/interfaces/draft-IERC1822.sol","46":"node_modules/@openzeppelin/contracts/interfaces/draft-IERC6093.sol","47":"node_modules/@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol","48":"node_modules/@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol","49":"node_modules/@openzeppelin/contracts/proxy/Proxy.sol","50":"node_modules/@openzeppelin/contracts/proxy/beacon/IBeacon.sol","51":"node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol","52":"node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol","53":"node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol","54":"node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol","55":"node_modules/@openzeppelin/contracts/utils/Address.sol","56":"node_modules/@openzeppelin/contracts/utils/Context.sol","57":"node_modules/@openzeppelin/contracts/utils/Errors.sol","58":"node_modules/@openzeppelin/contracts/utils/StorageSlot.sol","59":"node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol","60":"test/YtLending.t.sol"},"language":"Solidity"}
|
||||||
@@ -104,7 +104,6 @@ async function main() {
|
|||||||
borrowPerYearInterestRateBase: ethers.parseUnits("0.015", 18), // 1.5% 基础
|
borrowPerYearInterestRateBase: ethers.parseUnits("0.015", 18), // 1.5% 基础
|
||||||
|
|
||||||
storeFrontPriceFactor: ethers.parseUnits("0.5", 18), // 50% 清算折扣
|
storeFrontPriceFactor: ethers.parseUnits("0.5", 18), // 50% 清算折扣
|
||||||
trackingIndexScale: ethers.parseUnits("1", 15), // 10^15 比例
|
|
||||||
baseBorrowMin: ethers.parseUnits("100", USDC.decimals), // 最小借 100 USDC
|
baseBorrowMin: ethers.parseUnits("100", USDC.decimals), // 最小借 100 USDC
|
||||||
targetReserves: ethers.parseUnits("5000000", USDC.decimals), // 目标储备 500 万
|
targetReserves: ethers.parseUnits("5000000", USDC.decimals), // 目标储备 500 万
|
||||||
|
|
||||||
|
|||||||
@@ -156,7 +156,6 @@ contract YtLendingTest is Test {
|
|||||||
borrowPerYearInterestRateSlopeHigh: BORROW_RATE_HIGH,
|
borrowPerYearInterestRateSlopeHigh: BORROW_RATE_HIGH,
|
||||||
borrowPerYearInterestRateBase: BORROW_RATE_BASE,
|
borrowPerYearInterestRateBase: BORROW_RATE_BASE,
|
||||||
storeFrontPriceFactor: STORE_FRONT_PRICE_FACTOR,
|
storeFrontPriceFactor: STORE_FRONT_PRICE_FACTOR,
|
||||||
trackingIndexScale: 1e15,
|
|
||||||
baseBorrowMin: uint104(BASE_BORROW_MIN),
|
baseBorrowMin: uint104(BASE_BORROW_MIN),
|
||||||
targetReserves: uint104(TARGET_RESERVES),
|
targetReserves: uint104(TARGET_RESERVES),
|
||||||
assetConfigs: assetConfigs
|
assetConfigs: assetConfigs
|
||||||
@@ -319,7 +318,7 @@ contract YtLendingTest is Test {
|
|||||||
|
|
||||||
// 借款 $16,000 USDC(80% LTV)
|
// 借款 $16,000 USDC(80% LTV)
|
||||||
uint256 borrowAmount = 16000e6;
|
uint256 borrowAmount = 16000e6;
|
||||||
lending.borrow(borrowAmount);
|
lending.withdraw(borrowAmount);
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
|
|
||||||
// 验证
|
// 验证
|
||||||
@@ -335,7 +334,7 @@ contract YtLendingTest is Test {
|
|||||||
// Alice 尝试无抵押借款
|
// Alice 尝试无抵押借款
|
||||||
vm.prank(alice);
|
vm.prank(alice);
|
||||||
vm.expectRevert(ILending.InsufficientCollateral.selector);
|
vm.expectRevert(ILending.InsufficientCollateral.selector);
|
||||||
lending.borrow(1000e6);
|
lending.withdraw(1000e6);
|
||||||
}
|
}
|
||||||
|
|
||||||
function test_09_Borrow_FailBelowMinimum() public {
|
function test_09_Borrow_FailBelowMinimum() public {
|
||||||
@@ -345,7 +344,7 @@ contract YtLendingTest is Test {
|
|||||||
|
|
||||||
// 尝试借款低于最小值 (< 100 USDC)
|
// 尝试借款低于最小值 (< 100 USDC)
|
||||||
vm.expectRevert(ILending.BorrowTooSmall.selector);
|
vm.expectRevert(ILending.BorrowTooSmall.selector);
|
||||||
lending.borrow(50e6);
|
lending.withdraw(50e6);
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -361,7 +360,7 @@ contract YtLendingTest is Test {
|
|||||||
// Bob 存入 10 YTToken,借 8,000 USDC
|
// Bob 存入 10 YTToken,借 8,000 USDC
|
||||||
vm.startPrank(bob);
|
vm.startPrank(bob);
|
||||||
lending.supplyCollateral(address(ytVault), 10e18);
|
lending.supplyCollateral(address(ytVault), 10e18);
|
||||||
lending.borrow(8000e6);
|
lending.withdraw(8000e6);
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
|
|
||||||
// 时间前进 365 天
|
// 时间前进 365 天
|
||||||
@@ -398,7 +397,7 @@ contract YtLendingTest is Test {
|
|||||||
// Bob 借款
|
// Bob 借款
|
||||||
vm.startPrank(bob);
|
vm.startPrank(bob);
|
||||||
lending.supplyCollateral(address(ytVault), 10e18);
|
lending.supplyCollateral(address(ytVault), 10e18);
|
||||||
lending.borrow(8000e6);
|
lending.withdraw(8000e6);
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
|
|
||||||
// 每月触发一次利息累积(模拟复利)
|
// 每月触发一次利息累积(模拟复利)
|
||||||
@@ -426,7 +425,7 @@ contract YtLendingTest is Test {
|
|||||||
// Bob 存入 10 YTToken (价值 $20,000),借 10,000 USDC
|
// Bob 存入 10 YTToken (价值 $20,000),借 10,000 USDC
|
||||||
vm.startPrank(bob);
|
vm.startPrank(bob);
|
||||||
lending.supplyCollateral(address(ytVault), 10e18);
|
lending.supplyCollateral(address(ytVault), 10e18);
|
||||||
lending.borrow(10000e6);
|
lending.withdraw(10000e6);
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
|
|
||||||
// LTV = 50%,健康
|
// LTV = 50%,健康
|
||||||
@@ -441,7 +440,7 @@ contract YtLendingTest is Test {
|
|||||||
// Bob 存入 10 YTToken,借 16,000 USDC(80% LTV)
|
// Bob 存入 10 YTToken,借 16,000 USDC(80% LTV)
|
||||||
vm.startPrank(bob);
|
vm.startPrank(bob);
|
||||||
lending.supplyCollateral(address(ytVault), 10e18);
|
lending.supplyCollateral(address(ytVault), 10e18);
|
||||||
lending.borrow(16000e6);
|
lending.withdraw(16000e6);
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
|
|
||||||
// YTToken 价格暴跌到 $1,800
|
// YTToken 价格暴跌到 $1,800
|
||||||
@@ -463,7 +462,7 @@ contract YtLendingTest is Test {
|
|||||||
// 1. Bob 建立借款头寸
|
// 1. Bob 建立借款头寸
|
||||||
vm.startPrank(bob);
|
vm.startPrank(bob);
|
||||||
lending.supplyCollateral(address(ytVault), 10e18); // 10 YTToken @ $2000 = $20,000
|
lending.supplyCollateral(address(ytVault), 10e18); // 10 YTToken @ $2000 = $20,000
|
||||||
lending.borrow(16000e6); // $16,000(80% LTV)
|
lending.withdraw(16000e6); // $16,000(80% LTV)
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
|
|
||||||
// 2. 计算精确的清算价格(1e30 精度)
|
// 2. 计算精确的清算价格(1e30 精度)
|
||||||
@@ -507,7 +506,7 @@ contract YtLendingTest is Test {
|
|||||||
// 1. Bob 建立不良头寸
|
// 1. Bob 建立不良头寸
|
||||||
vm.startPrank(bob);
|
vm.startPrank(bob);
|
||||||
lending.supplyCollateral(address(ytVault), 10e18); // 10 YTToken @ $2000 = $20,000
|
lending.supplyCollateral(address(ytVault), 10e18); // 10 YTToken @ $2000 = $20,000
|
||||||
lending.borrow(16000e6); // $16,000
|
lending.withdraw(16000e6); // $16,000
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
|
|
||||||
// 2. YTToken 价格跌到 $1,750
|
// 2. YTToken 价格跌到 $1,750
|
||||||
@@ -544,12 +543,12 @@ contract YtLendingTest is Test {
|
|||||||
// 1. Bob 和 Charlie 都建立不良头寸
|
// 1. Bob 和 Charlie 都建立不良头寸
|
||||||
vm.startPrank(bob);
|
vm.startPrank(bob);
|
||||||
lending.supplyCollateral(address(ytVault), 10e18);
|
lending.supplyCollateral(address(ytVault), 10e18);
|
||||||
lending.borrow(16000e6);
|
lending.withdraw(16000e6);
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
|
|
||||||
vm.startPrank(charlie);
|
vm.startPrank(charlie);
|
||||||
lending.supplyCollateral(address(ytVault), 5e18);
|
lending.supplyCollateral(address(ytVault), 5e18);
|
||||||
lending.borrow(8000e6);
|
lending.withdraw(8000e6);
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
|
|
||||||
// 2. 价格下跌
|
// 2. 价格下跌
|
||||||
@@ -581,7 +580,7 @@ contract YtLendingTest is Test {
|
|||||||
// 1. 先清算一个账户,产生抵押品库存
|
// 1. 先清算一个账户,产生抵押品库存
|
||||||
vm.startPrank(bob);
|
vm.startPrank(bob);
|
||||||
lending.supplyCollateral(address(ytVault), 10e18);
|
lending.supplyCollateral(address(ytVault), 10e18);
|
||||||
lending.borrow(16000e6);
|
lending.withdraw(16000e6);
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
|
|
||||||
ytFactory.updateVaultPrices(address(ytVault), 1750e30);
|
ytFactory.updateVaultPrices(address(ytVault), 1750e30);
|
||||||
@@ -619,7 +618,7 @@ contract YtLendingTest is Test {
|
|||||||
// 设置清算库存
|
// 设置清算库存
|
||||||
vm.startPrank(bob);
|
vm.startPrank(bob);
|
||||||
lending.supplyCollateral(address(ytVault), 10e18);
|
lending.supplyCollateral(address(ytVault), 10e18);
|
||||||
lending.borrow(16000e6);
|
lending.withdraw(16000e6);
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
|
|
||||||
ytFactory.updateVaultPrices(address(ytVault), 1750e30);
|
ytFactory.updateVaultPrices(address(ytVault), 1750e30);
|
||||||
@@ -649,7 +648,7 @@ contract YtLendingTest is Test {
|
|||||||
// Bob 小额借款
|
// Bob 小额借款
|
||||||
vm.startPrank(bob);
|
vm.startPrank(bob);
|
||||||
lending.supplyCollateral(address(ytVault), 10e18); // 10 YTToken @ $2000 = $20,000
|
lending.supplyCollateral(address(ytVault), 10e18); // 10 YTToken @ $2000 = $20,000
|
||||||
lending.borrow(100e6); // 只借 $100
|
lending.withdraw(100e6); // 只借 $100
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
|
|
||||||
// 让时间流逝以累积利息,增加 reserves
|
// 让时间流逝以累积利息,增加 reserves
|
||||||
@@ -701,7 +700,7 @@ contract YtLendingTest is Test {
|
|||||||
// Bob 借 5,000 USDC
|
// Bob 借 5,000 USDC
|
||||||
vm.startPrank(bob);
|
vm.startPrank(bob);
|
||||||
lending.supplyCollateral(address(ytVault), 10e18);
|
lending.supplyCollateral(address(ytVault), 10e18);
|
||||||
lending.borrow(5000e6);
|
lending.withdraw(5000e6);
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
|
|
||||||
// reserves = balance - totalSupply + totalBorrow
|
// reserves = balance - totalSupply + totalBorrow
|
||||||
@@ -719,7 +718,7 @@ contract YtLendingTest is Test {
|
|||||||
|
|
||||||
vm.startPrank(bob);
|
vm.startPrank(bob);
|
||||||
lending.supplyCollateral(address(ytVault), 10e18);
|
lending.supplyCollateral(address(ytVault), 10e18);
|
||||||
lending.borrow(8000e6);
|
lending.withdraw(8000e6);
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
|
|
||||||
// 时间流逝
|
// 时间流逝
|
||||||
@@ -746,7 +745,7 @@ contract YtLendingTest is Test {
|
|||||||
|
|
||||||
vm.startPrank(bob);
|
vm.startPrank(bob);
|
||||||
lending.supplyCollateral(address(ytVault), 10e18);
|
lending.supplyCollateral(address(ytVault), 10e18);
|
||||||
lending.borrow(8000e6);
|
lending.withdraw(8000e6);
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
|
|
||||||
vm.warp(block.timestamp + 365 days);
|
vm.warp(block.timestamp + 365 days);
|
||||||
@@ -799,7 +798,7 @@ contract YtLendingTest is Test {
|
|||||||
// Bob 借 8,000 USDC
|
// Bob 借 8,000 USDC
|
||||||
vm.startPrank(bob);
|
vm.startPrank(bob);
|
||||||
lending.supplyCollateral(address(ytVault), 10e18);
|
lending.supplyCollateral(address(ytVault), 10e18);
|
||||||
lending.borrow(8000e6);
|
lending.withdraw(8000e6);
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
|
|
||||||
// 利用率 = 8000 / 10000 = 80%
|
// 利用率 = 8000 / 10000 = 80%
|
||||||
@@ -813,7 +812,7 @@ contract YtLendingTest is Test {
|
|||||||
|
|
||||||
vm.startPrank(bob);
|
vm.startPrank(bob);
|
||||||
lending.supplyCollateral(address(ytVault), 10e18);
|
lending.supplyCollateral(address(ytVault), 10e18);
|
||||||
lending.borrow(5000e6);
|
lending.withdraw(5000e6);
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
|
|
||||||
uint64 supplyRate = lending.getSupplyRate();
|
uint64 supplyRate = lending.getSupplyRate();
|
||||||
@@ -831,7 +830,7 @@ contract YtLendingTest is Test {
|
|||||||
|
|
||||||
vm.startPrank(bob);
|
vm.startPrank(bob);
|
||||||
lending.supplyCollateral(address(ytVault), 10e18);
|
lending.supplyCollateral(address(ytVault), 10e18);
|
||||||
lending.borrow(8000e6);
|
lending.withdraw(8000e6);
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
|
|
||||||
uint64 borrowRate = lending.getBorrowRate();
|
uint64 borrowRate = lending.getBorrowRate();
|
||||||
@@ -869,7 +868,7 @@ contract YtLendingTest is Test {
|
|||||||
lending.supplyCollateral(address(ytVault), 10e18); // $20,000
|
lending.supplyCollateral(address(ytVault), 10e18); // $20,000
|
||||||
|
|
||||||
// 借款 $16,000(正好 80%)
|
// 借款 $16,000(正好 80%)
|
||||||
lending.borrow(16000e6);
|
lending.withdraw(16000e6);
|
||||||
|
|
||||||
// 应该成功
|
// 应该成功
|
||||||
assertEq(lending.borrowBalanceOf(alice), 16000e6, "Should borrow at max LTV");
|
assertEq(lending.borrowBalanceOf(alice), 16000e6, "Should borrow at max LTV");
|
||||||
@@ -887,7 +886,7 @@ contract YtLendingTest is Test {
|
|||||||
|
|
||||||
// 尝试借 $16,001(超过 80%)
|
// 尝试借 $16,001(超过 80%)
|
||||||
vm.expectRevert(ILending.InsufficientCollateral.selector);
|
vm.expectRevert(ILending.InsufficientCollateral.selector);
|
||||||
lending.borrow(16001e6);
|
lending.withdraw(16001e6);
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -899,7 +898,7 @@ contract YtLendingTest is Test {
|
|||||||
// Alice 借款后尝试取出抵押品
|
// Alice 借款后尝试取出抵押品
|
||||||
vm.startPrank(alice);
|
vm.startPrank(alice);
|
||||||
lending.supplyCollateral(address(ytVault), 10e18);
|
lending.supplyCollateral(address(ytVault), 10e18);
|
||||||
lending.borrow(16000e6);
|
lending.withdraw(16000e6);
|
||||||
|
|
||||||
// 尝试取出 1 YTToken 会破坏抵押率
|
// 尝试取出 1 YTToken 会破坏抵押率
|
||||||
vm.expectRevert(ILending.InsufficientCollateral.selector);
|
vm.expectRevert(ILending.InsufficientCollateral.selector);
|
||||||
@@ -929,13 +928,13 @@ contract YtLendingTest is Test {
|
|||||||
// 2. Bob 抵押借款
|
// 2. Bob 抵押借款
|
||||||
vm.startPrank(bob);
|
vm.startPrank(bob);
|
||||||
lending.supplyCollateral(address(ytVault), 20e18); // $40,000
|
lending.supplyCollateral(address(ytVault), 20e18); // $40,000
|
||||||
lending.borrow(30000e6); // 75% LTV
|
lending.withdraw(30000e6); // 75% LTV
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
|
|
||||||
// 3. Charlie 也抵押借款(更激进,容易被清算)
|
// 3. Charlie 也抵押借款(更激进,容易被清算)
|
||||||
vm.startPrank(charlie);
|
vm.startPrank(charlie);
|
||||||
lending.supplyCollateral(address(ytVault), 5e18); // $10,000
|
lending.supplyCollateral(address(ytVault), 5e18); // $10,000
|
||||||
lending.borrow(7900e6); // 79% LTV
|
lending.withdraw(7900e6); // 79% LTV
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
|
|
||||||
// 4. 时间流逝,利息累积
|
// 4. 时间流逝,利息累积
|
||||||
|
|||||||
Reference in New Issue
Block a user