vyperlang / vyper

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

Difficulty handling dynamic type sizes in .vyi Interfaces #4239

Open fubuloubu opened 1 month ago

fubuloubu commented 1 month ago

Version Information

What's your issue about?

I've tried a few different possibilities for this:

  1. using the docs, it mentions that 0 is treated as a minimum for a dynamic structure's sizes. That doesn't work:

    ArrayIndexException: Subscript must be greater than 0                                                                                                               
    
    contract "contracts/Validator.vyi:16", function "validate", line 16:18                                                                                           
       15     amount_per_second: uint256,                                                                                                                          
    ---> 16     reason: Bytes[0],  # NOTE: Represents lower-bound of implementation                                                                                  
    --------------------------^                                                                                                                                      
       17 ) -> uint256:
  2. I tried 1, which is mentioned in the docs somewhat implicitly in the example (instead of 0 which I thought would work). Doesn't work either (downstream uses 1024):

    TypeMismatch:Given reference has type Bytes[1024], expected Bytes[1]                                                                                               
    
    contract "contracts/Validator.vyi:16", function "validate", line 16:4                                                                                            
       15     amount_per_second: uint256,                                                                                                                          
    ---> 16     reason: Bytes[1],  # NOTE: Represents lower-bound of implementation                                                                                  
    ------------^
       17 ) -> uint256:
  3. I tried a larger value, thinking maybe the docs were mistating the "minimum behavior" of sizes in interfaces. Nope (the error actually isn't entirely clear, but I assume this is the root cause):

    InterfaceViolation:Contract does not implement all interface functions: validate(address,interface [...]/IERC20.vyi,uint256,Bytes[65535])
    
    contract "contracts/test/TestValidator.vy:8", line 8:0 
       7
    ---> 8 implements: Validator
    -------^
       9

The only thing that works if they exactly match the specific value that I am using in the implementation with the interface. This makes Interfaces brittle to deploy, especially when using interfaces from 2nd party libraries.

How can it be fixed?

Now, this may be intended behavior that the 2nd party developer may have! They might want to specify a specific value that is accepted for that field (the size can always be less, but not more) for some downstream logic that may be called into by some other function (since I can use interfaces as types in other modules). Something to keep in mind.

At the very least, the ability to specify "I really don't care what you set this too" should be easy and natural to do w/ Vyper. My suggestion is that we allow ... (the Elipsis AST node) to define "ignore whatever this says for the purposes of determining interface alignment in a downstream implementation".

fubuloubu commented 1 month ago

For now, the only truly surefire solution is to use a .json interface