Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix extraData in approveAndCall not being ABI encoded in HumanStandardToken #45

Closed
wants to merge 1 commit into from

Conversation

izqui
Copy link

@izqui izqui commented Mar 31, 2017

Appending a bytes array to a function call wasn't properly setting it as the bytes parameter.

@simondlr
Copy link
Contributor

simondlr commented Apr 1, 2017

Hey @izqui. I misunderstood how you changed/edited it from our Twitter convo.

I don't think this is correct. You should be able to pass bytes as usual into extraData (from Solidity itself), in which this will cause it to break. (eg: using a throwProxy here by passing through bytes will cause this to break).

Meaning, the responsibility for the right encoding should not be the contract's responsibility. It's the test itself that should change its encoding, and then pass it onto the contract.

Does that make sense?

As far as I understand it, you are basically allowing the contract to take non-bytes info and create the equivalent bytes representation? Is that correct?

@izqui
Copy link
Author

izqui commented Apr 1, 2017 via email

@simondlr
Copy link
Contributor

simondlr commented Apr 5, 2017

@izqui, yes. That is correct, but I would still venture and say it should be encoded before you do the call. The contract shouldn't do the encoding.

@izqui
Copy link
Author

izqui commented Apr 5, 2017

Ok, I see what you are saying.

But I think the user expectation is that whatever data they send in the extraData parameter is exactly what the receiving contract will receive in the extraData parameter.

What you are proposing right now is that for calling an approveAndCall, the user would need to do:

token.approveAndCall(..., abi_encoded(extraData))

And that extraData parameter will be ABI encoded by web3 again, so the data sent to the blockchain in the tx data will be abi_encoded(abi_encoded(extraData)).

I think it should be a responsibility of the contract once it receives a valid bytes array to pack it correctly doing its abi_encode before forwarding it via a raw call.

@simondlr
Copy link
Contributor

simondlr commented Apr 5, 2017

I think it should be a responsibility of the contract once it receives a valid bytes array to pack it correctly doing its abi_encode before forwarding it via a raw call.

I might be misunderstanding this.

The issue I have with this is that an already encoded call will be then malformed by the right pad. This is likely to occur when you use bytes that are already correctly encoded: eg msg.data. So, then you would need to decode this, JUST to be able to send it across.

You are also then incurring extra gas costs, when you could've just encoded it outside the contract.

Do I have it right?

@izqui
Copy link
Author

izqui commented Apr 5, 2017

The problem is that when you do a raw call, and pass a bytes array as part of the payload it will not encode it correctly.

The extra data is correctly encoded in msg.data but gets decoded when assigning to the extraData parameter.

I'm doing a poor job explaining myself, let me try with this example:

contract Receiver {
  function receive(bytes extraData);
}

contract Sender {
  function send(address to, bytes extraData) {
      Receiver(to).receive(extraData);  // this works

      bool result1 = to.call(bytes4(sha3('receive(bytes)')), uint256(byte(0x80)), uint256(extraData.length), rightPad(extraData));  // works as the above function

      bool result2 = to.call(bytes4(sha3('receive(bytes)')), extraData);  // this will not work as the above call as it just appends the decoded bytes to the call payload.
  } 
}

@skmgoldin
Copy link
Contributor

it should be encoded before you do the call. The contract shouldn't do the encoding.

I agree with Simon. No reason to spend gas on this in-EVM. Better separation of concerns leaving it out of the contract. I think this should be closed.

@simondlr
Copy link
Contributor

There is an issue iirc, that I spoke with @izqui about. And I tried to get a grip around the problem by running some tests and encodings. Encoding issues in general is a headache for me though. And I forgot exactly what the problems/issues were.

@izqui
Copy link
Author

izqui commented Jul 27, 2017

I think the easiest way to solve this is by having Solidity do the encoding under the hood, and not doing a raw call.

MiniMe fixed this having an interface and then just making the call through it

@GNSPS
Copy link
Collaborator

GNSPS commented Nov 23, 2017

I've reviewed this and @izqui claim is right. However there's not a need to right pad the extra data.

My proposal is to keep the call as:

_spender.call(bytes4(bytes32(sha3("receiveApproval(address,uint256,address,bytes)"))), msg.sender, _value, this, uint256(byte(0x80)), uint256(_extraData.length), _extraData)

And drop the rightPad() function altogether.

Other than that this LGTM, we should merge! 😄

Copy link
Collaborator

@GNSPS GNSPS left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please remove both the rightPad() function and its use in one of the raw call's parameters?

@maurelian
Copy link
Contributor

approveAndCall is not part of the EIP20 token definition, and for the time being, not within scope of this repo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants