Testing

Multi-chain Testing Using Starknet

written by
Dalena Dang
Date Last Updated
December 19, 2022
Download Project Files

Learn how you can test connecting to multiple networks and providers, if you wanted to test on both Starknet and Ethereum at the same time.

Introduction to Multi-chain Testing

The Ape software is an elegant and efficient way to build smart contracts on multiple blockchains. With our modular approach, you can easily create your own code base and deploy it across multiple chains.

Testing smart contracts in a multi-chain environment doesn't have to be complicated. Ape provides a modular approach making your builder journey easy and efficient.

In this tutorial, we will walk you through multi-chain testing with Starknet. We will review how you can test connecting to multiple networks and providers, like testing both Starknet and Ethereum contracts simultaneously.

The reason why ApeWorX supports multi-chain testing is that many dApps are multi-chain. While this tutorial is an example of L1 and L2 testing, you can also test on other chains unrelated to Ethereum. We wanted to create something that would make it more accessible for developers to test and develop on whatever chain they want to work with.

Developers can also find information for testing and multi-chain testing in our documentation here.

I will use a demo project from our team to show how this testing works. You can find the link to the GitHub repo here.

Setting up the demo Project

This demo project already contains both Cairo and Vyper contracts used by Starknet and Ethereum, respectively.

Let’s go into ape-config.yaml. If you want to set a default ecosystem for your ape project, you need to set the default ecosystem by putting this line below the plugins:

default_ecosystem: starknet

To see how the multi-chain testing works, let’s first go into the conftest.py file and see that we have already set up pytest fixtures for the Ethereum and Starknet accounts.


@pytest.fixture(scope="session")
def eth_account(accounts):
    return accounts[0]

@pytest.fixture(scope="session")
def stark_account():
    with ape.networks.starknet.local.use_provider("starknet"):
        return ape.accounts.containers["starknet"].test_accounts[0]
        

Now let’s go into the test_multichain.py file. Here, we have also set up two pytest fixtures for the Ethereum and Starknet contracts.



@pytest.fixture(scope="module")
def eth_contract(networks, project, eth_account):
    # Make a module-scoped Ethereum contract.
    # NOTE: Can also yield here to retain connection
    with networks.parse_network_choice("ethereum:local"):
        yield eth_account.deploy(project.MyContract, sender=eth_account)


@pytest.fixture(scope="module")
def stark_contract(networks, project, stark_account):
    with networks.parse_network_choice("starknet:local"):
        contract = project.Bank.deploy()
        contract.initialize(sender=stark_account)
        yield contract
        
 

We have also set up individual tests to ensure that the Ethereum and Starknet contracts are working correctly.


def test_ethereum_thing(eth_contract, eth_account):
	eth_contract.setNumber(123, sender=eth_account)
	assert eth_contract.myNumber() == 123

def test_starknet_thing(stark_account, stark_contract):
	initial_balance = stark_contract.get_balance()
	stark_contract.increase_balance(100, sender=stark_account)
	assert stark_contract.get_balance() == initial_balance + 100

Testing Multi-chain

Now let’s focus on the function for testing multi-chain in the same test. We start the test connected to the Starknet network and then test to ensure that the Starknet contract works correctly.


def test_multichain_in_same_test(networks, stark_account, stark_contract, eth_account, eth_contract):
		initial_balance = stark_contract.get_balance()
		stark_contract.increase_balance(100, sender=stark_account)
		assert stark_contract.get_balance() == initial_balance + 100

Then we switch the current active network for all the code under the indent using the line

with networks.parse_network_choice(“ethereum:local”):

This line adds the provider to the top of the stack.


with networks.parse_network_choice(“ethereum:local”):
		eth_contract.setNumber(123, sender=eth_account)
		assert eth_contract.myNumber() == 123
   

We then assert the test again to make sure that the lines below the network switch run properly.

Following the test, we switch back to the default network, Starknet, and show that the test has switched back to the default provider.


initial_balance = starknet_contract.get_balance()
	stark_contract.increase_balance(100, sender=stark_account)
	assert stark_contract.get_balance() == initial_balance + 100
  

The Ethereum network has not been disconnected; it's just no longer the active network. The new active network will be the previous network that was at the top of the stack.

Ape only disconnects from all providers at the end of the test. This lets you switch between different networks as much as you need to during the test.

Now we can run ape test in the terminal to see that all the tests work correctly.

We will also show this by running the script multichain_demo.py using ape run multichain_demo.


#Default network is starknet:local:starknet
echo(ape.networks.provider.network.ecosystem.name) #prints Starknet

    with networks.parse_network_choice("ethereum:local:test"):
        echo(ape.networks.provider.network.ecosystem.name) #prints Ethereum
        
        with networks.parse_network_choice("fantom:local:test"):
            echo(ape.networks.provider.network.ecosystem.name) #prints Fantom

            with networks.parse_network_choice("arbitrum:local:test"):
                echo(ape.networks.provider.network.ecosystem.name) #prints Arbitrum
            
            echo(ape.networks.provider.network.ecosystem.name) #prints Fantom

        echo(ape.networks.provider.network.ecosystem.name) #prints Ethereum

    echo(ape.networks.provider.network.ecosystem.name) #prints Starknet
  

In this example, we start connected with the default network provider, Starknet. Then we switch the active network to Ethereum, Fantom, and Arbitrum. After connecting to each network, we exit the with block and pop the network off the stack. The active network provider changes to the previous network at the top of the stack. You can see it in action where we print the current active network provider name. In order, it will show Starknet, Ethereum, Fantom, Arbitrum, Fantom, Ethereum, and Starknet.

Ape simplifies the process of creating a test environment for your smart contracts by providing a simple interface for configuring the network, accounts, and keys. This lets you to focus on writing your tests instead of configuring the network. If you have any questions, visit our discord and connect with peers to learn how to optimize your dApps and on-chain interactions.