forked from Alma-Research/growthdefi-v1-core
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathGCTokenBase.sol
245 lines (228 loc) · 11.9 KB
/
GCTokenBase.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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.6.0;
import { GFormulae } from "./GFormulae.sol";
import { GTokenBase } from "./GTokenBase.sol";
import { GCToken } from "./GCToken.sol";
import { GCFormulae } from "./GCFormulae.sol";
import { GMining } from "./GMining.sol";
import { G } from "./G.sol";
import { GC } from "./GC.sol";
import { $ } from "./network/$.sol";
/**
* @notice This abstract contract provides the basis implementation for all
* gcTokens, i.e. gTokens that use Compound cTokens as reserve, and
* implements the common functionality shared amongst them.
* In a nutshell, it extends the functinality of the GTokenBase contract
* to support operating directly using the cToken underlying asset.
* Therefore this contract provides functions that encapsulate minting
* and redeeming of cTokens internally, allowing users to interact with
* the contract providing funds directly in their underlying asset.
*/
abstract contract GCTokenBase is GTokenBase, GCToken, GMining
{
address public immutable override miningToken;
address public immutable override growthToken;
address public immutable override underlyingToken;
/**
* @dev Constructor for the gcToken contract.
* @param _name The ERC-20 token name.
* @param _symbol The ERC-20 token symbol.
* @param _decimals The ERC-20 token decimals.
* @param _stakesToken The ERC-20 token address to be used as stakes
* token (GRO).
* @param _reserveToken The ERC-20 token address to be used as reserve
* token (e.g. cDAI for gcDAI).
* @param _miningToken The ERC-20 token used for liquidity mining on
* compound (COMP).
* @param _growthToken The ERC-20 token address of the associated
* gToken, for gcTokens Type 2, or address(0),
* if this contract is a gcToken Type 1.
*/
constructor (string memory _name, string memory _symbol, uint8 _decimals, address _stakesToken, address _reserveToken, address _miningToken, address _growthToken)
GTokenBase(_name, _symbol, _decimals, _stakesToken, _reserveToken) public
{
miningToken = _miningToken;
growthToken = _growthToken;
address _underlyingToken = GC.getUnderlyingToken(_reserveToken);
underlyingToken = _underlyingToken;
}
/**
* @notice Allows for the beforehand calculation of the cToken amount
* given the amount of the underlying token and an exchange rate.
* @param _underlyingCost The cost in terms of the cToken underlying asset.
* @param _exchangeRate The given exchange rate as provided by exchangeRate().
* @return _cost The equivalent cost in terms of cToken
*/
function calcCostFromUnderlyingCost(uint256 _underlyingCost, uint256 _exchangeRate) public pure override returns (uint256 _cost)
{
return GCFormulae._calcCostFromUnderlyingCost(_underlyingCost, _exchangeRate);
}
/**
* @notice Allows for the beforehand calculation of the underlying token
* amount given the cToken amount and an exchange rate.
* @param _cost The cost in terms of the cToken.
* @param _exchangeRate The given exchange rate as provided by exchangeRate().
* @return _underlyingCost The equivalent cost in terms of the cToken underlying asset.
*/
function calcUnderlyingCostFromCost(uint256 _cost, uint256 _exchangeRate) public pure override returns (uint256 _underlyingCost)
{
return GCFormulae._calcUnderlyingCostFromCost(_cost, _exchangeRate);
}
/**
* @notice Allows for the beforehand calculation of shares to be
* received/minted upon depositing the underlying asset to the
* contract.
* @param _underlyingCost The amount of the underlying asset being deposited.
* @param _totalReserve The reserve balance as obtained by totalReserve().
* @param _totalSupply The shares supply as obtained by totalSupply().
* @param _depositFee The current deposit fee as obtained by depositFee().
* @param _exchangeRate The exchange rate as obtained by exchangeRate().
* @return _netShares The net amount of shares being received.
* @return _feeShares The fee amount of shares being deducted.
*/
function calcDepositSharesFromUnderlyingCost(uint256 _underlyingCost, uint256 _totalReserve, uint256 _totalSupply, uint256 _depositFee, uint256 _exchangeRate) public pure override returns (uint256 _netShares, uint256 _feeShares)
{
return GCFormulae._calcDepositSharesFromUnderlyingCost(_underlyingCost, _totalReserve, _totalSupply, _depositFee, _exchangeRate);
}
/**
* @notice Allows for the beforehand calculation of the amount of the
* underlying asset to be deposited in order to receive the desired
* amount of shares.
* @param _netShares The amount of this gcToken shares to receive.
* @param _totalReserve The reserve balance as obtained by totalReserve().
* @param _totalSupply The shares supply as obtained by totalSupply().
* @param _depositFee The current deposit fee as obtained by depositFee().
* @param _exchangeRate The exchange rate as obtained by exchangeRate().
* @return _underlyingCost The cost, in the underlying asset, to be paid.
* @return _feeShares The fee amount of shares being deducted.
*/
function calcDepositUnderlyingCostFromShares(uint256 _netShares, uint256 _totalReserve, uint256 _totalSupply, uint256 _depositFee, uint256 _exchangeRate) public pure override returns (uint256 _underlyingCost, uint256 _feeShares)
{
return GCFormulae._calcDepositUnderlyingCostFromShares(_netShares, _totalReserve, _totalSupply, _depositFee, _exchangeRate);
}
/**
* @notice Allows for the beforehand calculation of shares to be
* given/burned upon withdrawing the underlying asset from the
* contract.
* @param _underlyingCost The amount of the underlying asset being withdrawn.
* @param _totalReserve The reserve balance as obtained by totalReserve()
* @param _totalSupply The shares supply as obtained by totalSupply()
* @param _withdrawalFee The current withdrawl fee as obtained by withdrawalFee()
* @param _exchangeRate The exchange rate as obtained by exchangeRate().
* @return _grossShares The total amount of shares being deducted,
* including fees.
* @return _feeShares The fee amount of shares being deducted.
*/
function calcWithdrawalSharesFromUnderlyingCost(uint256 _underlyingCost, uint256 _totalReserve, uint256 _totalSupply, uint256 _withdrawalFee, uint256 _exchangeRate) public pure override returns (uint256 _grossShares, uint256 _feeShares)
{
return GCFormulae._calcWithdrawalSharesFromUnderlyingCost(_underlyingCost, _totalReserve, _totalSupply, _withdrawalFee, _exchangeRate);
}
/**
* @notice Allows for the beforehand calculation of the amount of the
* underlying asset to be withdrawn given the desired amount of
* shares.
* @param _grossShares The amount of this gcToken shares to provide.
* @param _totalReserve The reserve balance as obtained by totalReserve().
* @param _totalSupply The shares supply as obtained by totalSupply().
* @param _withdrawalFee The current withdrawal fee as obtained by withdrawalFee().
* @param _exchangeRate The exchange rate as obtained by exchangeRate().
* @return _underlyingCost The cost, in the underlying asset, to be received.
* @return _feeShares The fee amount of shares being deducted.
*/
function calcWithdrawalUnderlyingCostFromShares(uint256 _grossShares, uint256 _totalReserve, uint256 _totalSupply, uint256 _withdrawalFee, uint256 _exchangeRate) public pure override returns (uint256 _underlyingCost, uint256 _feeShares)
{
return GCFormulae._calcWithdrawalUnderlyingCostFromShares(_grossShares, _totalReserve, _totalSupply, _withdrawalFee, _exchangeRate);
}
/**
* @notice Provides the Compound exchange rate since their last update.
* @return _exchangeRate The exchange rate between cToken and its
* underlying asset
*/
function exchangeRate() public view override returns (uint256 _exchangeRate)
{
return GC.getExchangeRate(reserveToken);
}
/**
* @notice Provides the total amount kept in the reserve in terms of the
* underlying asset.
* @return _totalReserveUnderlying The underlying asset balance on reserve.
*/
function totalReserveUnderlying() public view virtual override returns (uint256 _totalReserveUnderlying)
{
return GCFormulae._calcUnderlyingCostFromCost(totalReserve(), exchangeRate());
}
/**
* @notice Provides the total amount of the underlying asset (or equivalent)
* this contract is currently lending on Compound.
* @return _lendingReserveUnderlying The underlying asset lending
* balance on Compound.
*/
function lendingReserveUnderlying() public view virtual override returns (uint256 _lendingReserveUnderlying)
{
return GC.getLendAmount(reserveToken);
}
/**
* @notice Provides the total amount of the underlying asset (or equivalent)
* this contract is currently borrowing on Compound.
* @return _borrowingReserveUnderlying The underlying asset borrowing
* balance on Compound.
*/
function borrowingReserveUnderlying() public view virtual override returns (uint256 _borrowingReserveUnderlying)
{
return GC.getBorrowAmount(reserveToken);
}
/**
* @notice Performs the minting of gcToken shares upon the deposit of the
* cToken underlying asset. The funds will be pulled in by this
* contract, therefore they must be previously approved. This
* function builds upon the GTokenBase deposit function. See
* GTokenBase.sol for further documentation.
* @param _underlyingCost The amount of the underlying asset being
* deposited in the operation.
*/
function depositUnderlying(uint256 _underlyingCost) public override nonReentrant
{
address _from = msg.sender;
require(_underlyingCost > 0, "underlying cost must be greater than 0");
uint256 _cost = GCFormulae._calcCostFromUnderlyingCost(_underlyingCost, exchangeRate());
(uint256 _netShares, uint256 _feeShares) = GFormulae._calcDepositSharesFromCost(_cost, totalReserve(), totalSupply(), depositFee());
require(_netShares > 0, "shares must be greater than 0");
G.pullFunds(underlyingToken, _from, _underlyingCost);
GC.safeLend(reserveToken, _underlyingCost);
require(_prepareDeposit(_cost), "not available at the moment");
_mint(_from, _netShares);
_mint(address(this), _feeShares.div(2));
}
/**
* @notice Performs the burning of gcToken shares upon the withdrawal of
* the underlying asset. This function builds upon the
* GTokenBase withdrawal function. See GTokenBase.sol for
* further documentation.
* @param _grossShares The gross amount of this gcToken shares being
* redeemed in the operation.
*/
function withdrawUnderlying(uint256 _grossShares) public override nonReentrant
{
address _from = msg.sender;
require(_grossShares > 0, "shares must be greater than 0");
(uint256 _cost, uint256 _feeShares) = GFormulae._calcWithdrawalCostFromShares(_grossShares, totalReserve(), totalSupply(), withdrawalFee());
uint256 _underlyingCost = GCFormulae._calcUnderlyingCostFromCost(_cost, exchangeRate());
require(_underlyingCost > 0, "underlying cost must be greater than 0");
require(_prepareWithdrawal(_cost), "not available at the moment");
_underlyingCost = G.min(_underlyingCost, GC.getLendAmount(reserveToken));
GC.safeRedeem(reserveToken, _underlyingCost);
G.pushFunds(underlyingToken, _from, _underlyingCost);
_burn(_from, _grossShares);
_mint(address(this), _feeShares.div(2));
}
/**
* @dev The default behavior of this function is to send the funds to
* address(0), but we override it and send the funds to the stkGRO
* contract instead.
* @param _stakesAmount The amount of the stakes token being burned.
*/
function _burnStakes(uint256 _stakesAmount) internal override
{
G.pushFunds(stakesToken, $.stkGRO, _stakesAmount);
}
}