-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathBorrowerWrappersScript.sol
More file actions
160 lines (126 loc) · 6.1 KB
/
BorrowerWrappersScript.sol
File metadata and controls
160 lines (126 loc) · 6.1 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
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: MIT
pragma solidity 0.6.11;
import "../Dependencies/SafeMath.sol";
import "../Dependencies/LiquityMath.sol";
import "../Dependencies/IERC20.sol";
import "../Interfaces/IBorrowerOperations.sol";
import "../Interfaces/ITroveManager.sol";
import "../Interfaces/IStabilityPool.sol";
import "../Interfaces/IPriceFeed.sol";
import "../Interfaces/IZEROStaking.sol";
import "./BorrowerOperationsScript.sol";
import "./ETHTransferScript.sol";
import "./ZEROStakingScript.sol";
import "../Dependencies/console.sol";
contract BorrowerWrappersScript is BorrowerOperationsScript, ETHTransferScript, ZEROStakingScript {
using SafeMath for uint;
string constant public NAME = "BorrowerWrappersScript";
ITroveManager immutable troveManager;
IStabilityPool immutable stabilityPool;
IPriceFeed immutable priceFeed;
IERC20 immutable zusdToken;
IERC20 immutable zeroToken;
IZEROStaking immutable zeroStaking;
constructor(
address _borrowerOperationsAddress,
address _troveManagerAddress,
address _zeroStakingAddress,
address _stabilityPoolAddress,
address _priceFeedAddress,
address _zusdTokenAddress,
address _zeroTokenAddress
)
BorrowerOperationsScript(IBorrowerOperations(_borrowerOperationsAddress))
ZEROStakingScript(_zeroStakingAddress)
public
{
checkContract(_troveManagerAddress);
ITroveManager troveManagerCached = ITroveManager(_troveManagerAddress);
troveManager = troveManagerCached;
IStabilityPool stabilityPoolCached = IStabilityPool(_stabilityPoolAddress);
checkContract(_stabilityPoolAddress);
stabilityPool = stabilityPoolCached;
IPriceFeed priceFeedCached = IPriceFeed(_priceFeedAddress);
checkContract(_priceFeedAddress);
priceFeed = priceFeedCached;
checkContract(_zusdTokenAddress);
zusdToken = IERC20(_zusdTokenAddress);
checkContract(_zeroTokenAddress);
zeroToken = IERC20(_zeroTokenAddress);
IZEROStaking zeroStakingCached = IZEROStaking(_zeroStakingAddress);
checkContract(_zeroStakingAddress);
zeroStaking = zeroStakingCached;
}
function claimCollateralAndOpenTrove(uint _maxFee, uint _ZUSDAmount, address _upperHint, address _lowerHint) external payable {
uint balanceBefore = address(this).balance;
// Claim collateral
borrowerOperations.claimCollateral();
uint balanceAfter = address(this).balance;
// already checked in CollSurplusPool
assert(balanceAfter > balanceBefore);
uint totalCollateral = balanceAfter.sub(balanceBefore).add(msg.value);
// Open trove with obtained collateral, plus collateral sent by user
borrowerOperations.openTrove{ value: totalCollateral }(_maxFee, _ZUSDAmount, _upperHint, _lowerHint);
}
function claimSPRewardsAndRecycle(uint _maxFee, address _upperHint, address _lowerHint) external {
uint collBalanceBefore = address(this).balance;
uint zeroBalanceBefore = zeroToken.balanceOf(address(this));
// Claim rewards
stabilityPool.withdrawFromSP(0);
uint collBalanceAfter = address(this).balance;
uint zeroBalanceAfter = zeroToken.balanceOf(address(this));
uint claimedCollateral = collBalanceAfter.sub(collBalanceBefore);
// Add claimed ETH to trove, get more ZUSD and stake it into the Stability Pool
if (claimedCollateral > 0) {
_requireUserHasTrove(address(this));
uint ZUSDAmount = _getNetZUSDAmount(claimedCollateral);
borrowerOperations.adjustTrove{ value: claimedCollateral }(_maxFee, 0, ZUSDAmount, true, _upperHint, _lowerHint);
// Provide withdrawn ZUSD to Stability Pool
if (ZUSDAmount > 0) {
stabilityPool.provideToSP(ZUSDAmount, address(0));
}
}
// Stake claimed ZERO
uint claimedZERO = zeroBalanceAfter.sub(zeroBalanceBefore);
if (claimedZERO > 0) {
zeroStaking.stake(claimedZERO);
}
}
function claimStakingGainsAndRecycle(uint _maxFee, address _upperHint, address _lowerHint) external {
uint collBalanceBefore = address(this).balance;
uint zusdBalanceBefore = zusdToken.balanceOf(address(this));
uint zeroBalanceBefore = zeroToken.balanceOf(address(this));
// Claim gains
zeroStaking.unstake(0);
uint gainedCollateral = address(this).balance.sub(collBalanceBefore); // stack too deep issues :'(
uint gainedZUSD = zusdToken.balanceOf(address(this)).sub(zusdBalanceBefore);
uint netZUSDAmount;
// Top up trove and get more ZUSD, keeping ICR constant
if (gainedCollateral > 0) {
_requireUserHasTrove(address(this));
netZUSDAmount = _getNetZUSDAmount(gainedCollateral);
borrowerOperations.adjustTrove{ value: gainedCollateral }(_maxFee, 0, netZUSDAmount, true, _upperHint, _lowerHint);
}
uint totalZUSD = gainedZUSD.add(netZUSDAmount);
if (totalZUSD > 0) {
stabilityPool.provideToSP(totalZUSD, address(0));
// Providing to Stability Pool also triggers ZERO claim, so stake it if any
uint zeroBalanceAfter = zeroToken.balanceOf(address(this));
uint claimedZERO = zeroBalanceAfter.sub(zeroBalanceBefore);
if (claimedZERO > 0) {
zeroStaking.stake(claimedZERO);
}
}
}
function _getNetZUSDAmount(uint _collateral) internal returns (uint) {
uint price = priceFeed.fetchPrice();
uint ICR = troveManager.getCurrentICR(address(this), price);
uint ZUSDAmount = _collateral.mul(price).div(ICR);
uint borrowingRate = troveManager.getBorrowingRateWithDecay();
uint netDebt = ZUSDAmount.mul(LiquityMath.DECIMAL_PRECISION).div(LiquityMath.DECIMAL_PRECISION.add(borrowingRate));
return netDebt;
}
function _requireUserHasTrove(address _depositor) internal view {
require(troveManager.getTroveStatus(_depositor) == 1, "BorrowerWrappersScript: caller must have an active trove");
}
}