vyperlang / vyper

Pythonic Smart Contract Language for the EVM
https://vyperlang.org
Other
4.87k stars 799 forks source link

`raw_call` cannot return values that it doesnt know it should return #3856

Open bout3fiddy opened 7 months ago

bout3fiddy commented 7 months ago

Version Information

What's your issue about?

In the following snippet:

implementation: constant(address) = 0xsomething

@external
def __default__() -> uint256:
    result: uint256 = convert(raw_call(implementation, msg.data, max_outsize=32, is_delegate_call=True), uint256)
    return result

If implementation address has the following code:

@external
@view
def foo() -> uint256:
    return 0

@external
@view
def bar() -> address:
    return empty(address)

I can only call foo() through the parent contract but not bar() since the __default__() method of the parent contract can only return uint256. It also needs to be able to return address to allow returning whatever bar() of the code at implementation address returns.

How can it be fixed?

Vyper should pass the bytes data as-is. This would probably require a new feature in the language.

charles-cooper commented 7 months ago

in this particular example i think you could actually just use bytes32, as it is byte-compatible across all primitive types.

but in general, the issue is that the ABI requires by convention that return types are wrapped in a tuple, and the encoding of the wrapped type may be different from the encoding from the type itself (e.g. bytes vs (bytes)). so a potential solution is to have a builtin which returns the bytes directly instead of ABI encoding them.