Questions about Call Function

Hi,

I found this code snippet online


  /// @notice Withdraws the ether distributed to the sender.
  /// @dev It emits a `DividendWithdrawn` event if the amount of withdrawn ether is greater than 0.
  function _withdrawDividendOfUser(address payable user) internal returns (uint256) {
    uint256 _withdrawableDividend = withdrawableDividendOf(user);
    if (_withdrawableDividend > 0) {
      withdrawnDividends[user] = withdrawnDividends[user].add(_withdrawableDividend);
      emit DividendWithdrawn(user, _withdrawableDividend);
      (bool success,) = user.call{value: _withdrawableDividend, gas: 3000}("");

      if(!success) {
        withdrawnDividends[user] = withdrawnDividends[user].sub(_withdrawableDividend);
        return 0;
      }

      return _withdrawableDividend;
    }

    return 0;
  }

Does anyone know how to modify this line
(bool success,) = user.call{value: _withdrawableDividend, gas: 3000}("");

to also send any type of token instead of only ether? Or can call{} function only send ether?

Thank you

Hey @jrdefideveloper, hope you are great.

If this contract is deployed on the ethereum network for example, the gas fess are based on the Network main token, so I think that might not be the best way to transfer tokens.

If you want to transfer let’s say link, your contract should have the link token contract address assigned properly, I do remember there is a further lesson in this course which will give you an example on how to do what you ask with the Link token (instance of it, but is the same procedure) :nerd_face:

Carlos Z

Hmm I see so I still need to use the ERC-20 transfer() function as opposed to this .call{} is what you are saying?

:smiley:

Thank you for the response!

EDIT: Solidity’s author, chriseth, recommends to avoid using Solidity’s call

https://github.com/ethereum/solidity/issues/2884#issuecomment-329169020

The thing is: a.call() is an ancient beast that should not be used. I would recommend using inline assembly for such tasks, since it provides the same security guarantees but does not do any invisible magic.

Solidity’s call is a low-level interface for sending a message to a contract. It returns false if the subcall encounters an exception, otherwise it returns true . There is no notion of a legal call, if it compiles, it’s valid Solidity.

  1. nameReg.call("register", "MyName") is a message that passes certain bytes to nameReg. For the bytes, see: Understanding nameReg.call(“register”, “MyName”) style call between contracts
  2. nameReg.call(bytes4(sha3("fun(uint256)")), a) is a message that would invoke a function named fun (if nameReg adheres to the ABI) and pass it the raw, unpadded data a (you need to correctly pad a to 32 bytes first if you want behavior to match the ABI. For uint256 use left-padding.).

For 3, contract.call.value(...)(...) is a way to add Ether when invoking a contract. if(!nameReg.call.value(10)()){throw;} is an example of handling the failure case of the subcall. Note the extra parentheses value(10)() which invokes the fallback function.

call is a low-level interface, and it is simpler to invoke a function directly, nameReg.fun(a) instead of the second example. The direct invocation is also type-safe, and allows the return value of fun to be used.