generated from ZeframLou/foundry-template
-
Notifications
You must be signed in to change notification settings - Fork 15
/
YearnGate.sol
145 lines (126 loc) · 4.55 KB
/
YearnGate.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
// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.13;
import {ERC20} from "solmate/tokens/ERC20.sol";
import {SafeTransferLib} from "solmate/utils/SafeTransferLib.sol";
import {Gate} from "../Gate.sol";
import {Factory} from "../Factory.sol";
import {ERC20Gate} from "./ERC20Gate.sol";
import {FullMath} from "../lib/FullMath.sol";
import {YearnVault} from "../external/YearnVault.sol";
/// @title YearnGate
/// @author zefram.eth
/// @notice The Gate implementation for Yearn vaults
contract YearnGate is ERC20Gate {
/// -----------------------------------------------------------------------
/// Library usage
/// -----------------------------------------------------------------------
using SafeTransferLib for ERC20;
/// -----------------------------------------------------------------------
/// Initialization
/// -----------------------------------------------------------------------
constructor(Factory factory_) ERC20Gate(factory_) {}
/// -----------------------------------------------------------------------
/// Getters
/// -----------------------------------------------------------------------
/// @inheritdoc Gate
function getUnderlyingOfVault(address vault)
public
view
virtual
override
returns (ERC20)
{
return ERC20(YearnVault(vault).token());
}
/// @inheritdoc Gate
function getPricePerVaultShare(address vault)
public
view
virtual
override
returns (uint256)
{
YearnVault yearnVault = YearnVault(vault);
return
yearnVault.pricePerShare() *
10**(PRECISION_DECIMALS - yearnVault.decimals());
}
/// -----------------------------------------------------------------------
/// Internal utilities
/// -----------------------------------------------------------------------
/// @inheritdoc Gate
function _depositIntoVault(
ERC20 underlying,
uint256 underlyingAmount,
address vault
) internal virtual override {
if (underlying.allowance(address(this), vault) != 0) {
// reset allowance to support tokens like USDT
// that only allow non-zero approval if the current
// allowance is zero
underlying.safeApprove(vault, 0);
}
// we don't do infinite approval because vault is not trusted
underlying.safeApprove(vault, underlyingAmount);
YearnVault(vault).deposit(underlyingAmount);
if (underlying.allowance(address(this), vault) != 0) {
// clear any outstanding allowances to prevent unknown attack vectors
underlying.safeApprove(vault, 0);
}
}
/// @inheritdoc Gate
function _withdrawFromVault(
address recipient,
address vault,
uint256 underlyingAmount,
uint256 pricePerVaultShare,
bool checkBalance
) internal virtual override returns (uint256 withdrawnUnderlyingAmount) {
uint256 shareAmount = _underlyingAmountToVaultSharesAmount(
vault,
underlyingAmount,
pricePerVaultShare
);
if (checkBalance) {
uint256 shareBalance = getVaultShareBalance(vault);
if (shareAmount > shareBalance) {
// rounding error, withdraw entire balance
shareAmount = shareBalance;
}
}
withdrawnUnderlyingAmount = YearnVault(vault).withdraw(
shareAmount,
recipient
);
}
/// @inheritdoc Gate
function _vaultSharesAmountToUnderlyingAmount(
address, /*vault*/
uint256 vaultSharesAmount,
uint256 pricePerVaultShare
) internal view virtual override returns (uint256) {
return
FullMath.mulDiv(vaultSharesAmount, pricePerVaultShare, PRECISION);
}
/// @inheritdoc Gate
function _vaultSharesAmountToUnderlyingAmountRoundingUp(
address, /*vault*/
uint256 vaultSharesAmount,
uint256 pricePerVaultShare
) internal view virtual override returns (uint256) {
return
FullMath.mulDivRoundingUp(
vaultSharesAmount,
pricePerVaultShare,
PRECISION
);
}
/// @inheritdoc Gate
function _underlyingAmountToVaultSharesAmount(
address, /*vault*/
uint256 underlyingAmount,
uint256 pricePerVaultShare
) internal view virtual override returns (uint256) {
return FullMath.mulDiv(underlyingAmount, PRECISION, pricePerVaultShare);
}
}