2

I have a function that needs to make transfers to a token smart contract as well as personal accounts upon satisfaction of some conditions.

function completeSale() onlyOwner public {
        if (something == true && balance >= requested) {
            tokenContract.transfer(requested/100);
            seller.transfer(requested - (requested/100));
            buyer.transfer(balance - requested);
            assert(address(this).balance == 0);
            complete = true;
        }
    }

However, looking at the ERC20 standard, transfer is implemented as a token method:

 function transfer(address to, uint tokens) public returns (bool success) {
         balances[msg.sender] = balances[msg.sender].sub(tokens);
         balances[to] = balances[to].add(tokens);
         emit Transfer(msg.sender, to, tokens);
         return true;    }

How does one then transfer value in ether to an ERC20 smart contract? Is this possible without writing another function that then requires a low level call (i.e. tokenAddress.myPayMethod.value(x) or tokenAddress.call.value(x)())?

2 Answers 2

0

You don't generally do that. It's a matter of separation of concerns.

The OP didn't say exactly what the end goal is. A common scenario is a token contract and a crowdsale contract. Let each one do what they do and don't mix up concerns.

The ERC20 contract's job is to keep track of use balances and facilitate transfers. That's it. Anything beyond that is creeping beyond the concerns of minting/supply and basic accounting.

A CrowdSale would typically offer some tokens for sale at some (business rule) price. This "store" is "stocked" with merchandise (the tokens) and it sells, possibly buys in exchange for ETH. Thus, it has simple functions to accept Ether and transfer tokens that it has, and possibly a method to redeem tokens. It's not concerned with wallets. The ERC20 "minter" or "deployer" usually receives the initial supply and can safely store the tokens, periodically "restocking" the store as the tokens are sold.

Things will work out much simpler if the token contract is considered separately from whatever activities one might want to use it for.

Hope it helps.

1
  • Thanks @Rob, I figured this out soon after posting. It's a matter function overloading and assuming function signatures don't collide. The question was more of an academic one, which I left up in case others were confused about how token transfer is differentiated from ether transfer. Of course, good design practice mandate separation of concerns, especially when funds are concerned. Jan 9, 2019 at 18:50
-1

Those two functions have different signatures. Function which transfer ETH is

function transfer(uint _value) public;

And the one which transfer tokens have two parameters

function transfer(address _to, uint _amount) public;

You can use them both. Just provide different parameters.

Look at the code below which implements exactly what you want to do. You can copy it to Remix and test it. Create two instances of ERC20Test contract and transfer to one of them some balance ( ETH ). Then you can call transferETHToERC20 from the contract which has some ether to transfer it to another ERC20Test contract.

You can also call transferTokentoERC20 to transfer tokens. Just make sure that ERC20Test contract which is calling transferTokentoERC20 function of another ERC20Test contract has some token balance.

Warning ! This contract is not 100% safe. It is not making sure there will be not uint overflow. It was written only to present answer to this question and is only implementing neccessary ERC20 functions.

pragma solidity 0.4.24;


contract ERC20Test
{

    mapping(address => uint256) balances;
    uint256 totalSupply_ = 100;
    event Transfer(address from, address to, uint256 value);

    function () payable 
    {
        return;
    }

    function transferETHToERC20(ERC20Test token, uint256 value) public
    {
        token.transfer(value); //this is going to transfer ETH.Only one parameter is provided
    }

    function transferTokentoERC20(ERC20Test token,address _to, uint amount) public 
    {
        token.transfer(_to,amount); //this will transfer tokens.two parameters
    }


    function returnBalance() public view returns (uint256)
    {
        return this.balance;

    }

    function totalSupply() public view returns (uint256) 
    {
    return totalSupply_;
    }

    constructor ()
    {
        balances[msg.sender] = totalSupply_;
    }
    function transfer(address _to, uint256 _value) public returns (bool) {
    require(_to != address(0));
    require(_value <= balances[msg.sender]);

    balances[msg.sender] = balances[msg.sender]- _value;
    balances[_to] = balances[_to] + _value;
    emit Transfer(msg.sender, _to, _value);
    return true;
    }

    function balanceOf(address _owner) public view  returns (uint256)
    {
        return balances[_owner];
    }

}
3
  • Thanks for the fantastic response. My suspicion was that both transfer methods would work because the function call code is based on hash of the function declarations–the signatures you mentioned–but being such a high security issue, I wanted some confirmation. Appreciate it! Jul 23, 2018 at 1:52
  • One note here. If you want another ERC20Test token to transfer ETH to some other address then you will have to write another function for it. I am talking about scenario when you want to ERC20Test token1 to call function of ERC20Test token2 to transfer ETH to ERC20Test token3. If in token1 you are calling token2.transfer(1) it will transfer 1 wei from token1 to token2. if from token1 you are calling token2.transfer(token3,1) then it will transfer 1 token of contract token2 from token1 to token3. I hope it is not too complicated.
    – Rob Magier
    Jul 23, 2018 at 2:03
  • Not at all, just have to create a function (on contract 2) to call and that function signature cannot collide with another method. Thanks again! Aug 2, 2018 at 23:18

Your Answer

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

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