update lending contract
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -27,7 +27,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;
|
||||||
|
|||||||
@@ -50,8 +50,7 @@ contract Configurator is
|
|||||||
Configuration memory oldConfiguration = configuratorParams[lendingProxy];
|
Configuration memory oldConfiguration = configuratorParams[lendingProxy];
|
||||||
|
|
||||||
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();
|
||||||
|
|
||||||
delete configuratorParams[lendingProxy];
|
delete configuratorParams[lendingProxy];
|
||||||
@@ -67,7 +66,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;
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,6 @@ contract Lending is
|
|||||||
borrowPerSecondInterestRateBase = uint64(config.borrowPerYearInterestRateBase / SECONDS_PER_YEAR);
|
borrowPerSecondInterestRateBase = uint64(config.borrowPerYearInterestRateBase / SECONDS_PER_YEAR);
|
||||||
|
|
||||||
storeFrontPriceFactor = config.storeFrontPriceFactor;
|
storeFrontPriceFactor = config.storeFrontPriceFactor;
|
||||||
trackingIndexScale = config.trackingIndexScale;
|
|
||||||
baseBorrowMin = config.baseBorrowMin;
|
baseBorrowMin = config.baseBorrowMin;
|
||||||
targetReserves = config.targetReserves;
|
targetReserves = config.targetReserves;
|
||||||
|
|
||||||
@@ -211,36 +210,6 @@ contract Lending is
|
|||||||
emit WithdrawCollateral(msg.sender, msg.sender, asset, amount);
|
emit WithdrawCollateral(msg.sender, msg.sender, asset, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
function _absorbInternal(address absorber, address borrower) internal {
|
function _absorbInternal(address absorber, address borrower) internal {
|
||||||
if (!isLiquidatable(borrower)) revert NotLiquidatable();
|
if (!isLiquidatable(borrower)) revert NotLiquidatable();
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ contract LendingConfiguration {
|
|||||||
uint64 borrowPerYearInterestRateBase; // 借款基础利率
|
uint64 borrowPerYearInterestRateBase; // 借款基础利率
|
||||||
|
|
||||||
uint64 storeFrontPriceFactor; // 清算价格折扣
|
uint64 storeFrontPriceFactor; // 清算价格折扣
|
||||||
uint64 trackingIndexScale; // 追踪索引比例
|
|
||||||
uint104 baseBorrowMin; // 最小借款额
|
uint104 baseBorrowMin; // 最小借款额
|
||||||
uint104 targetReserves; // 目标储备金
|
uint104 targetReserves; // 目标储备金
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ abstract contract LendingStorage is LendingConfiguration {
|
|||||||
uint64 public borrowPerSecondInterestRateBase;
|
uint64 public borrowPerSecondInterestRateBase;
|
||||||
|
|
||||||
uint64 public storeFrontPriceFactor;
|
uint64 public storeFrontPriceFactor;
|
||||||
uint64 public trackingIndexScale;
|
|
||||||
uint104 public baseBorrowMin;
|
uint104 public baseBorrowMin;
|
||||||
uint104 public targetReserves;
|
uint104 public targetReserves;
|
||||||
|
|
||||||
|
|||||||
@@ -602,7 +602,7 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 5. 借款流程(Borrow)
|
## 5. 借款流程(Withdraw,如果余额不足会自动借款)
|
||||||
|
|
||||||
```
|
```
|
||||||
┌─────────────────────────────────────────────────────────────────────┐
|
┌─────────────────────────────────────────────────────────────────────┐
|
||||||
@@ -614,12 +614,12 @@
|
|||||||
│ 计划: 借款 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) │
|
||||||
@@ -1824,7 +1824,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":"0x608080604052346013576039908160188239f35b5f80fdfe5f80fdfea2646970667358221220b04c3c7a0eacf47d0507fbb0a0a2dcb975a2a0626145dd2c26e6cc0eba61456664736f6c634300081e0033","sourceMap":"57:1677:11:-:0;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x5f80fdfea2646970667358221220b04c3c7a0eacf47d0507fbb0a0a2dcb975a2a0626145dd2c26e6cc0eba61456664736f6c634300081e0033","sourceMap":"57:1677:11:-:0;;","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"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\":\"0xad0926447becfa7fd4d742ab3e8e30eba2913a991e2dff6362ccabdf67af3220\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://a7f540e927a359c0196a7e0385c1684f31cad5ec5d75143e6c869327d95ea436\",\"dweb:/ipfs/QmfExMH3ajtieteArNbCgnNFFqybz2k7WCm2AR6yheD6TG\"]}},\"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":"0xad0926447becfa7fd4d742ab3e8e30eba2913a991e2dff6362ccabdf67af3220","urls":["bzz-raw://a7f540e927a359c0196a7e0385c1684f31cad5ec5d75143e6c869327d95ea436","dweb:/ipfs/QmfExMH3ajtieteArNbCgnNFFqybz2k7WCm2AR6yheD6TG"],"license":"MIT"}},"version":1},"id":11}
|
{"abi":[],"bytecode":{"object":"0x608080604052346013576039908160188239f35b5f80fdfe5f80fdfea2646970667358221220f8112b2e9d03bdb94e5e5cd9ad0c208785a05e855bbd3fb5fb6de208e49fa01864736f6c634300081e0033","sourceMap":"57:1599:11:-:0;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x5f80fdfea2646970667358221220f8112b2e9d03bdb94e5e5cd9ad0c208785a05e855bbd3fb5fb6de208e49fa01864736f6c634300081e0033","sourceMap":"57:1599:11:-:0;;","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"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\":\"0x5bc25b91410dd160bbb8d141b079b269b82677dab41b65742ae757df6da889bd\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://d721d8b4c60e7f495586426d71fc9d03c8c2615f0005b90d2a3d85ef1a7ae3b9\",\"dweb:/ipfs/QmTBUTpF22QVJYYF6f72bqBWKvdgj8ottEVc2QXgVBcYnk\"]}},\"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":"0x5bc25b91410dd160bbb8d141b079b269b82677dab41b65742ae757df6da889bd","urls":["bzz-raw://d721d8b4c60e7f495586426d71fc9d03c8c2615f0005b90d2a3d85ef1a7ae3b9","dweb:/ipfs/QmTBUTpF22QVJYYF6f72bqBWKvdgj8ottEVc2QXgVBcYnk"],"license":"MIT"}},"version":1},"id":11}
|
||||||
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/f52e10224748efca.json
Normal file
1
out/build-info/f52e10224748efca.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"id":"f52e10224748efca","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"}
|
||||||
@@ -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