Skip to content

Commit 91dd4ca

Browse files
committed
wip
1 parent 6f8ee1b commit 91dd4ca

File tree

4 files changed

+133
-49
lines changed

4 files changed

+133
-49
lines changed

TODO

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
reserves
2+
hook operations
3+
early repay fees
4+
5+
lens
6+
UI

foundry.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,6 @@ libs = ["lib"]
66
auto_detect_remappings = false
77
solc = "0.8.27"
88
fs_permissions = [{ access = "read-write", path = "./dev-ctx/"}]
9+
10+
[lint]
11+
lint_on_build = false

src/LayerCredit.sol

Lines changed: 101 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,100 +1,152 @@
11
// SPDX-License-Identifier: UNLICENSED
22
pragma solidity ^0.8.27;
33

4-
import {IEVC} from "evc/interfaces/IEthereumVaultConnector.sol";
4+
import {EnumerableSet} from "openzeppelin-contracts/utils/structs/EnumerableSet.sol";
5+
import {EVCUtil} from "evc/utils/EVCUtil.sol";
56
import {IEVault, IERC20} from "evk/EVault/IEVault.sol";
6-
import {IEulerRouterFactory, IEulerRouter} from "./interfaces/Misc.sol";
77
import "evk/EVault/shared/Constants.sol";
88
import {GenericFactory} from "evk/GenericFactory/GenericFactory.sol";
9+
import {IEulerRouterFactory, IEulerRouter} from "./interfaces/Misc.sol";
910
import {StubOracle} from "./StubOracle.sol";
1011

11-
contract LayerCredit {
12+
contract LayerCredit is EVCUtil {
13+
using EnumerableSet for EnumerableSet.AddressSet;
14+
1215
GenericFactory immutable private eVaultFactory;
1316
IEulerRouterFactory immutable private routerFactory;
1417
StubOracle immutable private stubOracle;
1518

1619
address public settingAdmin;
17-
uint16 public settingNumVaultLimit; // Special value of 0 means system sunset (no new bond creation allowed)
18-
uint40 public settingMaxTermDuration;
19-
uint40 public settingReserveMultiplier; // 1e4 scale
20-
uint256 public settlementInterestRate;
20+
uint16 public settingMaxCollaterals = 3; // Special value of 0 means system sunset (no new bond creation allowed)
21+
uint40 public settingMaxTermDuration = 90 days;
22+
uint40 public settingReserveMultiplier = 20e4; // 1e4 scale
23+
uint80 public settingSettlementInterestRate = 21964959992727444861; // 100% APY
2124

22-
constructor(address eVaultFactory_, address routerFactory_, address settingAdmin_) {
25+
mapping(address asset => address escrowVault) public escrowVaults;
26+
27+
constructor(address evc, address eVaultFactory_, address routerFactory_, address settingAdmin_) EVCUtil(evc) {
2328
eVaultFactory = GenericFactory(eVaultFactory_);
2429
routerFactory = IEulerRouterFactory(routerFactory_);
2530
stubOracle = new StubOracle();
2631

2732
settingAdmin = settingAdmin_;
28-
settingNumVaultLimit = 4;
29-
settingMaxTermDuration = 90 days;
30-
settingReserveMultiplier = 20e4;
31-
settlementInterestRate = 21964959992727444861; // 100% APY
3233
}
3334

34-
struct DeployBondVault {
35+
struct DeployBondCollateral {
3536
address asset;
36-
address oracle;
37-
uint256 interestRate;
38-
address restrictedLender;
39-
address restrictedBorrower;
40-
bool noEarlyRepay;
41-
}
42-
43-
struct DeployBondLTV {
44-
uint256 collateralIndex;
45-
uint256 liabilityIndex;
37+
bool isExternalVault;
4638
uint16 liquidationLTV;
39+
address oracle;
4740
}
4841

4942
struct DeployBondParams {
43+
address asset;
5044
address unitOfAccount;
5145
uint256 termDuration;
52-
uint256 interestFee;
53-
address interestFeeRecipient;
54-
DeployBondVault[] vaults;
55-
DeployBondLTV[] ltvs;
46+
47+
uint80 interestRate;
48+
uint16 interestFee;
49+
address interestFeeReceiver;
50+
51+
address restrictedLender;
52+
address restrictedBorrower;
53+
uint64 earlyRepayPenalty;
54+
55+
DeployBondCollateral[] collaterals;
56+
}
57+
58+
59+
struct BondStorage {
60+
address vault;
61+
uint40 bondId;
62+
uint16 state; // 0 = active, 1 = soft settlement, 2 = hard settlement, 3 = dead
63+
uint40 termEnd;
64+
uint40 termStart;
65+
address restrictedLender;
66+
address restrictedBorrower;
67+
uint40 reserveMultiplier; // 1e4 scale
68+
uint80 settlementInterestRate;
5669
}
5770

71+
mapping(address vault => BondStorage) private bondsByVault;
72+
mapping(uint256 bondId => address vault) private bondsById;
73+
uint256 private nextBondId = 1;
74+
EnumerableSet.AddressSet private activeBonds;
75+
76+
mapping(address vault => mapping(address who => uint256 shares)) reservedShares;
77+
78+
5879
error SystemSunset();
5980
error InvalidTermDuration();
60-
error InvalidNumberOfVaults();
81+
error InvalidNumberOfCollaterals();
6182
error InvalidLTVIndex();
83+
error VaultNotEVCCompatible();
6284

63-
function deployBond(DeployBondParams memory p) external {
64-
require(settingNumVaultLimit != 0, SystemSunset());
85+
function deployBond(DeployBondParams memory p) external returns (address) {
86+
require(settingMaxCollaterals != 0, SystemSunset());
6587
require(p.termDuration <= settingMaxTermDuration, InvalidTermDuration());
6688

67-
require(p.vaults.length >= 2 && p.vaults.length <= settingNumVaultLimit, InvalidNumberOfVaults());
89+
require(p.collaterals.length >= 1 && p.collaterals.length <= settingMaxCollaterals, InvalidNumberOfCollaterals());
6890

6991
IEulerRouter router = IEulerRouter(IEulerRouterFactory(routerFactory).deploy(address(this)));
7092

71-
IEVault[] memory vaults = new IEVault[](p.vaults.length);
93+
IEVault vault = IEVault(GenericFactory(eVaultFactory).createProxy(address(0), true, abi.encodePacked(p.asset, address(router), p.unitOfAccount)));
94+
95+
vault.setInterestRateModel(address(this));
96+
vault.setInterestFee(p.interestFee);
97+
vault.setFeeReceiver(p.interestFeeReceiver);
98+
vault.setHookConfig(address(this), OP_CONVERT_FEES | OP_BORROW | OP_REPAY | OP_REPAY_WITH_SHARES | OP_DEPOSIT | OP_MINT | OP_SKIM | OP_WITHDRAW | OP_REDEEM);
99+
vault.setMaxLiquidationDiscount(0.15e4);
100+
vault.setLiquidationCoolOffTime(1);
72101

73-
for (uint256 i = 0; i < p.vaults.length; i++) {
74-
IEVault vault = vaults[i] = IEVault(GenericFactory(eVaultFactory).createProxy(address(0), true, abi.encodePacked(p.vaults[i].asset, address(router), p.unitOfAccount)));
102+
for (uint256 i = 0; i < p.collaterals.length; i++) {
103+
IEVault collateralVault;
75104

76-
vault.setInterestRateModel(address(this));
77-
vault.setHookConfig(address(this), OP_CONVERT_FEES | OP_BORROW | OP_REPAY | OP_REPAY_WITH_SHARES | OP_DEPOSIT | OP_MINT | OP_SKIM | OP_VAULT_STATUS_CHECK);
78-
vault.setMaxLiquidationDiscount(0.15e4);
79-
vault.setLiquidationCoolOffTime(1);
105+
if (p.collaterals[i].isExternalVault) {
106+
collateralVault = IEVault(p.collaterals[i].asset);
107+
require(collateralVault.EVC() == address(evc), VaultNotEVCCompatible());
108+
} else {
109+
collateralVault = getEscrowVault(p.collaterals[i].asset);
110+
}
80111

81112
router.govSetResolvedVault(address(vault), true);
82-
router.govSetConfig(p.vaults[i].asset, p.unitOfAccount, address(stubOracle));
113+
114+
router.govSetConfig(collateralVault.asset(), p.unitOfAccount, address(stubOracle));
115+
vault.setLTV(address(collateralVault), uint16(p.collaterals[i].liquidationLTV * 0.98e18 / 1e18), p.collaterals[i].liquidationLTV, 0);
116+
router.govSetConfig(collateralVault.asset(), p.unitOfAccount, p.collaterals[i].oracle);
83117
}
84118

85-
for (uint256 i = 0; i < p.ltvs.length; i++) {
86-
require(p.ltvs[i].collateralIndex < p.vaults.length, InvalidLTVIndex());
87-
require(p.ltvs[i].liabilityIndex < p.vaults.length, InvalidLTVIndex());
119+
router.transferGovernance(address(0));
120+
vault.setGovernorAdmin(address(0));
121+
122+
bondsByVault[address(vault)] = BondStorage({
123+
vault: address(vault),
124+
bondId: uint40(nextBondId),
125+
termEnd: uint40(block.timestamp + p.termDuration),
126+
termStart: uint40(block.timestamp),
127+
restrictedLender: p.restrictedLender,
128+
restrictedBorrower: p.restrictedBorrower,
129+
reserveMultiplier: settingReserveMultiplier,
130+
settlementInterestRate: settingSettlementInterestRate
131+
});
88132

89-
vaults[p.ltvs[i].liabilityIndex].setLTV(address(vaults[p.ltvs[i].collateralIndex]), uint16(p.ltvs[i].liquidationLTV * 0.98e18 / 1e18), p.ltvs[i].liquidationLTV, 0);
90-
}
133+
bondsById[nextBondId] = address(vault);
91134

92-
// Install final oracles
135+
activeBonds.add(address(vault));
93136

94-
for (uint256 i = 0; i < p.vaults.length; i++) {
95-
router.govSetConfig(p.vaults[i].asset, p.unitOfAccount, p.vaults[i].oracle);
96-
}
137+
nextBondId++;
97138

98-
router.transferGovernance(address(0));
139+
return address(vault);
140+
}
141+
142+
function getEscrowVault(address asset) internal returns (IEVault) {
143+
if (escrowVaults[asset] != address(0)) return IEVault(escrowVaults[asset]);
144+
145+
IEVault newEscrow = IEVault(GenericFactory(eVaultFactory).createProxy(address(0), true, abi.encodePacked(asset, address(0), address(0))));
146+
escrowVaults[asset] = address(newEscrow);
147+
148+
newEscrow.setGovernorAdmin(address(0));
149+
150+
return newEscrow;
99151
}
100152
}

src/LayerCreditLens.sol

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity ^0.8.27;
3+
4+
import {IEVC} from "evc/interfaces/IEthereumVaultConnector.sol";
5+
import {IEVault, IERC20} from "evk/EVault/IEVault.sol";
6+
import {RPow} from "evk/EVault/shared/lib/RPow.sol";
7+
import {LayerCredit} from "./LayerCredit.sol";
8+
9+
contract LayerCreditLens {
10+
// vault, bondId, state, termEnd, termStart, flags(restrictedLender, restrictedBorrower), supplyAPY, borrowAPY, supplyCap, collaterals
11+
// 20 + 5 + 1 + 5 + 5 + 1 + 6 + 6 + 2 + N
12+
function activeBonds(address layerCreditAddr) external view returns (bytes[] memory output) {
13+
/*
14+
unchecked {
15+
output = new bytes[](vaults.length);
16+
for (uint256 i; i < vaults.length; ++i) {
17+
IEVault v = IEVault(vaults[i]);
18+
output[i] = abi.encodePacked(v.asset(), v.decimals(), v.symbol());
19+
}
20+
}
21+
*/
22+
}
23+
}

0 commit comments

Comments
 (0)