error [Revert] OwnableUnauthorizedAccount
when testing StableCoin contract
#3061
-
I keep getting this error Any suggestions are appreciated. Thanks in advance Here is my test function (I also copied Patrck's solution from the repo, but got the same error) function testRevertIfMintFails() public {
address owner = msg.sender;
vm.prank(owner);
MockFailedMint mockDSC = new MockFailedMint();
ERC20Mock(address(mockDSC)).mint(USER, STARTING_ERC20_BALANCE);
tokenAddresses = [weth];
priceFeedAddresses = [ethUSDPriceFeed];
vm.prank(owner);
DSCEngine mockDSCE = new DSCEngine(tokenAddresses, priceFeedAddresses, address(mockDSC));
mockDSC.transferOwnership(address(mockDSCE));
vm.startPrank(USER);
ERC20Mock(weth).approve(address(mockDSCE), AMOUNT_COLLATERAL);
vm.expectRevert(DSCEngine.DSCEngine__FailedMint.selector);
// mockDSCE.depositCollateralAndMintDSC(weth, AMOUNT_COLLATERAL, AMOUNT_TO_MINT);
mockDSCE.depositCollateral(weth, AMOUNT_COLLATERAL);
mockDSCE.mintDSC(AMOUNT_TO_MINT);
vm.stopPrank();
}
Here are my traces Traces:
[9070883] DSCEngineTest::setUp()
├─ [4020885] → new DeployDSC@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f
│ └─ ← [Return] 19971 bytes of code
├─ [4752401] DeployDSC::run()
│ ├─ [2984545] → new HelperConfig@0x104fBc016F4bb334D775a19E8A6510109AC63E00
│ │ ├─ [0] VM::startBroadcast()
│ │ │ └─ ← [Return]
│ │ ├─ [362441] → new MockV3Aggregator@0x34A1D3fff3958843C43aD80F30b94c510645C316
│ │ │ └─ ← [Return] 1033 bytes of code
│ │ ├─ [437024] → new ERC20Mock@0x90193C961A926261B756D1E5bb255e67ff9498A1
│ │ │ └─ ← [Return] 1953 bytes of code
│ │ ├─ [362441] → new MockV3Aggregator@0xA8452Ec99ce0C64f20701dB7dD3abDb607c00496
│ │ │ └─ ← [Return] 1033 bytes of code
│ │ ├─ [437024] → new ERC20Mock@0xBb2180ebd78ce97360503434eD37fcf4a1Df61c3
│ │ │ └─ ← [Return] 1953 bytes of code
│ │ ├─ [0] VM::stopBroadcast()
│ │ │ └─ ← [Return]
│ │ └─ ← [Return] 5588 bytes of code
│ ├─ [958] HelperConfig::activeNetworkConfig() [staticcall]
│ │ └─ ← [Return] MockV3Aggregator: [0x34A1D3fff3958843C43aD80F30b94c510645C316], MockV3Aggregator: [0xA8452Ec99ce0C64f20701dB7dD3abDb607c00496], ERC20Mock: [0x90193C961A926261B756D1E5bb255e67ff9498A1], ERC20Mock: [0xBb2180ebd78ce97360503434eD37fcf4a1Df61c3], DefaultSender: [0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38]
│ ├─ [0] VM::startBroadcast(DefaultSender: [0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38])
│ │ └─ ← [Return]
│ ├─ [576041] → new DecentralizedStableCoin@0xDB8cFf278adCCF9E9b5da745B44E754fC4EE3C76
│ │ ├─ emit OwnershipTransferred(previousOwner: 0x0000000000000000000000000000000000000000, newOwner: DefaultSender: [0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38])
│ │ └─ ← [Return] 2533 bytes of code
│ ├─ [905885] → new DSCEngine@0x50EEf481cae4250d252Ae577A09bF514f224C6C4
│ │ └─ ← [Return] 3847 bytes of code
│ ├─ [2421] DecentralizedStableCoin::transferOwnership(DSCEngine: [0x50EEf481cae4250d252Ae577A09bF514f224C6C4])
│ │ ├─ emit OwnershipTransferred(previousOwner: DefaultSender: [0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38], newOwner: DSCEngine: [0x50EEf481cae4250d252Ae577A09bF514f224C6C4])
│ │ └─ ← [Stop]
│ ├─ [0] VM::stopBroadcast()
│ │ └─ ← [Return]
│ └─ ← [Return] DecentralizedStableCoin: [0xDB8cFf278adCCF9E9b5da745B44E754fC4EE3C76], DSCEngine: [0x50EEf481cae4250d252Ae577A09bF514f224C6C4], HelperConfig: [0x104fBc016F4bb334D775a19E8A6510109AC63E00]
├─ [958] HelperConfig::activeNetworkConfig() [staticcall]
│ └─ ← [Return] MockV3Aggregator: [0x34A1D3fff3958843C43aD80F30b94c510645C316], MockV3Aggregator: [0xA8452Ec99ce0C64f20701dB7dD3abDb607c00496], ERC20Mock: [0x90193C961A926261B756D1E5bb255e67ff9498A1], ERC20Mock: [0xBb2180ebd78ce97360503434eD37fcf4a1Df61c3], DefaultSender: [0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38]
├─ [46783] ERC20Mock::mint(user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], 10000000000000000000 [1e19])
│ ├─ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], value: 10000000000000000000 [1e19])
│ └─ ← [Stop]
├─ [46783] ERC20Mock::mint(user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], 10000000000000000000 [1e19])
│ ├─ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], value: 10000000000000000000 [1e19])
│ └─ ← [Stop]
└─ ← [Stop]
[615229] DSCEngineTest::testRevertIfMintFails()
├─ [0] VM::prank(DefaultSender: [0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38])
│ └─ ← [Return]
├─ [576035] → new MockFailedMint@0xDEb1E9a6Be7Baf84208BB6E10aC9F9bbE1D70809
│ ├─ emit OwnershipTransferred(previousOwner: 0x0000000000000000000000000000000000000000, newOwner: DefaultSender: [0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38])
│ ├─ storage changes:
│ │ @ 3: 0 → 0x446563656e7472616c697a6564537461626c65436f696e00000000000000002e
│ │ @ 5: 0 → 0x0000000000000000000000001804c8ab1f12e6bbf3894d4083f33e07309d1f38
│ │ @ 4: 0 → 0x4453430000000000000000000000000000000000000000000000000000000006
│ └─ ← [Return] 2533 bytes of code
├─ [614] MockFailedMint::mint(user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], 10000000000000000000 [1e19])
│ └─ ← [Revert] OwnableUnauthorizedAccount(0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496)
└─ ← [Revert] OwnableUnauthorizedAccount(0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496)
Suite result: FAILED. 0 passed; 1 failed; 0 skipped; finished in 1.61ms (273.60µs CPU time)
Ran 1 test suite in 1.04s (1.61ms CPU time): 0 tests passed, 1 failed, 0 skipped (1 total tests)
Failing tests:
Encountered 1 failing test in test/unit/DSCEngineTest.t.sol:DSCEngineTest
[FAIL: OwnableUnauthorizedAccount(0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496)] testRevertIfMintFails() (gas: 615229) here is my contract // SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import {ERC20Burnable, ERC20} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import {DecentralizedStableCoin} from "../src/DecentralizedStableCoin.sol";
/**
* @title DSCEngine
* @author yawarasuuna
*
* The system is designed to be as minimal as possible, and have the tokens maintain a 1 token == USD 1 peg.
* This stablecoin has the properties:
* - Exogenous Collateral
* - Dollar Pegged
* - Algorithmically Stable
*
* It is similar to DAI as if it had no governance, no fees, and only backed by WETH and WBTC.
*
* DSC System should always be overcollateralized. The dollar backed value of all DSC should NOT be, at any point, greater or equal than the sum of all collateral in the protocol.
*
* @notice This contract is the core of DSC System. It handles all the logic for minting and redeeming DSC, as well as depositing & withdrawing collateral.
* @notice This contract is very loosely based on the MakerDao DSS (DAI) system.
*/
contract DSCEngine is ReentrancyGuard {
/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
error DSCEngine__MustBeGreaterThanZero();
error DSCEngine__NotAllowedToken();
error DSCEngine__LengthMustBeEqualForTokenAddressesAndPriceFeedAddresses();
error DSCEngine__FailedMint();
error DSCEngine__FailedTransfer();
error DSCEngine__NotImprovedHealthFactor();
error DSCEngine__OkHealthFactor();
error DSCEngine__ViolatedHealthFactor();
/*//////////////////////////////////////////////////////////////
STATE VARIABLES
//////////////////////////////////////////////////////////////*/
uint256 private constant ADDITIONAL_FEED_PRECISION = 1e10;
uint256 private constant PRECISION = 1e18;
uint256 private constant LIQUIDATION_BONUS = 10;
uint256 private constant LIQUIDATION_THRESHOLD = 50; // 200% collateralized
uint256 private constant LIQUIDATION_PRECISION = 100;
uint256 private constant MIN_HEALTH_FACTOR = 1e18;
// mapping(address => bool) private s_tokenToAllowed; // if we were to do it manually, but we'll use price feeds
mapping(address token => address priceFeed) private s_priceFeed; // new convention, used to be s_tokenToPriceFeed
mapping(address user => mapping(address token => uint256 amount)) private s_collateralDeposited;
mapping(address user => uint256 amountOfDSCMinted) private s_mintedDSC;
address[] private s_collateralTokens;
DecentralizedStableCoin private immutable i_dsc;
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event CollateralDeposited(address indexed user, address indexed tokenCollateral, uint256 indexed amountDeposited);
event CollateralRedeemed(
address indexed redeemedFrom,
address indexed redeemedTo,
address indexed tokenCollateral,
uint256 amountRedeemed
);
/*//////////////////////////////////////////////////////////////
MODIFIERS
//////////////////////////////////////////////////////////////*/
modifier moreThanZero(uint256 amount) {
if (amount <= 0) {
revert DSCEngine__MustBeGreaterThanZero();
}
_;
}
modifier isAllowedToken(address token) {
if (s_priceFeed[token] == address(0)) {
revert DSCEngine__NotAllowedToken();
}
_;
}
/*//////////////////////////////////////////////////////////////
FUNCTIONS
//////////////////////////////////////////////////////////////*/
constructor(address[] memory tokenAddresses, address[] memory priceFeedAddresses, address dscAddress) {
// USD Price Feed
if (tokenAddresses.length != priceFeedAddresses.length) {
revert DSCEngine__LengthMustBeEqualForTokenAddressesAndPriceFeedAddresses();
}
for (uint256 i = 0; i < tokenAddresses.length; i++) {
s_priceFeed[tokenAddresses[i]] = priceFeedAddresses[i];
s_collateralTokens.push(tokenAddresses[i]);
}
i_dsc = DecentralizedStableCoin(dscAddress);
}
/*//////////////////////////////////////////////////////////////
EXTERNAL FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
*
* @param tokenCollateralAddress The address of the token to deposit as collateral
* @param amountCollateral The amount of collateral to deposit
* @param amountDSCToMint The amount of decentralized stablecoin to mint
* @notice This function will deposit collateral and mint DSC in one function
* @notice It must have more collateral value than the minimum threshold
*/
function depositCollateralAndMintDSC(
address tokenCollateralAddress,
uint256 amountCollateral,
uint256 amountDSCToMint
) external {
depositCollateral(tokenCollateralAddress, amountCollateral);
mintDSC(amountDSCToMint);
}
/**
* @param tokenCollateralAddress The address of the token to deposit as collateral
* @param amountCollateral The amount of collateral to deposit
* @notice This function will only deposit collateral
*/
function depositCollateral(address tokenCollateralAddress, uint256 amountCollateral)
public
moreThanZero(amountCollateral)
isAllowedToken(tokenCollateralAddress)
nonReentrant
{
s_collateralDeposited[msg.sender][tokenCollateralAddress] += amountCollateral;
// updates state, so we should emit an event
emit CollateralDeposited(msg.sender, tokenCollateralAddress, amountCollateral);
bool sucess = IERC20(tokenCollateralAddress).transferFrom(msg.sender, address(this), amountCollateral);
if (!sucess) {
revert DSCEngine__FailedTransfer();
}
}
/**
* @param tokenCollateralAddress The address of the token to redeem as collateral
* @param amountCollateral The amount of collateral to redeem
* @param amountDSCToBurn The amount of decentralized stablecoin to burn
* @notice This function will redeem collateral and burn DSC in one function
* @notice It must have more collateral value than the minimum threshold
*/
function redeemCollateralForDSC(address tokenCollateralAddress, uint256 amountCollateral, uint256 amountDSCToBurn)
external
{
burnDSC(amountDSCToBurn);
redeemCollateral(tokenCollateralAddress, amountCollateral);
// redeemCollateral already checks health factor
}
/**
* @param tokenCollateralAddress The address of the token to redeem as collateral
* @param amountCollateral The amount of collateral to redeem
* @notice This function will only redeem collateral
* @notice It must have more collateral value than the minimum threshold
* DRY: dont repeat yourself
*/
function redeemCollateral(address tokenCollateralAddress, uint256 amountCollateral)
public
moreThanZero(amountCollateral)
nonReentrant
{
// v1
// s_collateralDeposited[msg.sender][tokenCollateralAddress] -= amountCollateral;
// emit CollateralRedeemed(msg.sender, tokenCollateralAddress, amountCollateral);
// bool success = IERC20(tokenCollateralAddress).transfer(msg.sender, amountCollateral);
// if (!success) {
// revert DSCEngine__FailedTransfer();
// }
// v2
_redeemCollateral(tokenCollateralAddress, amountCollateral, msg.sender, msg.sender);
_revertIfHealthFactorIsViolated(msg.sender);
}
/**
* @param amountDSCToMint The amount of decentralized stablecoin to mint
* @notice It must have more collateral value than the minimum threshold
*/
function mintDSC(uint256 amountDSCToMint) public moreThanZero(amountDSCToMint) nonReentrant {
s_mintedDSC[msg.sender] += amountDSCToMint;
_revertIfHealthFactorIsViolated(msg.sender);
bool minted = i_dsc.mint(msg.sender, amountDSCToMint);
if (!minted) {
revert DSCEngine__FailedMint();
}
}
/**
* @param amountDSCToBurn The amount of decentralized stablecoin to burn
*/
function burnDSC(uint256 amountDSCToBurn) public moreThanZero(amountDSCToBurn) {
// v1
// s_mintedDSC[msg.sender] -= amountDSCToBurn;
// bool success = i_dsc.transferFrom(msg.sender, address(this), amountDSCToBurn);
// if (!success) {
// revert DSCEngine__FailedTransfer(); // hypothetically unreachable?
// }
// i_dsc.burn(amountDSCToBurn);
// v2
_burnDSC(amountDSCToBurn, msg.sender, msg.sender);
_revertIfHealthFactorIsViolated(msg.sender); // hypothetically unreachable?
}
/**
* @param tokenCollateralAddress The ERC20 collateral address to liquidate from the user
* @param user who has broken the health factor. Their _healthFactor should be below MIN_HEALTH_FACTOR
* @param debtToCover The amount of DSC you want to burn to improve the users health factor
* @notice You can partially liquidate a user.
* @notice You will get a liquidation bonus for taking the users fund.
* @notice This function working assumes the protocol will be roughly 200% overcollateralized in order for this to work.
* @notice A known bug would be if the protocol were 100% or less collateralized, then we wouldn't be able to incentivize liquidators.
* For example, if the price of the collateral plummeted before anyone could be liquidated.
*/
function liquidate(address tokenCollateralAddress, address user, uint256 debtToCover)
external
moreThanZero(debtToCover)
nonReentrant
{
uint256 startingUserHealthFactor = _healthFactor(user);
if (startingUserHealthFactor >= MIN_HEALTH_FACTOR) {
revert DSCEngine__OkHealthFactor();
}
uint256 tokenAmountFromDebtCovered = getTokenAmountFromUSD(tokenCollateralAddress, debtToCover);
uint256 bonusCollateral = tokenAmountFromDebtCovered * LIQUIDATION_BONUS / LIQUIDATION_PRECISION;
uint256 totalCollateralToRedeem = tokenAmountFromDebtCovered + bonusCollateral;
_redeemCollateral(tokenCollateralAddress, totalCollateralToRedeem, user, msg.sender);
_burnDSC(debtToCover, user, msg.sender);
uint256 endingUserHealthFactor = _healthFactor(user);
if (endingUserHealthFactor <= startingUserHealthFactor) {
revert DSCEngine__NotImprovedHealthFactor();
}
_revertIfHealthFactorIsViolated(msg.sender);
}
function getHealthFactor() external view {}
/*//////////////////////////////////////////////////////////////
PRIVATE AND INTERNAL VIEW FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @dev Low-level internal function, don't call unless the function callint it is checking for health factors being broken
*/
function _burnDSC(uint256 amountDSCToBurn, address onBehalfOf, address dscFrom) private {
s_mintedDSC[onBehalfOf] -= amountDSCToBurn;
bool success = i_dsc.transferFrom(dscFrom, address(this), amountDSCToBurn);
if (!success) {
revert DSCEngine__FailedTransfer();
}
i_dsc.burn(amountDSCToBurn);
}
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__FailedTransfer();
}
}
function _getAccountInformation(address user)
private
view
returns (uint256 totalDSCMinted, uint256 collateralValueInUSD)
{
totalDSCMinted = s_mintedDSC[user];
collateralValueInUSD = getAccountCollateralValue(user);
}
/**
* Returns how close to liquidation a user is
* If it goes below 1, user is liquidated
*/
function _healthFactor(address user) private view returns (uint256) {
// amount of collateral value
// amount of DSC Minted
(uint256 totalDSCMinted, uint256 collateralValueInUSD) = _getAccountInformation(user);
uint256 collateralAdjustedForThreshold = (collateralValueInUSD * LIQUIDATION_THRESHOLD) / LIQUIDATION_PRECISION;
return (collateralAdjustedForThreshold * PRECISION) / totalDSCMinted;
}
/**
* Checks health factor to know if they have enough collateral
* Otherwise it reverts
*/
function _revertIfHealthFactorIsViolated(address user) internal view {
uint256 userHealthFactor = _healthFactor(user);
if (userHealthFactor < MIN_HEALTH_FACTOR) {
revert DSCEngine__ViolatedHealthFactor();
}
}
/*//////////////////////////////////////////////////////////////
PUBLIC & EXTERNAL VIEW FUNCTIONS
//////////////////////////////////////////////////////////////*/
function getTokenAmountFromUSD(address token, uint256 usdAmountInWei) public view returns (uint256) {
AggregatorV3Interface priceFeed = AggregatorV3Interface(s_priceFeed[token]);
(, int256 price,,,) = priceFeed.latestRoundData();
return (usdAmountInWei * PRECISION / (uint256(price) * ADDITIONAL_FEED_PRECISION));
}
function getAccountCollateralValue(address user) public view returns (uint256 totalCollateralValueInUSD) {
// loop through each collateral token, get amount deposited, map it to price, to get usd value
for (uint256 i = 0; i < s_collateralTokens.length; i++) {
address token = s_collateralTokens[i];
uint256 amount = s_collateralDeposited[user][token];
totalCollateralValueInUSD += getUSDValue(token, amount);
}
return totalCollateralValueInUSD;
}
function getUSDValue(address token, uint256 amount) public view returns (uint256) {
AggregatorV3Interface priceFeed = AggregatorV3Interface(s_priceFeed[token]);
(, int256 price,,,) = priceFeed.latestRoundData();
return ((uint256(price) * ADDITIONAL_FEED_PRECISION) * amount) / PRECISION;
}
} here is my mock contract // SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {ERC20Burnable, ERC20} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
contract MockFailedMint is ERC20Burnable, Ownable {
error DecentralizedStableCoin__CannotBurnZeroTokens();
error DecentralizedStableCoin__BalanceLowerThanBurnAmount();
error DecentralizedStableCoin__CannotMintToZeroAddress();
error DecentralizedStableCoin__CannotMintZero();
/*
In future versions of OpenZeppelin contracts package, Ownable must be declared with an address of the contract owner
as a parameter.
For example:
constructor() ERC20("DecentralizedStableCoin", "DSC") Ownable(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266) {}
Related code changes can be viewed in this commit:
https://github.com/OpenZeppelin/openzeppelin-contracts/commit/13d5e0466a9855e9305119ed383e54fc913fdc60
*/
constructor() ERC20("DecentralizedStableCoin", "DSC") Ownable(msg.sender) {}
function burn(uint256 _amount) public override onlyOwner {
uint256 balance = balanceOf(msg.sender);
if (_amount <= 0) {
revert DecentralizedStableCoin__CannotBurnZeroTokens();
}
if (balance < _amount) {
revert DecentralizedStableCoin__BalanceLowerThanBurnAmount();
}
super.burn(_amount);
}
function mint(address _to, uint256 _amount) external onlyOwner returns (bool) {
if (_to == address(0)) {
revert DecentralizedStableCoin__CannotMintToZeroAddress();
}
if (_amount <= 0) {
revert DecentralizedStableCoin__CannotMintZero();
}
_mint(_to, _amount);
return false;
}
} ownable contract // SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
} |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 6 replies
-
Hello @yawarasuuna, Please have your test as the below then retry and let's see if it still fails. function testRevertIfMintFails() public {
address owner = msg.sender;
vm.prank(owner);
MockFailedMint mockDSC = new MockFailedMint();
ERC20Mock(address(mockDSC)).mint(USER, STARTING_ERC20_BALANCE);
tokenAddresses = [weth];
priceFeedAddresses = [ethUSDPriceFeed];
vm.statPrank(owner);
DSCEngine mockDSCE = new DSCEngine(tokenAddresses, priceFeedAddresses, address(mockDSC));
mockDSC.transferOwnership(address(mockDSCE));
vm.stopPrank();
vm.startPrank(USER);
ERC20Mock(weth).approve(address(mockDSCE), AMOUNT_COLLATERAL);
vm.expectRevert(DSCEngine.DSCEngine__FailedMint.selector);
// mockDSCE.depositCollateralAndMintDSC(weth, AMOUNT_COLLATERAL, AMOUNT_TO_MINT);
mockDSCE.depositCollateral(weth, AMOUNT_COLLATERAL);
mockDSCE.mintDSC(AMOUNT_TO_MINT);
vm.stopPrank();
} |
Beta Was this translation helpful? Give feedback.
Confirm who the owner is on the
MockFailedMint
contract and from there we can start figuring what the problem is.