solidity – How to Withdraw Amount from Deployed Ethereum Contract

contract-developmentremixsolidity

Normally we use owner-only restrictions for the withdrawal functions but still, I'm curious why it didn't work.

I created a sender and receiver contract. After deploying the contract I kept some amount in the contract. Then I tried to withdraw that balance amount from another contract. I wrote two functions to try two different ways. One is using the interface and one is without it.

I'm not sure what I'm doing is the right way. Please help me to learn.

I got an error when I try to withdraw it from the contract WithrawAmtFromAnotherContract

Like this:

transact to WithrawAmtFromAnotherContract.stealAmntFromContract1
errored: VM error: revert.

revert The transaction has been reverted to the initial state. Note:
The called function should be payable if you send value and the value
you send should be less than your current balance. Debug the
transaction to get more information.

This is the code:

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

contract ReceiveEther {

    receive() external payable {}
    fallback() external payable {}

    function getBalance() public view returns (uint) {
        return address(this).balance;
    }

    function withdraw() public payable{
        payable(address(msg.sender)).transfer(address(this).balance);
    }
}

contract SendEther {
    function sendViaCall(address payable _to) public payable {
        // Call returns a boolean value indicating success or failure.
        // This is the current recommended method to use.
        (bool sent, bytes memory data) = _to.call{value: msg.value}("");
        require(sent, "Failed to send Ether");
    }
}

interface With{
    function getBalance() external view returns(uint);
    function withdraw() external payable;
}

contract WithrawAmtFromAnotherContract{
    function getBalance(address _address) public view returns(uint){
        return With(_address).getBalance();
    }
    function stealAmntFromContract_method1(address payable _address) public payable{
        With(_address).withdraw();
    }
    function stealAmntFromContract_method2(address payable _address) public payable{
        payable(msg.sender).transfer(_address.balance);
    }
}

Best Answer

In your case, when you call stealAmntFromContract_method1() method inside WithrawAmtFromAnotherContract the msg.sender value passed to withdraw() function inside ReceiveEther is the WithrawAmtFromAnotherContract smart contract address and for this reason you see this error. That's because, WithrawAmtFromAnotherContract call withdraw() function on your behalf and passed it its address like msg.sender. You must to change your smart contract in this way:

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

contract ReceiveEther {

    receive() external payable {}
    fallback() external payable {}

    function getBalance() public view returns (uint) {
        return address(this).balance;
    }

    function withdraw(address _to) public payable{
        payable(address(_to)).transfer(address(this).balance);
    }
}

contract SendEther {

    function sendViaCall(address payable _to) public payable {
        // Call returns a boolean value indicating success or failure.
        // This is the current recommended method to use.
        (bool sent,) = _to.call{value: msg.value}("");
        require(sent, "Failed to send Ether");
    }
}

interface With {
    function getBalance() external view returns(uint);
    function withdraw(address _to) external payable;
}

contract WithrawAmtFromAnotherContract{

    function getBalance(address _address) public view returns(uint){
        return With(_address).getBalance();
    }

    function stealAmntFromContract_method1(address _address) public {
        With(_address).withdraw(msg.sender);
    }
}

In this smart contract, I added a new input parameter call _to (datatype: address) that allows you to keep the user address that call stealAmntFromContract_method1 and pass it to widthdraw() function. At this point, this last function'll have inside _to input parameter the user address and it can transfer your balance to him.

NOTE: I also changed withdraw() signature in With interface.

Related Topic