Getting Started

Install

Simular is available on PyPi It requires Python >=3.10.

>>> pip install simular-evm

Here are a few examples of how to use simular.

Transfer Ether

Create 2 Ethereum accounts and transfer Ether between the accounts.

# import the EVM and a few utility function
>>> from simular inport PyEvm, ether_to_wei, create_account

# create an instance of the Evm
>>> evm = PyEvm()

# convert 1 ether to wei (1e18)
>>> one_ether = ether_to_wei(1)

# create a couple of accounts - one for Bob with and initial
# balance of 1 ether and one for Alice with no balance.
>>> bob = create_account(evm, value=one_ether)
>>> alice = create_account(evm)

# Bob transfers 1 ether to alice
>>> evm.transfer(bob, alice, one_ether)

# check balances
>>> assert int(1e18) == evm.get_balance(alice)
>>> assert 0 == evm.get_balance(bob)

Deploy and interact with a contract

Load an ERC20 contract and mint tokens.

# import the EVM and a few utility functions
from simular inport PyEvm, create_account, contract_from_abi_bytecode

def deploy_and_mint():

    # Create an instance of the EVM
    evm = PyEvm()

    # Create accounts
    alice = create_account(evm)
    bob = create_account(evm)

    # Load the contract.
    # ABI and BYTECODE are the str versions of the ERC20 contract
    # interface and compiled bytecode
    erc20 = contract_from_abi_bytecode(evm, ABI, BYTECODE)

    # Deploy the contract. Returns the contract's address
    # The contract's constructor takes 3 arguments:
    # name: MyCoin
    # symbol: MYC
    # decimals: 6
    #
    # 'caller' (bob) is the one deploying the contract. This
    # translates to 'msg.sender'. And in the case of this contract,
    # bob will be the 'owner'
    contract_address = erc20.deploy("MyCoin", "MYC", 6, caller=bob)
    print(contract_address)


    # Let's check to see if it worked...
    # Notice how the contract functions are added as attributes
    # to the contract object.
    #
    # We use 'call' to make a read-only request
    assert erc20.name.call() == "MyCoin"
    assert erc20.decimals.call() == 6
    assert erc20.owner.call() == bob

    # Bob mints 10 tokens to alice.
    # Again, 'mint' is a contract function. It's
    # automatically attached to the erc20 contract
    # object as an attribute.
    # 'transact' is a write call to the contract (it will change state).
    tx1 = erc20.mint.transact(alice, 10, caller=bob)

    # View emitted events
    print(tx1.event['Transfer'])

    # check balances and supply
    assert 10 == erc20.balanceOf.call(alice)
    assert 10 == erc20.totalSupply.call()

    # Let's take a snapshot of the state of the EVM
    # and use it again later to pre-populate the EVM:
    snapshot = evm.create_snapshot()

    # and save it to a file
    with open('erc20snap.json', 'w') as f:
        f.write(snapshot)


    # ... later on, we can load this back into the EVM
    with open('erc20snap.json') as f:
        snapback = f.read()

    # a new instance of the EVM
    evm2 = PyEvm.from_snapshot(snapback)

    # load the contract definitions
    erc20back = contract_from_abi_bytecode(evm2, erc20abi, erc20bin)

    # check the state was preserved in the snapshot
    assert 10 == erc20back.balanceOf.call(alice)