6

Is it possible when calling a contract from another one to specify the sender?

Something like the API exposed by web3.

function sendTokensToContract() {
    //Send tokens from this contract to this contract (?!)
    token.transfer(this, amount); 

    //Send tokens from sender to this contract
    token.transfer(this, assetPrice, {sender: msg.sender});
} 

Thanks.

1 Answer 1

5

No, but yes.

No, because the contract can't send anything from anything other than itself. There's no {from: account} possibility. Transactions are "from" the contract. No exceptions.

Yes, because if the token contract is in charge of maintaining a ledger for tokens or something else it tracks, then it merely needs to perform some internal bookkeeping operations.

Just a simplified example with illustration about the functionality needed in token.transfer. Be really careful about making sure you haven't opened it up to users spending tokens from any old account. That would be chaos:

function sendTokensFromAnywhere(address sender, address receiver, uint amount) 
    onlyAuthorized // needs definition, or look at 2nd example
    returns(bool success)
{
    token.transfer(sender, receiver, amount); 
    return true;
} 

contract Token {

  modifier onlyOwner() {
    // owner is trusted, but no one else
    if(msg.sender != owner) throw;
    _;
  }

  function Token() {
    // assume deployment originates from the "owner"
    owner = msg.sender; 
    // owner will be the only contract authorized to use transfer()
  }
...
  function transfer(address sender, address receiver, uint amount) 
    onlyOwner  // sender is obviously dangerous, so control who can call this
    returns (bool success)
  {
    if(balances[sender] < amount) throw;
    balances[sender] -= amount;
    balances[receiver] += amount;
    return true;
  }

In practice, the functions exposed to the public should probably ensure users can only transfer from their own accounts:

function sendTokensFromAnywhere(address receiver, uint amount) 
    public
    returns(bool success)
{
    token.transfer(msg.sender, receiver, amount); // only own tokens
    return true;
} 

The entity calling the function can only transfer() from its own assets, so we can remove onlyAuthorized instead of defining it.

With a little added caution, (although nothing in token.transfer currently returns false):

function sendTokensFromAnywhere(address receiver, uint amount) 
    public
    returns(bool success)
{
    if(token.transfer(msg.sender, receiver, amount)) return true;
    // looks like something went wrong with the transfer
    throw;
} 

Hope it helps.

4
  • Thanks. But what about callcode and delegatecall? I tried to follow this approach ethereum.stackexchange.com/questions/3667/… But when I call a given function using delegatecall or callcode that function is never executed. Jan 4, 2017 at 17:28
  • I may be mistaken, but I think callcode and delegatecall solve different problems than what this is about. Jan 4, 2017 at 17:47
  • I don't really know. But it seems to be related with this issue: "When an account C invokes D, and D does DELEGATECALL on E, msg.sender inside E is C. That is, E has the same msg.sender and msg.value as D". Jan 4, 2017 at 17:49
  • It rhymes, but no.Those ideas provide some tools for possibly upgrading your contract software in the future by engineering some modularity into it at the outset. If the "sender" is going to be a user as I've been assuming, then we have no control over it and those solutions aren't helpful. Jan 4, 2017 at 18:03

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.