1

so can someone please help me come up with a solution to implement the change I want to make to my stable coin project please?

The system is designed to be as minimal as possible, and have the tokens maintain a 1 token == $1 peg at all times. This is a stablecoin with the following properties:

  • Exogenously Collateralized
  • Dollar Pegged
  • Algorithmically Stable

This contract is the core of the Decentralized Stablecoin system. It handles all the logic for minting and redeeming DSC, as well as depositing and withdrawing collateral. This contract is based on the MakerDAO DSS system

But I have created a separate contract(IndexedAssetPriceFeed.sol) that you can pass in multiple ChainLink price feed addresses (all USD pairs), the way it works is like this you pass in multiple price feeds of assets, and then it adds up all the USD values of all the assets then divides by the number of assets returning a single indexed average value in USD.

for example: you pass in 10 price feeds (asset1 / USD) = $3000; (asset2 / USD) = $2000; (asset3 / USD) = $500; (asset4 / USD) = $150; (asset5 / USD) = $200; (asset6 / USD) = $75; (asset7 / USD) = $20; (asset8 / USD) = $1; (asset9 / USD) = $17; (asset10 / USD) = $37;

asset1 + asset2 + ...asset10 = $6000 / 10 = $600.

and then I want to peg the stablecoin to the indexed average value instead of the US Dollar, so the stability comes from Diversification similar to how an Index fund on the stock market works. I don't want to change anything about the contract except change what the DSC token is pegged to.

But I need help with coming up with a way to implement this. so first I am going to provide the needed contracts and context.

  • I am using the Foundry framework.
  • Based on this GitHub repository 'https://github.com/Cyfrin/foundry-defi-stablecoin-f23' by Patrick Collins.
  • tried solutions at the bottom.

so here is the IndexedAssetPriceFeed.sol contract:

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.19;

import {AggregatorV3Interface} from "../../lib/chainlink-brownie-contracts/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import {MockV3Aggregator} from "../../test/mocks/MockV3Aggregator.sol";


contract IndexedAssetPriceFeed {
    error PriceTooHigh(uint256 givenPrice);

    AggregatorV3Interface[] public priceFeeds;
    MockV3Aggregator[] public mockPriceFeeds;
    uint256 public lastKnownPrice;

    mapping(address => uint256) public prices;

  // can pass in the priceFeed Addresses in on deployment 
    constructor(AggregatorV3Interface[] memory _priceFeeds) {
        priceFeeds = _priceFeeds;
    }

    function getLatestPrice() public returns (uint256) {
      return updatePrice();
    }

    function updatePrice() public returns(uint256) {
        uint256 total = 0;
        uint256 count = 0;
        for (uint256 i = 0; i < priceFeeds.length; i++) {
            try priceFeeds[i].latestRoundData() returns (uint80, int256 price, uint256, uint256, uint80) {
                prices[address(priceFeeds[i])] = uint256(price);
                total += uint256(price);
                count++;
            } catch {
                revert("Call to latestRoundData failed");
            }
        }
        lastKnownPrice = total / count;
        return lastKnownPrice;
    }

    function getLatestTimeStamp() public view returns (uint256) {
        uint256 latestTimeStamp = 0;
        for (uint256 i = 0; i < priceFeeds.length; i++) {
            (, , , uint256 updatedAt, ) = priceFeeds[i].latestRoundData();
            if (updatedAt > latestTimeStamp) {
                latestTimeStamp = updatedAt;
            }
        }
        return latestTimeStamp;
    }

    function setRoundDataForTesting(address _mockPriceFeedAddress, uint80 _roundId, int256 _answer, uint256 _timestamp, uint256 _startedAt) external {
        // Assuming you want to set the round data for the first price feed
        MockV3Aggregator mockPriceFeed = MockV3Aggregator(_mockPriceFeedAddress);

        // Call the updateRoundData function on the price feed
        mockPriceFeed.updateRoundData(_roundId, _answer, _timestamp, _startedAt);
    }

    function getPriceFeeds() public view returns (AggregatorV3Interface[] memory) {
        return priceFeeds;
    }

}

here is the OracleLib.sol contract if needed:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

// import {AggregatorV3Interface} from "lib/chainlink-brownie-contracts/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import {console} from "lib/forge-std/src/console.sol";
import { IndexedAssetPriceFeed } from './IndexedAssetPriceFeed.sol';
import {AggregatorV3Interface} from "../../lib/chainlink-brownie-contracts/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";


/*
 * @title OracleLib
 * @notice This library is used to check the Chainlink Oracle for stale data.
 * If a price is stale, functions will revert, and render the DSCEngine unusable - this is by design.
 * We want the DSCEngine to freeze if prices become stale.
 *
 * So if the Chainlink network explodes and you have a lot of money locked in the protocol... too bad.
 */
library OracleLib {
    error OracleLib__StalePrice(string message);

    uint256 private constant TIMEOUT = 3 hours;

    function staleCheckLatestRoundData(IndexedAssetPriceFeed indexedAssetPriceFeed)
        public returns (uint256)
    {
        uint256 price = indexedAssetPriceFeed.getLatestPrice();

        // console.log(price);

        uint256 secondsSince = block.timestamp - indexedAssetPriceFeed.getLatestTimeStamp();

        // console.log("seconds Since Latest timestamp: %s", secondsSince);

        if (secondsSince > getTimeout()) revert OracleLib__StalePrice("Stale price detected");

        // console.log(price);

        return price;
    }

    function getTimeout() public pure returns (uint256) {
        return TIMEOUT;
    }


    // AggregatorV3Interface price tests
    function staleCheckLatestRoundDataOnCollateral(AggregatorV3Interface chainlinkFeed)
        public
        view
        returns (uint80, int256, uint256, uint256, uint80)
    {
        (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) =
            chainlinkFeed.latestRoundData();

        if (updatedAt == 0 || answeredInRound < roundId) {
            revert OracleLib__StalePrice("Stale price detected");
        }
        uint256 secondsSince = block.timestamp - updatedAt;
        if (secondsSince > TIMEOUT) revert OracleLib__StalePrice("Stale price detected");

        return (roundId, answer, startedAt, updatedAt, answeredInRound);
    }

    function getTimeoutAggregatorV3Interface(AggregatorV3Interface /* chainlinkFeed */ ) public pure returns (uint256) {
        return TIMEOUT;
    }
}

and here is the DSCEnigne contract:

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.19;

import {AggregatorV3Interface} from "lib/chainlink-brownie-contracts/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import {OracleLib} from "./libraries/OracleLib.sol";
import {IndexedAssetPriceFeed} from "./libraries/IndexedAssetPriceFeed.sol";
import {ReentrancyGuard} from "lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol";
import {IERC20} from "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {DecentralizedStableCoin} from "./DecentralizedStableCoin.sol";
// import {console} from "../lib/forge-std/src/console.sol";

/*
 * @title DSCEngine
 * @author Dylan Katsch
 * credit to Patrick Collins, this project is based on a repository for Patrick     Collins's GitHub.
 *
 * The system is designed to be as minimal as possible, and have the tokens maintain a 1 token == $1 peg at all times.
 * This is a stablecoin with the properties:
 * - Exogenously Collateralized
 * - Dollar Pegged
 * - Algorithmically Stable
 *
 * @notice This contract is the core of the Decentralized Stablecoin system. It handles all the logic
 * for minting and redeeming DSC, as well as depositing and withdrawing collateral.
 * @notice This contract is based on the MakerDAO DSS system
 */
contract DSCEngine is ReentrancyGuard {
    ///////////////////
    // Errors
    ///////////////////
    error DSCEngine__TokenAddressesAndPriceFeedAddressesAmountsDontMatch();
    error DSCEngine__NeedsMoreThanZero();
    error DSCEngine__TokenNotAllowed(address token);
    error DSCEngine__TransferFailed();
    error DSCEngine__BreaksHealthFactor(uint256 healthFactorValue);
    error DSCEngine__MintFailed();
    error DSCEngine__HealthFactorOk();
    error DSCEngine__HealthFactorNotImproved();

    ///////////////////
    // Types
    ///////////////////
    using OracleLib for AggregatorV3Interface;

    ///////////////////
    // State Variables
    ///////////////////
    DecentralizedStableCoin private immutable i_dsc;

    uint256 private constant LIQUIDATION_THRESHOLD = 50; // This means you need to be 200% over-collateralized
    uint256 private constant LIQUIDATION_BONUS = 10; // This means you get assets at a 10% discount when liquidating
    uint256 private constant LIQUIDATION_PRECISION = 100;
    uint256 private constant MIN_HEALTH_FACTOR = 1e18;
    uint256 private constant PRECISION = 1e18;
    uint256 private constant ADDITIONAL_FEED_PRECISION = 1e10;
    uint256 private constant FEED_PRECISION = 1e8;

    /// @dev Mapping of token address to price feed address
    mapping(address collateralToken => address priceFeed) private s_priceFeeds;
    /// @dev Amount of collateral deposited by user
    mapping(address user => mapping(address collateralToken => uint256 amount)) private s_collateralDeposited;
    /// @dev Amount of DSC minted by user
    mapping(address user => uint256 amount) private s_DSCMinted;
    /// @dev If we know exactly how many tokens we have, we could make this immutable!
    address[] private s_collateralTokens;

    ///////////////////
    // Events
    ///////////////////
    event CollateralDeposited(address indexed user, address indexed token, uint256 indexed amount);
    event CollateralRedeemed(address indexed redeemFrom, address indexed redeemTo, address token, uint256 amount); // if redeemFrom != redeemedTo, then it was liquidated

    ///////////////////
    // Modifiers
    ///////////////////
    modifier moreThanZero(uint256 amount) {
        if (amount == 0) {
            revert DSCEngine__NeedsMoreThanZero();
        }
        _;
    }

    modifier isAllowedToken(address token) {
        if (s_priceFeeds[token] == address(0)) {
            revert DSCEngine__TokenNotAllowed(token);
        }
        _;
    }


    ///////////////////
    // Functions
    ///////////////////
    
    constructor(address[] memory tokenAddresses, address[] memory priceFeedAddresses, address dscAddress) {
        if (tokenAddresses.length != priceFeedAddresses.length) {
            revert DSCEngine__TokenAddressesAndPriceFeedAddressesAmountsDontMatch();
        }
        // These feeds will be the USD pairs
        // For example ETH / USD or MKR / USD
        for (uint256 i = 0; i < tokenAddresses.length; i++) {
            s_priceFeeds[tokenAddresses[i]] = priceFeedAddresses[i];
            s_collateralTokens.push(tokenAddresses[i]);
        }
        i_dsc = DecentralizedStableCoin(dscAddress);
        // IndexedAssetPriceFeed indexedAssetPriceFeed = new IndexedAssetPriceFeed(priceFeedAddresses);
    }

    ///////////////////
    // External Functions
    ///////////////////
    /*
     * @param tokenCollateralAddress: The ERC20 token address of the collateral you're depositing
     * @param amountCollateral: The amount of collateral you're depositing
     * @param amountDscToMint: The amount of DSC you want to mint
     * @notice This function will deposit your collateral and mint DSC in one transaction
     */
    function depositCollateralAndMintDsc(
        address tokenCollateralAddress,
        uint256 amountCollateral,
        uint256 amountDscToMint
    ) external {
        depositCollateral(tokenCollateralAddress, amountCollateral);
        mintDsc(amountDscToMint);
    }

    /*
     * @param tokenCollateralAddress: The ERC20 token address of the collateral you're depositing
     * @param amountCollateral: The amount of collateral you're depositing
     * @param amountDscToBurn: The amount of DSC you want to burn
     * @notice This function will withdraw your collateral and burn DSC in one transaction
     */
    function redeemCollateralForDsc(address tokenCollateralAddress, uint256 amountCollateral, uint256 amountDscToBurn)
        external
        moreThanZero(amountCollateral)
    {
        _burnDsc(amountDscToBurn, msg.sender, msg.sender);
        _redeemCollateral(tokenCollateralAddress, amountCollateral, msg.sender, msg.sender);
        revertIfHealthFactorIsBroken(msg.sender);
    }

    /*
     * @param tokenCollateralAddress: The ERC20 token address of the collateral you're redeeming
     * @param amountCollateral: The amount of collateral you're redeeming
     * @notice This function will redeem your collateral.
     * @notice If you have DSC minted, you will not be able to redeem until you burn your DSC
     */
    function redeemCollateral(address tokenCollateralAddress, uint256 amountCollateral)
        external
        moreThanZero(amountCollateral)
        nonReentrant
    {
        _redeemCollateral(tokenCollateralAddress, amountCollateral, msg.sender, msg.sender);
        revertIfHealthFactorIsBroken(msg.sender);
    }

    /*
     * @notice careful! You'll burn your DSC here! Make sure you want to do this...
     * @dev you might want to use this if you're nervous you might get liquidated and want to just burn
     * you DSC but keep your collateral in.
     */
    function burnDsc(uint256 amount) external moreThanZero(amount) {
        _burnDsc(amount, msg.sender, msg.sender);
        revertIfHealthFactorIsBroken(msg.sender); // I don't think this would ever hit...
    }

    /*
     * @param collateral: The ERC20 token address of the collateral you're using to make the protocol solvent again.
     * This is collateral that you're going to take from the user who is insolvent.
     * In return, you have to burn your DSC to pay off their debt, but you don't pay off your own.
     * @param user: The user who is insolvent. They have to have a _healthFactor below MIN_HEALTH_FACTOR
     * @param debtToCover: The amount of DSC you want to burn to cover the user's debt.
     *
     * @notice: You can partially liquidate a user.
     * @notice: You will get a 10% LIQUIDATION_BONUS for taking the users funds.
     * @notice: This function working assumes that the protocol will be roughly 150% overcollateralized in order for this to work.
     * @notice: A known bug would be if the protocol was only 100% collateralized, we wouldn't be able to liquidate anyone.
     * For example, if the price of the collateral plummeted before anyone could be liquidated.
     */
    function liquidate(address collateral, address user, uint256 debtToCover)
        external
        moreThanZero(debtToCover)
        nonReentrant
    {
        uint256 startingUserHealthFactor = _healthFactor(user);
        if (startingUserHealthFactor >= MIN_HEALTH_FACTOR) {
            revert DSCEngine__HealthFactorOk();
        }
        // If covering 100 DSC, we need to $100 of collateral
        uint256 tokenAmountFromDebtCovered = getTokenAmountFromUsd(collateral, debtToCover);
        // And give them a 10% bonus
        // So we are giving the liquidator $110 of WETH for 100 DSC
        // We should implement a feature to liquidate in the event the protocol is insolvent
        // And sweep extra amounts into a treasury
        uint256 bonusCollateral = (tokenAmountFromDebtCovered * LIQUIDATION_BONUS) / LIQUIDATION_PRECISION;
        // Burn DSC equal to debtToCover
        // Figure out how much collateral to recover based on how much burnt
        _redeemCollateral(collateral, tokenAmountFromDebtCovered + bonusCollateral, user, msg.sender);
        _burnDsc(debtToCover, user, msg.sender);

        uint256 endingUserHealthFactor = _healthFactor(user);
        // This conditional should never hit, but just in case
        if (endingUserHealthFactor <= startingUserHealthFactor) {
            revert DSCEngine__HealthFactorNotImproved();
        }
        revertIfHealthFactorIsBroken(msg.sender);
    }

    ///////////////////
    // Public Functions
    ///////////////////
    /*
     * @param amountDscToMint: The amount of DSC you want to mint
     * You can only mint DSC if you hav enough collateral
     */
    function mintDsc(uint256 amountDscToMint) public moreThanZero(amountDscToMint) nonReentrant {
        s_DSCMinted[msg.sender] += amountDscToMint;
        revertIfHealthFactorIsBroken(msg.sender);
        bool minted = i_dsc.mint(msg.sender, amountDscToMint);

        if (minted != true) {
            revert DSCEngine__MintFailed();
        }
    }

    /*
     * @param tokenCollateralAddress: The ERC20 token address of the collateral you're depositing
     * @param amountCollateral: The amount of collateral you're depositing
     */
    function depositCollateral(address tokenCollateralAddress, uint256 amountCollateral)
        public
        moreThanZero(amountCollateral)
        nonReentrant
        isAllowedToken(tokenCollateralAddress)
    {
        s_collateralDeposited[msg.sender][tokenCollateralAddress] += amountCollateral;
        emit CollateralDeposited(msg.sender, tokenCollateralAddress, amountCollateral);
        bool success = IERC20(tokenCollateralAddress).transferFrom(msg.sender, address(this), amountCollateral);
        if (!success) {
            revert DSCEngine__TransferFailed();
        }
    }

    ///////////////////
    // Private Functions
    ///////////////////
    function _redeemCollateral(address tokenCollateralAddress, uint256 amountCollateral, address from, address to)
        private
    {
        s_collateralDeposited[from][tokenCollateralAddress] -= amountCollateral;
        emit CollateralRedeemed(from, to, tokenCollateralAddress, amountCollateral);
        bool success = IERC20(tokenCollateralAddress).transfer(to, amountCollateral);
        if (!success) {
            revert DSCEngine__TransferFailed();
        }
    }

    function _burnDsc(uint256 amountDscToBurn, address onBehalfOf, address dscFrom) private {
        s_DSCMinted[onBehalfOf] -= amountDscToBurn;

        bool success = i_dsc.transferFrom(dscFrom, address(this), amountDscToBurn);
        // This conditional is hypothetically unreachable
        if (!success) {
            revert DSCEngine__TransferFailed();
        }
        i_dsc.burn(amountDscToBurn);
    }

    //////////////////////////////
    // Private & Internal View & Pure Functions
    //////////////////////////////

    function _getAccountInformation(address user)
        private
        view
        returns (uint256 totalDscMinted, uint256 collateralValueInUsd)
    {
        totalDscMinted = s_DSCMinted[user];
        collateralValueInUsd = getAccountCollateralValue(user);
    }

    function _healthFactor(address user) private view returns (uint256) {
        (uint256 totalDscMinted, uint256 collateralValueInUsd) = _getAccountInformation(user);
        return _calculateHealthFactor(totalDscMinted, collateralValueInUsd);
    }

    function _getUsdValue(address token, uint256 amount) private view returns (uint256) {
        AggregatorV3Interface priceFeed = AggregatorV3Interface(s_priceFeeds[token]);
        (, int256 price,,,) = OracleLib.staleCheckLatestRoundDataOnCollateral(priceFeed);
        return ((uint256(price) * ADDITIONAL_FEED_PRECISION) * amount) / PRECISION;
    }

    function _calculateHealthFactor(uint256 totalDscMinted, uint256 collateralValueInUsd)
        internal
        pure
        returns (uint256)
    {
        if (totalDscMinted == 0) return type(uint256).max;
        uint256 collateralAdjustedForThreshold = (collateralValueInUsd * LIQUIDATION_THRESHOLD) / LIQUIDATION_PRECISION;
        return (collateralAdjustedForThreshold * PRECISION) / totalDscMinted;
    }

    function revertIfHealthFactorIsBroken(address user) internal view {
        uint256 userHealthFactor = _healthFactor(user);
        if (userHealthFactor < MIN_HEALTH_FACTOR) {
            revert DSCEngine__BreaksHealthFactor(userHealthFactor);
        }
    }

    ////////////////////////////////////////////////////////////////////////////
    // External & Public View & Pure Functions
    ////////////////////////////////////////////////////////////////////////////
    function calculateHealthFactor(uint256 totalDscMinted, uint256 collateralValueInUsd)
        external
        pure
        returns (uint256)
    {
        return _calculateHealthFactor(totalDscMinted, collateralValueInUsd);
    }

    function getAccountInformation(address user)
        external
        view
        returns (uint256 totalDscMinted, uint256 collateralValueInUsd)
    {
        return _getAccountInformation(user);
    }

    function getUsdValue(
        address token,
        uint256 amount // in WEI
    ) external view returns (uint256) {
        return _getUsdValue(token, amount);
    }

    function getCollateralBalanceOfUser(address user, address token) external view returns (uint256) {
        return s_collateralDeposited[user][token];
    }

    function getAccountCollateralValue(address user) public view returns (uint256 totalCollateralValueInUsd) {
        for (uint256 index = 0; index < s_collateralTokens.length; index++) {
            address token = s_collateralTokens[index];
            uint256 amount = s_collateralDeposited[user][token];
            totalCollateralValueInUsd += _getUsdValue(token, amount);
        }
        return totalCollateralValueInUsd;
    }

    function getTokenAmountFromUsd(address token, uint256 usdAmountInWei) public view returns (uint256) {
        AggregatorV3Interface priceFeed = AggregatorV3Interface(s_priceFeeds[token]);
        (, int256 price,,,) = OracleLib.staleCheckLatestRoundDataOnCollateral(priceFeed);
        // $100e18 USD Debt
        // 1 ETH = 2000 USD
        // The returned value from Chainlink will be 2000 * 1e8
        // Most USD pairs have 8 decimals, so we will just pretend they all do
        return ((usdAmountInWei * PRECISION) / (uint256(price) * ADDITIONAL_FEED_PRECISION));
    }

    function getPrecision() external pure returns (uint256) {
        return PRECISION;
    }

    function getAdditionalFeedPrecision() external pure returns (uint256) {
        return ADDITIONAL_FEED_PRECISION;
    }

    function getLiquidationThreshold() external pure returns (uint256) {
        return LIQUIDATION_THRESHOLD;
    }

    function getLiquidationBonus() external pure returns (uint256) {
        return LIQUIDATION_BONUS;
    }

    function getLiquidationPrecision() external pure returns (uint256) {
        return LIQUIDATION_PRECISION;
    }

    function getMinHealthFactor() external pure returns (uint256) {
        return MIN_HEALTH_FACTOR;
    }

    function getCollateralTokens() external view returns (address[] memory) {
        return s_collateralTokens;
    }

    function getDsc() external view returns (address) {
        return address(i_dsc);
    }

    function getCollateralTokenPriceFeed(address token) external view returns (address) {
        return s_priceFeeds[token];
    }

    function getHealthFactor(address user) external view returns (uint256) {
        return _healthFactor(user);
    }
}

what I have tried:

obviously instantiate the IndexedAssetPriceFeed.sol contract in the constructor of the DSCEngine.sol contract

but then the pegging of the DSC token to USD happens in the _getUsdValue() function which returns the USD value of the deposited collateral the returned value goes through a few functions but ends up in the mintDsc() function where it gets pegged on minting

function mintDsc(uint256 amountDscToMint) public moreThanZero(amountDscToMint) nonReentrant {
        s_DSCMinted[msg.sender] += amountDscToMint;
        revertIfHealthFactorIsBroken(msg.sender);
        bool minted = i_dsc.mint(msg.sender, amountDscToMint);

        if (minted != true) {
            revert DSCEngine__MintFailed();
        }
    }

function _getUsdValue(address token, uint256 amount) private view returns (uint256) {
        AggregatorV3Interface priceFeed = AggregatorV3Interface(s_priceFeeds[token]);
        (, int256 price,,,) = OracleLib.staleCheckLatestRoundDataOnCollateral(priceFeed);
        return ((uint256(price) * ADDITIONAL_FEED_PRECISION) * amount) / PRECISION;
    }

relevant function can be seen in the provided DSCEngine contract :

  • getAccountCollateralValue()
  • _healthFactor() & _calculateHealthFactor()
  • depositCollateral()

so I don't know if I so call/get the average indexed value in the mintDsc function or in the _getUsdValue function, I think doing it in the mintDsc function will be simpler because we would have to change multiple functions to handle the extra information so something like this maybe?

function mintDsc(uint256 amountDscToMint) public moreThanZero(amountDscToMint) nonReentrant {
    // Retrieve the indexed average price from the IndexedAssetPriceFeed contract
    uint256 indexedPrice = indexedAssetPriceFeed.getLatestPrice();
    
    // Calculate the total value of the collateral in indexed units
    uint256 collateralValueInIndexedUnits = (amountDscToMint * indexedPrice) / PRECISION;
    
    // Check if the collateral value meets the minimum requirements for minting
    uint256 totalCollateralValueInIndexedUnits = getAccountCollateralValue(msg.sender);
    require(totalCollateralValueInIndexedUnits >= collateralValueInIndexedUnits, "Insufficient collateral");
    
    // Update the amount of DSC minted by the user
    s_DSCMinted[msg.sender] += amountDscToMint;
    
    // Mint the DSC tokens
    bool minted = i_dsc.mint(msg.sender, amountDscToMint);
    require(minted, "Minting failed");
    
    // Revert if the health factor is broken after minting
    revertIfHealthFactorIsBroken(msg.sender);
}

I know I am asking a lot but please help, I am also not sure that I 100% understand everything, maybe there is something I overlooked so if a more advanced dev comes up with a completely different solution it's cool.

Thank you to anyone willing to help. Please ask if there is any confusion about anything.

1 Answer 1

0

I figured it out this proposed solution work with a small modification from this:

function mintDsc(uint256 amountDscToMint) public moreThanZero(amountDscToMint) nonReentrant {
    // Retrieve the indexed average price from the IndexedAssetPriceFeed contract
    uint256 indexedPrice = indexedAssetPriceFeed.getLatestPrice();
    
    // Calculate the total value of the collateral in indexed units
    uint256 collateralValueInIndexedUnits = (amountDscToMint * indexedPrice) / PRECISION;
    
    // Check if the collateral value meets the minimum requirements for minting
    uint256 totalCollateralValueInIndexedUnits = getAccountCollateralValue(msg.sender);
    require(totalCollateralValueInIndexedUnits >= collateralValueInIndexedUnits, "Insufficient collateral");
    
    // Update the amount of DSC minted by the user
    s_DSCMinted[msg.sender] += amountDscToMint;
    
    // Mint the DSC tokens
    bool minted = i_dsc.mint(msg.sender, amountDscToMint);
    require(minted, "Minting failed");
    
    // Revert if the health factor is broken after minting
    revertIfHealthFactorIsBroken(msg.sender);
}

to this,

function mintDsc(uint256 amountDscToMint) public moreThanZero(amountDscToMint) nonReentrant {
        // Retrieve the indexed average price from the IndexedAssetPriceFeed contract
        uint256 indexedPrice = indexedAssetPriceFeed.getLatestPrice();
        
        // Calculate the total value of the collateral in indexed units
        uint256 collateralValueInIndexedUnits = (amountDscToMint * indexedPrice) / PRECISION;
        
        // Check if the collateral value meets the minimum requirements for minting
        uint256 totalCollateralValueInIndexedUnits = getAccountCollateralValue(msg.sender);
        require(totalCollateralValueInIndexedUnits >= collateralValueInIndexedUnits, "Insufficient collateral");
        
        // Update the amount of DSC minted by the user
        s_DSCMinted[msg.sender] += amountDscToMint;
        
        // Revert if the health factor is broken after minting
        revertIfHealthFactorIsBroken(msg.sender);

        // Mint the DSC tokens
        bool minted = i_dsc.mint(msg.sender, amountDscToMint);
        // require(minted, "Minting failed");
        
        if (minted != true) {
            revert DSCEngine__MintFailed();
        }
        
    }

and it worked. didn't have to modify any other functions except the constructor and the deploy script, helperConfig script, and one of the tests.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.