-
Notifications
You must be signed in to change notification settings - Fork 28
Expand file tree
/
Copy pathCompoundERC4626Factory.sol
More file actions
123 lines (101 loc) · 4.69 KB
/
CompoundERC4626Factory.sol
File metadata and controls
123 lines (101 loc) · 4.69 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
111
112
113
114
115
116
117
118
119
120
121
122
123
// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.13;
import {ERC20} from "solmate/tokens/ERC20.sol";
import {ERC4626} from "solmate/mixins/ERC4626.sol";
import {ICERC20} from "./external/ICERC20.sol";
import {CompoundERC4626} from "./CompoundERC4626.sol";
import {IComptroller} from "./external/IComptroller.sol";
import {ERC4626Factory} from "../base/ERC4626Factory.sol";
/// @title CompoundERC4626Factory
/// @author zefram.eth
/// @notice Factory for creating CompoundERC4626 contracts
contract CompoundERC4626Factory is ERC4626Factory {
/// -----------------------------------------------------------------------
/// Errors
/// -----------------------------------------------------------------------
/// @notice Thrown when trying to deploy an CompoundERC4626 vault using an asset without a cToken
error CompoundERC4626Factory__CTokenNonexistent();
/// -----------------------------------------------------------------------
/// Immutable params
/// -----------------------------------------------------------------------
/// @notice The COMP token contract
ERC20 public immutable comp;
/// @notice The address that will receive the liquidity mining rewards (if any)
address public immutable rewardRecipient;
/// @notice The Compound comptroller contract
IComptroller public immutable comptroller;
/// @notice The Compound cEther address
address internal immutable cEtherAddress;
/// -----------------------------------------------------------------------
/// Storage variables
/// -----------------------------------------------------------------------
/// @notice Maps underlying asset to the corresponding cToken
mapping(ERC20 => ICERC20) public underlyingToCToken;
/// -----------------------------------------------------------------------
/// Constructor
/// -----------------------------------------------------------------------
constructor(IComptroller comptroller_, address cEtherAddress_, address rewardRecipient_) {
comptroller = comptroller_;
cEtherAddress = cEtherAddress_;
rewardRecipient = rewardRecipient_;
comp = ERC20(comptroller_.getCompAddress());
// initialize underlyingToCToken
ICERC20[] memory allCTokens = comptroller_.getAllMarkets();
uint256 numCTokens = allCTokens.length;
ICERC20 cToken;
for (uint256 i; i < numCTokens;) {
cToken = allCTokens[i];
if (address(cToken) != cEtherAddress_) {
underlyingToCToken[cToken.underlying()] = cToken;
}
unchecked {
++i;
}
}
}
/// -----------------------------------------------------------------------
/// External functions
/// -----------------------------------------------------------------------
/// @inheritdoc ERC4626Factory
function createERC4626(ERC20 asset) external virtual override returns (ERC4626 vault) {
ICERC20 cToken = underlyingToCToken[asset];
if (address(cToken) == address(0)) {
revert CompoundERC4626Factory__CTokenNonexistent();
}
vault = new CompoundERC4626{salt: bytes32(0)}(asset, comp, cToken, rewardRecipient, comptroller);
emit CreateERC4626(asset, vault);
}
/// @inheritdoc ERC4626Factory
function computeERC4626Address(ERC20 asset) external view virtual override returns (ERC4626 vault) {
vault = ERC4626(
_computeCreate2Address(
keccak256(
abi.encodePacked(
// Deployment bytecode:
type(CompoundERC4626).creationCode,
// Constructor arguments:
abi.encode(asset, comp, underlyingToCToken[asset], rewardRecipient, comptroller)
)
)
)
);
}
/// @notice Updates the underlyingToCToken mapping in order to support newly added cTokens
/// @dev This is needed because Compound doesn't have an onchain registry of cTokens corresponding to underlying assets.
/// @param newCTokenIndices The indices of the new cTokens to register in the comptroller.allMarkets array
function updateUnderlyingToCToken(uint256[] calldata newCTokenIndices) external {
uint256 numCTokens = newCTokenIndices.length;
ICERC20 cToken;
uint256 index;
for (uint256 i; i < numCTokens;) {
index = newCTokenIndices[i];
cToken = comptroller.allMarkets(index);
if (address(cToken) != cEtherAddress) {
underlyingToCToken[cToken.underlying()] = cToken;
}
unchecked {
++i;
}
}
}
}