@@ -50,6 +50,8 @@ contract CoinEngine is ReentrancyGuard {
5050 error CoinEngine_TransferFailed ();
5151 error CoinEngine_HealthFactorBroken ();
5252 error CoinEngine_TokenAddressAndPriceFeedAddressLengthDontMatch ();
53+ error CoinEngine_HealtFactorIsGood ();
54+ error CoinEngine_HealthFactorNotImproved ();
5355
5456 ///////////////////
5557 // Types
@@ -66,6 +68,7 @@ contract CoinEngine is ReentrancyGuard {
6668 uint256 private constant ADDITIONAL_FEED_PRECISION = 1e10 ;
6769 uint256 private constant LIQUIDATION_THRESOLD = 50 ;
6870 uint256 private constant LIQUIDATION_PRECISION = 100 ;
71+ uint256 private constant LIQUIDATION_BONUS = 10 ;
6972
7073 /// @dev Mapping of token address to price feed address
7174 mapping (address tokenCollateralAddress = > address priceFeed ) private s_priceFeeds;
@@ -80,6 +83,7 @@ contract CoinEngine is ReentrancyGuard {
8083 // Events
8184 ///////////////////
8285 event CollateralDeposited (address indexed user , address indexed tokenCollateralAddress , uint256 amount );
86+ event CollateralRedeemed (address indexed redeemFrom , address indexed redeemTo , address token , uint256 amount );
8387
8488 ///////////////////
8589 // Modifiers
@@ -154,13 +158,13 @@ contract CoinEngine is ReentrancyGuard {
154158
155159 function mintSc (uint256 amountToMint ) public nonReentrant moreThanZero (amountToMint) {
156160 s_scMinted[msg .sender ] += amountToMint;
157- _revertIfHealtFactorIsBroken (msg .sender );
161+ _revertIfHealthFactorIsBroken (msg .sender );
158162 }
159163
160164 // Burn you own SC.
161165 function burnSC (uint256 amount ) external moreThanZero (amount) {
162166 _burnSc (amount, msg .sender , msg .sender );
163- _revertIfHealtFactorIsBroken (msg .sender ); // technically not needed to do this
167+ _revertIfHealthFactorIsBroken (msg .sender ); // technically not needed to do this
164168 }
165169
166170 function redeemCollateral (address tokenCollateralAddress , uint256 amountCollateral )
@@ -171,7 +175,28 @@ contract CoinEngine is ReentrancyGuard {
171175 {
172176 s_collateralDeposited[msg .sender ][tokenCollateralAddress] -= amountCollateral;
173177 _redeemCollateral (tokenCollateralAddress, amountCollateral, msg .sender , msg .sender );
174- _revertIfHealtFactorIsBroken (msg .sender );
178+ _revertIfHealthFactorIsBroken (msg .sender );
179+ }
180+
181+ function liquidate (uint256 debtToCover , address tokenCollateralAddress , address user ) external {
182+ uint256 startingHealthFactor = _getUserHealthFactor (user);
183+
184+ if (startingHealthFactor > MIN_HEALTH_FACTOR) {
185+ revert CoinEngine_HealtFactorIsGood ();
186+ }
187+ uint256 tokenAmountToCoverFromDebt = getTokenValueFromUSD (debtToCover, tokenCollateralAddress);
188+ uint256 bonusCollateral = (tokenAmountToCoverFromDebt * LIQUIDATION_BONUS) / LIQUIDATION_PRECISION;
189+
190+ _redeemCollateral (tokenCollateralAddress, tokenAmountToCoverFromDebt + bonusCollateral, user, msg .sender );
191+ _burnSc (debtToCover, user, msg .sender );
192+
193+ uint256 endingUserHealthFactor = _getUserHealthFactor (user);
194+
195+ // This condtional will not hit
196+ if (endingUserHealthFactor < startingHealthFactor) {
197+ revert CoinEngine_HealthFactorNotImproved ();
198+ }
199+ _revertIfHealthFactorIsBroken (msg .sender );
175200 }
176201
177202 //////////////////////////////
@@ -200,6 +225,7 @@ contract CoinEngine is ReentrancyGuard {
200225 private
201226 {
202227 s_collateralDeposited[from][tokenCollateralAddress] -= amountCollateral;
228+ emit CollateralRedeemed (from, to, tokenCollateralAddress, amountCollateral);
203229 (bool success ) = IERC20 (tokenCollateralAddress).transfer (to, amountCollateral);
204230 if (! success) {
205231 revert CoinEngine_TransferFailed ();
@@ -213,7 +239,7 @@ contract CoinEngine is ReentrancyGuard {
213239 return ((uint256 (price) * ADDITIONAL_FEED_PRECISION) * amount) / PRECISION;
214240 }
215241
216- function _revertIfHealtFactorIsBroken (address user ) internal view {
242+ function _revertIfHealthFactorIsBroken (address user ) internal view {
217243 uint256 userHealthFactor = _getUserHealthFactor (user);
218244 if (userHealthFactor < MIN_HEALTH_FACTOR) {
219245 revert CoinEngine_HealthFactorBroken ();
@@ -248,16 +274,30 @@ contract CoinEngine is ReentrancyGuard {
248274 pure
249275 returns (uint256 )
250276 {
251- // if (totalSCMinted == 0) return type(uint256).max;
277+ if (totalSCMinted == 0 ) return type (uint256 ).max;
252278 uint256 collateralThresold = (collateralValueInUSD * LIQUIDATION_THRESOLD) / LIQUIDATION_PRECISION;
253279 return (collateralThresold * PRECISION) / totalSCMinted;
254280 }
255281
256282 /////////////////////////////////////////////
257283 // External & Public View & Pure Functions
258284 /////////////////////////////////////////////
285+ function getTokenValueFromUSD (uint256 amountSC , address tokenAddress ) public view returns (uint256 ) {
286+ AggregatorV3Interface priceFeed = AggregatorV3Interface (s_priceFeeds[tokenAddress]);
287+ (, int256 price ,,,) = priceFeed.latestRoundData ();
288+
289+ return ((amountSC * PRECISION) / (uint256 (price) * ADDITIONAL_FEED_PRECISION));
290+ }
259291
260292 function getValueUSD (address tokenAddress , uint256 amount ) external view returns (uint256 ) {
261293 return _getValueUSD (tokenAddress, amount);
262294 }
295+
296+ function getAccountInformation (address user )
297+ external
298+ view
299+ returns (uint256 totalSCMinted , uint256 collateralValueInUSD )
300+ {
301+ (totalSCMinted, collateralValueInUSD) = _getAccountInformation (user);
302+ }
263303}
0 commit comments