2

Introduction

I am working on a bounty contract. Here is the function for somebody answering the bounty. I am trying to figure out when it is better to cast to payable, it seems intuitively that always keeping an address type default and casting it just before a transfer would defeat the point of having types in the first place.

Code

  function answerBounty(
    uint _bountyId,
    string memory _answerId)
    public
    validateBountyArrayIndex(_bountyId)
  {
    bounties[_bountyId].hasBeenAnswered = true;
    bounties[_bountyId].fulfillments.push(Fulfillment(_answerId, msg.sender, block.timestamp));
    uint answerIndex = bounties[_bountyId].fulfillments.length - 1;

    emit BountyFulfilled(_bountyId, msg.sender, _answerId, answerIndex);
  }

Issue

I know that msg.sender default type is 'address'. If this answer is selected, the msg.sender that is stored in the the contract at that line:

bounties[_bountyId].fulfillments.push(Fulfillment(_answerId, msg.sender, block.timestamp));

will be sent the funds of the bounty. Just taking the address from Fulfillment and calling .transfer() would cause an error because msg.sender is type 'address'. So it needs to be cast to payable before calling .transfer().

Question

Is it better to to cast or declare an address to payable as soon as possible if we know it might receive funds later, or is it better to wait just before we need to transfer it funds and cast it to payable?

1
  • I'd recommend to narrow down the scope to the minimum possible. TLDR don't use payable until it is needed, casting an address to payable should cost almost nothing.
    – Ismael
    Sep 11, 2022 at 3:32

2 Answers 2

0

.transfer and .send have been deprecated for a while and can cause headaches due to their limited gas.

.call is the currently recommended method, and using .call, you don't need to cast address to payable

e.g.

(bool success,) = msg.sender.call{value: _amount}("");

look mum; no casting!

casting msg.sender doesn't change the global variable. the question only arises if you intend to save the result of payable(msg.sender) into another variable of type address payable. In most cases, this is not likely worth the extra code and gas. Just cast it at the (probably only one) time it's needed ... but using .call makes it a moot point anyway

2
  • Thanks! That makes sense. Curious why did you put a "," after the success bool? Sep 12, 2022 at 13:04
  • there's also bytes data returned in the tuple, but it's often ignored, so left out. if you want to get the data too, it would look something like this (bool ok, bytes memory data) = ...
    – sola24
    Sep 12, 2022 at 14:25
0

Its better if you do datatype casting at the end.

But note, even if you put address as payable in start, It is fine. Just make sure you smart contract dont have any vurnalibility.

This is how you can do typecasting
bounties[_bountyId].fulfillments.push(Fulfillment(_answerId, payable(msg.sender), block.timestamp));

You can do typecasting in transfer function itself

1
  • Thanks - makes more sense to do at the end indeed. Sep 12, 2022 at 13:05

Your Answer

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

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