DEV Community

Muwawu Moses
Muwawu Moses

Posted on

How to use 'initializes' and 'exports' in vyper: Modular Vyper code arrangement.

As vyper is evolving, a lot of new exciting changes have been introduced in version 0.4.0. Today, we are going to put our focus on two built-in functions: initializes and exports.

initializes

This mainly is useful when you need to initialize a module's state.

exports

In Vyper, @external functions are not automatically exposed (i.e., included in the runtime code) in the importing contract. This means that any externally facing functionality must be explicitly defined in the top-level of the compilation target.
So, exporting external functions from modules is accomplished using the exports keyword.

Anyway, to better understand these, we shall use a code example.
I am going to illustrate using three contracts i.e A.vy, B.vy and C.vy where A.vy is the module we gonna be utilizing.
A.vy

#pragma version >0.3.10

x: public(uint256)
y: public(uint256)
z: public(uint256)

@deploy
def __init__(_x: uint256, _y: uint256):
    self.x = _x
    self.y = _y

@external
def add(_x: uint256, _y: uint256):
    self._add(_x, _y)

@internal
def _add(_x: uint256, _y: uint256):
    _z: uint256 = _x + _y
    self.z = _z

Enter fullscreen mode Exit fullscreen mode

B.vy

#pragma version >0.3.10

from . import A
initializes: A

@deploy
def __init__(_x: uint256, _y: uint256):
    A.__init__(_x, _y)

@external
def set_value(_x: uint256, _y: uint256):
    A._add(_x, _y)

@view
@external
def get_x() -> uint256:
    _x: uint256 = A.x
    return _x

@view
@external
def get_y() -> uint256:
    _y: uint256 = A.y
    return _y

@view 
@external
def get_z() -> uint256:
    result: uint256 = A.z
    return result

Enter fullscreen mode Exit fullscreen mode

C.vy

#pragma version >0.3.10

from . import A
initializes: A

exports: A.add


@deploy
def __init__(_x: uint256, _y: uint256):
    A.__init__(_x, _y)

@view
@external
def get_x() -> uint256:
    _x: uint256 = A.x
    return _x

@view
@external
def get_y() -> uint256:
    _y: uint256 = A.y
    return _y

@view 
@external
def get_z() -> uint256:
    result: uint256 = A.z
    return result

Enter fullscreen mode Exit fullscreen mode

From the above code examples in contract B.vy, we can see that we use A.vy's state by initializing using the initializes: A magic. Also, i can access all @internal functions of the initialized contract. For example, I can call A._add(_x, _y). However, it's not possible to call external functions at this moment. A.add(_x, _y) will throw. To archive this, we need to use exports: A.add just like it's done in C.vy.
With exports, the external function is now available in the initializing contract. We are going to witness this later when it comes to interacting with the code.
scripts/deploy_B.py

from ape import project, accounts

def main():
    account = accounts.load('meta_wallet')  # Replace with your actual account alias
    _x = 3
    _y = 4
    # Deploy the contract
    contract = account.deploy(project.B, _x, _y)  # Initial values for x and y

    # Display initial values
    print(f"Initial x: {contract.get_x()} \u2705")
    print(f"Initial y: {contract.get_y()} \u2705")

    # Call the add method
    contract.set_value(5, 15, sender=account)

    # Fetch and display the result
    result = contract.get_z()
    print(f"Result (z): {result} \u2705")

Enter fullscreen mode Exit fullscreen mode

ape with smart-contracts

From the image above, we see that we get exactly what we expect from the way how initializes and exports operate.✅
scripts/deploy_C.py

from ape import project, accounts

def main():
    account = accounts.load('meta_wallet')  # Replace with your actual account name
    _x = 5
    _y = 10
    # Deploy the contract
    contract = account.deploy(project.C, _x, _y)  # Initial values for x and y

    # Display initial values
    print(f"Initial x: {contract.get_x()} \u2705")
    print(f"Initial y: {contract.get_y()} \u2705")

    # Call the add method
    contract.add(5, 15, sender=account)

    # Fetch and display the result
    result = contract.get_z()
    print(f"Result (z): {result} \u2705")

Enter fullscreen mode Exit fullscreen mode

modular vyper
Here also, you see that we can access the contract state of A just buy initializing and exporting it's external functions.✅ Therefore, one can just call from C, contract.add().

Thanks for reading. Let me hope my efforts help you at some stage. If you find the post helpful, please don't forget to give a like, and comment below if you need any help.

Top comments (0)