Custom Imports
If you have a function that is reusable, you can store it in a
separate .cairo
file and then import it. This can be helpful to
make contracts more readable and modular.
Consider an application that has an addition function.
- contracts/
- custom_imports.cairo
- utils/
- math.cairo
%lang starknet
%builtins range_check
# contracts/custom_imports.cairo
# Import from teh cairo-lang package
from starkware.cairo.common.cairo_builtins import HashBuiltin
# Import a function from a custom local file.
from contracts.utils.math import add_two, get_modulo
# This is the main contract file that will be deployed.
@view
func get_calculations{
range_check_ptr
}(
first : felt,
second : felt
) -> (
sum : felt,
modulo : felt
):
# Two custom operations.
let (sum) = add_two(first, second)
let (modulo) = get_modulo(first, second)
return (sum, modulo)
end
Save the contract above as contracts/custom_imports.cairo
Now save the module to be imported (below) as contracts/utils/math.cairo
.
Nile will deploy the main contract and bring the required functions
in during compilation. Only one contract is deployed.
%lang starknet
# This function is from the common library.
# It can live here, reducing the clutter of an application.
from starkware.cairo.common.math import unsigned_div_rem
# This function is imported by 'custom_import.cairo'
# Equivalent to placing this function in that file.
func add_two(
a : felt,
b : felt
) -> (
sum : felt
):
let sum = a + b
return (sum)
end
# This function performs the modulo operation.
func get_modulo{
range_check_ptr
}(
a : felt,
b : felt
) -> (
result : felt
):
let (dividend, remainder) = unsigned_div_rem(a, b)
# The dividend is not used, and the following is equivalent:
# let (_, remainder) = unsigned_div_rem(a, b)
return (remainder)
end
Compile
Compile
nile compile
Or compile this specific contract
nile compile contracts/custom_imports.cairo
Test
Make a new file called test_custom_imports.py
and populate it:
import pytest
import asyncio
from starkware.starknet.testing.starknet import Starknet
@pytest.fixture(scope='module')
def event_loop():
return asyncio.new_event_loop()
@pytest.fixture(scope='module')
async def contract_factory():
starknet = await Starknet.empty()
# Note how the contracts/utils/math.cairo file is not needed here.
contract = await starknet.deploy("contracts/custom_imports.cairo")
return starknet, contract
@pytest.mark.asyncio
async def test_contract(contract_factory):
starknet, contract = contract_factory
num_1 = 10
num_2 = 3
# Read from contract
response = await contract.get_calculations(10, 3).call()
# Check the results, addressing each returned value
# by its name defined in the contract return statement.
assert response.result.sum == num_1 + num_2
assert response.result.modulo == num_1 % num_2
Run the test
pytest tests/test_custom_imports.py
Local Deployment
Deploy to the local devnet.
nile deploy custom_imports --alias custom_imports
Interact
Read
nile call custom_imports get_calculations 10 3
Returns: 13 1
Public deployment
Will default to the Goerli/alpha testnet until mainnet is available.
nile deploy custom_imports --alias custom_imports --network mainnet
Returns:
🚀 Deploying custom_imports
🌕 artifacts/custom_imports.json successfully deployed to 0x0030cfe7438b17ccf64584e4f76f038c1f7f647dc85eedf4be1b175c8d7a7d2b
📦 Registering deployment as custom_imports in mainnet.deployments.txt
Deployments can be viewed in the voyager explorer https://voyager.online