generated from ZeframLou/foundry-template
-
Notifications
You must be signed in to change notification settings - Fork 29
/
CompoundERC4626.sol
160 lines (127 loc) · 6.13 KB
/
CompoundERC4626.sol
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// 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 {SafeTransferLib} from "solmate/utils/SafeTransferLib.sol";
import {ICERC20} from "./external/ICERC20.sol";
import {LibCompound} from "./lib/LibCompound.sol";
import {IComptroller} from "./external/IComptroller.sol";
/// @title CompoundERC4626
/// @author zefram.eth
/// @notice ERC4626 wrapper for Compound Finance
contract CompoundERC4626 is ERC4626 {
/// -----------------------------------------------------------------------
/// Libraries usage
/// -----------------------------------------------------------------------
using LibCompound for ICERC20;
using SafeTransferLib for ERC20;
/// -----------------------------------------------------------------------
/// Events
/// -----------------------------------------------------------------------
event ClaimRewards(uint256 amount);
/// -----------------------------------------------------------------------
/// Errors
/// -----------------------------------------------------------------------
/// @notice Thrown when a call to Compound returned an error.
/// @param errorCode The error code returned by Compound
error CompoundERC4626__CompoundError(uint256 errorCode);
/// -----------------------------------------------------------------------
/// Constants
/// -----------------------------------------------------------------------
uint256 internal constant NO_ERROR = 0;
/// -----------------------------------------------------------------------
/// Immutable params
/// -----------------------------------------------------------------------
/// @notice The COMP token contract
ERC20 public immutable comp;
/// @notice The Compound cToken contract
ICERC20 public immutable cToken;
/// @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;
/// -----------------------------------------------------------------------
/// Constructor
/// -----------------------------------------------------------------------
constructor(ERC20 asset_, ERC20 comp_, ICERC20 cToken_, address rewardRecipient_, IComptroller comptroller_)
ERC4626(asset_, _vaultName(asset_), _vaultSymbol(asset_))
{
comp = comp_;
cToken = cToken_;
comptroller = comptroller_;
rewardRecipient = rewardRecipient_;
}
/// -----------------------------------------------------------------------
/// Compound liquidity mining
/// -----------------------------------------------------------------------
/// @notice Claims liquidity mining rewards from Compound and sends it to rewardRecipient
function claimRewards() external {
address[] memory holders = new address[](1);
holders[0] = address(this);
ICERC20[] memory cTokens = new ICERC20[](1);
cTokens[0] = cToken;
comptroller.claimComp(holders, cTokens, false, true);
uint256 amount = comp.balanceOf(address(this));
comp.safeTransfer(rewardRecipient, amount);
emit ClaimRewards(amount);
}
/// -----------------------------------------------------------------------
/// ERC4626 overrides
/// -----------------------------------------------------------------------
function totalAssets() public view virtual override returns (uint256) {
return cToken.viewUnderlyingBalanceOf(address(this));
}
function beforeWithdraw(uint256 assets, uint256 /*shares*/ ) internal virtual override {
/// -----------------------------------------------------------------------
/// Withdraw assets from Compound
/// -----------------------------------------------------------------------
uint256 errorCode = cToken.redeemUnderlying(assets);
if (errorCode != NO_ERROR) {
revert CompoundERC4626__CompoundError(errorCode);
}
}
function afterDeposit(uint256 assets, uint256 /*shares*/ ) internal virtual override {
/// -----------------------------------------------------------------------
/// Deposit assets into Compound
/// -----------------------------------------------------------------------
// approve to cToken
asset.safeApprove(address(cToken), assets);
// deposit into cToken
uint256 errorCode = cToken.mint(assets);
if (errorCode != NO_ERROR) {
revert CompoundERC4626__CompoundError(errorCode);
}
}
function maxDeposit(address) public view override returns (uint256) {
if (comptroller.mintGuardianPaused(cToken)) {
return 0;
}
return type(uint256).max;
}
function maxMint(address) public view override returns (uint256) {
if (comptroller.mintGuardianPaused(cToken)) {
return 0;
}
return type(uint256).max;
}
function maxWithdraw(address owner) public view override returns (uint256) {
uint256 cash = cToken.getCash();
uint256 assetsBalance = convertToAssets(balanceOf[owner]);
return cash < assetsBalance ? cash : assetsBalance;
}
function maxRedeem(address owner) public view override returns (uint256) {
uint256 cash = cToken.getCash();
uint256 cashInShares = convertToShares(cash);
uint256 shareBalance = balanceOf[owner];
return cashInShares < shareBalance ? cashInShares : shareBalance;
}
/// -----------------------------------------------------------------------
/// ERC20 metadata generation
/// -----------------------------------------------------------------------
function _vaultName(ERC20 asset_) internal view virtual returns (string memory vaultName) {
vaultName = string.concat("ERC4626-Wrapped Compound ", asset_.symbol());
}
function _vaultSymbol(ERC20 asset_) internal view virtual returns (string memory vaultSymbol) {
vaultSymbol = string.concat("wc", asset_.symbol());
}
}