This repository was archived by the owner on Jan 25, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathVaultAdapter.sol
More file actions
110 lines (93 loc) · 4.64 KB
/
Copy pathVaultAdapter.sol
File metadata and controls
110 lines (93 loc) · 4.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.28;
import { Access } from "../../access/Access.sol";
import { IVault } from "../../interfaces/IVault.sol";
import { IVaultAdapter } from "../../interfaces/IVaultAdapter.sol";
import { VaultAdapterStorageUtils } from "../../storage/VaultAdapterStorageUtils.sol";
import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
/// @title Vault Adapter
/// @author kexley, Cap Labs
/// @notice Market rates are sourced from the Vault
contract VaultAdapter is IVaultAdapter, UUPSUpgradeable, Access, VaultAdapterStorageUtils {
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
/// @inheritdoc IVaultAdapter
function initialize(address _accessControl) external initializer {
__Access_init(_accessControl);
__UUPSUpgradeable_init();
}
/// @inheritdoc IVaultAdapter
function rate(address _vault, address _asset) external returns (uint256 latestAnswer) {
UtilizationData storage utilizationData = getVaultAdapterStorage().utilizationData[_vault][_asset];
uint256 elapsed;
uint256 utilization;
if (block.timestamp > utilizationData.lastUpdate) {
uint256 index = IVault(_vault).currentUtilizationIndex(_asset);
elapsed = block.timestamp - utilizationData.lastUpdate;
/// Use average utilization except on the first rate update
if (elapsed != block.timestamp) {
utilization = (index - utilizationData.index) / elapsed;
} else {
utilization = IVault(_vault).utilization(_asset);
}
utilizationData.index = index;
utilizationData.lastUpdate = block.timestamp;
} else {
utilization = IVault(_vault).utilization(_asset);
}
latestAnswer = _applySlopes(_vault, _asset, utilization, elapsed);
}
/// @inheritdoc IVaultAdapter
function setSlopes(address _asset, SlopeData memory _slopes) external checkAccess(this.setSlopes.selector) {
if (_slopes.kink >= 1e27 || _slopes.kink == 0) revert InvalidKink();
getVaultAdapterStorage().slopeData[_asset] = _slopes;
emit SetSlopes(_asset, _slopes);
}
/// @inheritdoc IVaultAdapter
function setLimits(uint256 _maxMultiplier, uint256 _minMultiplier, uint256 _rate)
external
checkAccess(this.setLimits.selector)
{
VaultAdapterStorage storage $ = getVaultAdapterStorage();
$.maxMultiplier = _maxMultiplier;
$.minMultiplier = _minMultiplier;
$.rate = _rate;
emit SetLimits(_maxMultiplier, _minMultiplier, _rate);
}
/// @dev Interest is applied according to where on the slope the current utilization is and the
/// multiplier depends on the duration and distance the utilization is from the kink point.
/// All utilization values, kinks, and multipliers are in ray (1e27)
/// @param _vault Vault address
/// @param _asset Asset address
/// @param _utilization Utilization ratio in ray (1e27)
/// @param _elapsed Length of time at the utilization
/// @return interestRate Interest rate in ray (1e27)
function _applySlopes(address _vault, address _asset, uint256 _utilization, uint256 _elapsed)
internal
returns (uint256 interestRate)
{
VaultAdapterStorage storage $ = getVaultAdapterStorage();
UtilizationData storage utilizationData = $.utilizationData[_vault][_asset];
SlopeData memory slopes = $.slopeData[_asset];
if (_utilization > slopes.kink) {
uint256 excess = _utilization - slopes.kink;
utilizationData.multiplier = utilizationData.multiplier
* (1e27 + (1e27 * excess / (1e27 - slopes.kink)) * (_elapsed * $.rate / 1e27)) / 1e27;
if (utilizationData.multiplier > $.maxMultiplier) {
utilizationData.multiplier = $.maxMultiplier;
}
interestRate = (slopes.slope0 + (slopes.slope1 * excess / 1e27)) * utilizationData.multiplier / 1e27;
} else {
utilizationData.multiplier = utilizationData.multiplier * 1e27
/ (1e27 + (1e27 * (slopes.kink - _utilization) / slopes.kink) * (_elapsed * $.rate / 1e27));
if (utilizationData.multiplier < $.minMultiplier) {
utilizationData.multiplier = $.minMultiplier;
}
interestRate = (slopes.slope0 * _utilization / slopes.kink) * utilizationData.multiplier / 1e27;
}
}
/// @inheritdoc UUPSUpgradeable
function _authorizeUpgrade(address) internal view override checkAccess(bytes4(0)) { }
}