vyper
vyper copied to clipboard
Importing interfaces not as docs describe
Version Information
- vyper Version (output of
vyper --version
): 0.3.3 - OS: osx
- Python Version (output of
python --version
): 3.9.5
What's your issue about?
Please include information like:
- full output of the error you received
- what command you ran
- the code that caused the failure (see this link for help with formatting code)
- please try running your example with the --debug flag turned on
I have an interface that looks like such:
# @version ^0.3.3
interface IFace:
def read_stuff() -> uint256: view
And a contract that looks as such:
# @version ^0.3.3
from interfaces.IFace import IFace
@external
@view
def read_contract(some_address: address) -> uint256:
myContract: IFace = IFace(some_address)
return myContract.read_stuff()
However, when I run vyper contracts/MyContract.vy
I get:
Error compiling: contracts/MyContract.vy
vyper.exceptions.UnknownAttribute: IFace has no member 'read_stuff'.
contract "contracts/MyContract.vy", function "read_contract", line 11:11
10 myContract: IFace = IFace(some_address)
---> 11 return myContract.read_stuff()
-------------------^
12
According to the documentation, when importing interfaces, you need to use regular vyper syntax. However, adjusting my interface as such:
# @version ^0.3.3
interface IFace:
@external
def read_stuff() -> uint256:
pass
Results in this error:
vyper.exceptions.StructureException: Body must only contain state mutability label
contract "contracts/interfaces/IFace.vy", function "read_stuff", line 6:8
5 def read_stuff() -> uint256:
---> 6 pass
---------------^
7
How can it be fixed?
I'm not sure
So, you can't import types from other Vyper contracts. What the docs mean by "regular vyper syntax" is that your file structure and internals should look like this:
interfaces/IFace.vy
:
@view
@external
def read_stuff() -> uint256:
pass
Contract.vy
:
# @version ^0.3.3
import interfaces.IFace as IFace
@view
@external
def read_contract(some_address: address) -> uint256:
myContract: IFace = IFace(some_address)
return myContract.read_stuff()
Got it. We should probably update the docs to be more clear - been slamming my head.
There's also a longer term fix with libraries that is coming in https://github.com/vyperlang/vyper/issues/2431
I'm still so confused by this. I have this one file named contract1.vy
@external
def interface_func():
pass
And then this other file named contract2.vy
import contract1 as Contract1
@external
def main_func(_to_call: address):
other_contract: Contract1 = Contract1(_to_call)
to_call.interface_func()
However, compilation of contract2.vy
fails with
vyper.exceptions.UndeclaredDefinition: Unknown interface: Contract1. Did you mean 'ERC20Detailed', or maybe 'ERC721'?
line 1:0
---> 1 import contract1 as Contract1
-------^
Try this
import .contract1 as Contract1
I tried this before, but it yields in a syntax error:
vyper.exceptions.SyntaxException: invalid syntax (<unknown>, line 1)
line 1:8
---> 1 import .contract1 as Contract1
---------------^
I also tried putting a separate interface in a subfolder as people mentioned before, but that did not seem to work either.
this should be closed by the language redesign done in #3663 and #3725. there are still two ways of importing interfaces, via importing .vyi
interface files and also by interface Foo:
declarations. however, the issue at hand should be fixed, see the following example works:
# ifaces.vy
interface IFoo:
def foo(): nonpayable
# contract.vy
from ifaces import foo
@external
def call_foo():
foo.IFoo(msg.sender).foo()
honestly now that you can import types from other modules, we could remove the .vyi
file machinery entirely in favor of the in-line interface declarations. i'm going to close this issue for now as soon as #3725 is merged though.