vyperlang / vyper

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

`implements` does not respect public getter of interface type #3954

Open pcaversaccio opened 6 months ago

pcaversaccio commented 6 months ago

Public getter of interface type is currently not respected by implements if implemented as module:

# lib.vy
# pragma version ~=0.4.0rc2

from ethereum.ercs import IERC20

asset: public(immutable(IERC20))

@deploy
def __init__(asset_: IERC20):
    asset = asset_
# main.vy
# pragma version ~=0.4.0rc2

from ethereum.ercs import IERC20

import lib
initializes: lib

interface IAsset:
    def asset() -> IERC20: view

implements: IAsset

exports: lib.__interface__ # exports the external getter function for `asset`

@deploy
def __init__(asset_: IERC20):
    lib.__init__(asset_)

will throw with:

vyper.exceptions.InterfaceViolation: Contract does not implement all interface functions: asset

  contract "main.vy:11", line 11:0
       10
  ---> 11 implements: IAsset
  --------^
       12
pcaversaccio commented 6 months ago

@charles-cooper it's not fully fixed yet IMHO.

PoC

# lib.vy
# pragma version ~=0.4.0rc2

from ethereum.ercs import IERC20

asset: public(immutable(IERC20))

@deploy
def __init__(asset_: IERC20):
    asset = asset_
# main.vy
# pragma version ~=0.4.0rc2

from ethereum.ercs import IERC20

import lib
initializes: lib

interface IAsset:
    def asset() -> address: view #  --> Vyper returns the `address` type for interface types by default.

implements: IAsset

exports: lib.__interface__ # exports the external getter function for `asset`

@deploy
def __init__(asset_: IERC20):
    lib.__init__(asset_)

This won't compile:

vyper.exceptions.InterfaceViolation: Contract does not implement all interface functions: asset()

  contract "main.vy:12", line 12:0 
       11
  ---> 12 implements: IAsset
  --------^
       13

The underlying issue I currently face is that I use the built-in ERC4626 interface: https://github.com/vyperlang/vyper/blob/e1adb7b3344c1ac03facfa553830a94dd7def2e2/vyper/builtins/interfaces/IERC4626.vyi#L15-L19

declare it in a module via (the module itself compiles):

asset: public(immutable(IERC20))

and I import into my my main contract, export everything and initialise it. But it throws with the error above. The compiler tells me however, if I do something like exports: (erc4626.__interface__, erc4626.asset), that it's already exported vyper.exceptions.StructureException: already exported!, but it seems that the return type of address and IERC20 has an internal conflict. You can fully repro via my PR here: https://github.com/pcaversaccio/snekmate/pull/236.