Solidity: How to Send Ether to Another Contract’s Payable Function

solidity

I am trying to send pay a dividend token contract Ether from another contract using the deposit() function in the contract below. I have found conflicting answers based on different compiler versions.

Below is the token contract that accepts deposits which are paid out as dividends:

pragma solidity ^0.4.19;

contract RobustDividendToken {

    string public name = "Robust Dividend Token";
    string public symbol = "DIV";
    uint8 public decimals = 18;

    uint256 public totalSupply = 1000000 * (uint256(10) ** decimals);

    mapping(address => uint256) public balanceOf;

    function RobustDividendToken() public {
        // Initially assign all tokens to the contract's creator.
        balanceOf[msg.sender] = totalSupply;
        Transfer(address(0), msg.sender, totalSupply);
    }

    uint256 public scaling = uint256(10) ** 8;

    mapping(address => uint256) public scaledDividendBalanceOf;

    uint256 public scaledDividendPerToken;

    mapping(address => uint256) public scaledDividendCreditedTo;

    function update(address account) internal {
        uint256 owed =
            scaledDividendPerToken - scaledDividendCreditedTo[account];
        scaledDividendBalanceOf[account] += balanceOf[account] * owed;
        scaledDividendCreditedTo[account] = scaledDividendPerToken;
    }

    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);

    mapping(address => mapping(address => uint256)) public allowance;

    function transfer(address to, uint256 value) public returns (bool success) {
        require(balanceOf[msg.sender] >= value);

        update(msg.sender);
        update(to);

        balanceOf[msg.sender] -= value;
        balanceOf[to] += value;

        Transfer(msg.sender, to, value);
        return true;
    }

    function transferFrom(address from, address to, uint256 value)
        public
        returns (bool success)
    {
        require(value <= balanceOf[from]);
        require(value <= allowance[from][msg.sender]);

        update(from);
        update(to);

        balanceOf[from] -= value;
        balanceOf[to] += value;
        allowance[from][msg.sender] -= value;
        Transfer(from, to, value);
        return true;
    }

    uint256 public scaledRemainder = 0;

    function deposit() public payable {
        // scale the deposit and add the previous remainder
        uint256 available = (msg.value * scaling) + scaledRemainder;

        scaledDividendPerToken += available / totalSupply;

        // compute the new remainder
        scaledRemainder = available % totalSupply;
    }

    function withdraw() public {
        update(msg.sender);
        uint256 amount = scaledDividendBalanceOf[msg.sender] / scaling;
        scaledDividendBalanceOf[msg.sender] %= scaling;  // retain the remainder
        msg.sender.transfer(amount);
    }

    function approve(address spender, uint256 value)
        public
        returns (bool success)
    {
        allowance[msg.sender][spender] = value;
        Approval(msg.sender, spender, value);
        return true;
    }

}

My contract works except for this operation. If I were to simple send a random address with: randomaddr.transfer(this.balance); then we have no problems.

However, when I try TokenContractAddress.call.value(this.balance)(); or I try TokenContractAddress.deposit.value(this.balance)(); the Tx fails.

I have tried importing the contract and some other syntax too, but I get the same error. What is the best way to make it work?

Best Answer

The following won't succeed because the target contract doesn't define a payable fallback function:

TokenContractAddress.call.value(this.balance)();

Your other attempt is correct, assuming TokenContractAddress is a variable of type RobustDividendToken that points to the deployed RobustDividendToken contract:

TokenContractAddress.deposit.value(this.balance)();

If this is failing, please provide the full code that you're using and describe how you're deploying each contract and how TokenContractAddress gets its value.

Here's a test contract I made that is able to successfully call RobustDividendToken's deposit function:

contract Test {
    RobustDividendToken token;

    function Test(RobustDividendToken _token) public {
        token = _token;
    }

    function deposit() public payable {
        token.deposit.value(msg.value)();
    }
}

I deployed RobustDividendToken via Remix, then copied its address and deployed Test passing that address as a constructor parameter. (Be sure to pass the address as a quoted string.) Then I set the value field in Remix to a non-zero value and called deposit on Test. The transaction succeeded.

Related Topic