Ownable: caller is not the owner

Hi there!

So I have created a smart contract and included the Withdrawable.sol file which inherits from the Ownable.sol file… all from your github repo. When I try to use the withdraw() function inside my smart contract, I get returned the error “Ownable: caller is not the owner”. I do understand that this function uses the “onlyOwner” modifier, but I do believe that the “owner” of the contract is the one calling this function.

I have also logged the owner of my contract in the console, just to verify that I am the owner of it… and it does in fact return my wallet address.

Here is a picture of the contract and the transaction that was reverted (due to this error).

You can see that both transactions (contract creation and the flashloan) are being sent from the same address, which is what leads to my question. Why am I receiving this error?

You can view the contract and its history here: https://kovan.etherscan.io/address/0xb22827c80c9f56dcc7d7405659eca83a440ef5cf

Hi, welcome! :wave:

Yeah, it seems like the contract owner is the contract deployer: 0xeB2D7e847b52FC05321D95d5066bE131c604d7f6, so maybe there is something else that checks the permission. I think if possible, you can share your code at here.

Yeah, totally!

This is the Withdrawable.sol code (where the withdraw function is created):


import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

/**
    Ensures that any contract that inherits from this contract is able to
    withdraw funds that are accidentally received or stuck.
 */

contract Withdrawable is Ownable {
    using SafeERC20 for ERC20;
    address constant ETHER = address(0);

    event LogWithdraw(
        address indexed _from,
        address indexed _assetAddress,
        uint amount
    );

    /**
     * @dev Withdraw asset.
     * @param _assetAddress Asset to be withdrawn.
     */
    function withdraw(address _assetAddress) public onlyOwner {
        uint assetBalance;
        if (_assetAddress == ETHER) {
            address self = address(this); // workaround for a possible solidity bug
            assetBalance = self.balance;
            msg.sender.transfer(assetBalance);
        } else {
            assetBalance = ERC20(_assetAddress).balanceOf(address(this));
            ERC20(_assetAddress).safeTransfer(msg.sender, assetBalance);
        }
        emit LogWithdraw(msg.sender, _assetAddress, assetBalance);
    }
}

And the Ownable.sol file here (the contract Withdrawable.sol inherits from)

This is where you can find the actual code for my smart contract (where the withdraw() function is called)

And finally, this is my python script that actually runs the flashloan smart contract:


MINIMUM_FLASHLOAN_WETH_BALANCE = 500000000000000000
ETHERSCAN_TX_URL = "https://kovan.etherscan.io/tx/{}"


def main():
    """
    Executes the funcitonality of the flash loan.
    """
    acct = accounts.add(config["wallets"]["from_key"])
    print("Getting Flashloan contract...")
    flashloan = FlashloanV2[len(FlashloanV2) - 1]
    weth = interface.WethInterface(config["networks"][network.show_active()]["weth"])
    # We need to fund it if it doesn't have any token to fund!
    if weth.balanceOf(flashloan) < MINIMUM_FLASHLOAN_WETH_BALANCE:
        print("Funding Flashloan contract with WETH...")
        weth.transfer(flashloan, "1 ether", {"from": acct, "gas_limit": 3000000})
    print("Executing Flashloan...")
    tx = flashloan.flashloan(weth, {"from": acct, "gas_limit": 3000000, "allow_revert": True})
    print("You did it! View your tx here: " + ETHERSCAN_TX_URL.format(tx.txid))
    return flashloan

I do believe that the only relevant code here will be the Withdrawable.sol file and Ownable.sol file (first link), but feel free to check out everything that I’ve posted (you can also view my whole github repo provided in the second link)

1 Like