Skip to main content

EVM Partition

This tutorial shows you how to deploy and execute smart contracts implemented in Solidity on Alphabill EVM Partition using Alphabill CLI wallet.

Prerequisites

Before you can begin, make sure you meet the following prerequisites:

Compile Solidity Source Code

Using Command-Line Solidity Compiler

This smart contract that you will deploy on the Alphabill EVM Partition implements a counter. The counter keeps its value in the state and provides functions for reading the current value (get()), incrementing the value by one (increment()), and setting the value to an arbitrary 256-bit integer (set()). The value of the counter is initialized to zero.

Copy the following source code and save it in a file named Counter.sol in the alphabill/build directory.

Counter.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

contract Counter {
uint256 value = 0;

event Increment(uint256 indexed newValue);

function get() public view returns (uint256) {
return value;
}

function increment() public returns (uint256) {
unchecked { // let the value wrap to zero instead of failing
value++;
}
emit Increment(value);
return value;
}

function set(uint256 n) public {
value = n;
}
}

Before deployment, the source code needs to be compiled into EVM bytecode with a Solidity compiler. If you don't have the solc compiler version 0.8.x installed and you don't want to install it for this tutorial, you can skip the compilation step and use the bytecode and function signatures provided later in the tutorial. Otherwise, if you have the compiler, invoke the following command:

solc --evm-version berlin --hashes --bin -o counter Counter.sol

Note that it is important to specify the --evm-version berlin command line option, otherwise the compiler may by default generate instructions that are not yet supported in the EVM Partition. If the compilation is successful, you should see the following output from the compiler:

Compiler run successful. Artifact(s) can be found in directory "counter".

Now let's verify the artifacts Counter.bin and Counter.signatures exist in the counter sub directory. The contents of the files should look like shown below (if you skipped the compilation step, create the files manually now and copy the contents from the guide). First, the file Counter.bin that contains EVM bytecode you will use to deploy the smart contract:

counter/Counter.bin
60806040526000805534801561001457600080fd5b506101c3806100246000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806360fe47b1146100465780636d4ce63c14610062578063d09de08a14610080575b600080fd5b610060600480360381019061005b9190610136565b61009e565b005b61006a6100a8565b6040516100779190610172565b60405180910390f35b6100886100b1565b6040516100959190610172565b60405180910390f35b8060008190555050565b60008054905090565b600080600081548092919060010191905055506000547f51af157c2eee40f68107a47a49c32fbbeb0a3c9e5cd37aa56e88e6be92368a8160405160405180910390a2600054905090565b600080fd5b6000819050919050565b61011381610100565b811461011e57600080fd5b50565b6000813590506101308161010a565b92915050565b60006020828403121561014c5761014b6100fb565b5b600061015a84828501610121565b91505092915050565b61016c81610100565b82525050565b60006020820190506101876000830184610163565b9291505056fea2646970667358221220567c7e5fdc6353f0e1c8cf1771cb6d9a4e91532d997c577f52a72f3027b62de464736f6c63430008150033

The other file, Counter.signatures, contains encoded names of the functions that you will need to invoke the functions using Alphabill CLI wallet:

counter/Counter.signatures
Function signatures:
6d4ce63c: get()
d09de08a: increment()
60fe47b1: set(uint256)

Event signatures:
51af157c2eee40f68107a47a49c32fbbeb0a3c9e5cd37aa56e88e6be92368a81: Increment(uint256)

Now you are all set to deploy the smart contract.

Using Remix Online IDE

Alternatively, you can compile the same source code by using the Remix Online IDE, which is a no-setup tool with a GUI for developing smart contracts.

  1. Go to Remix Online IDE and under "Get Started - Project Templates", open "REMIX BASIC".

    remix-basic

  2. In the File explorer, create a new file under the "Contracts" folder and name it 4_Counter.sol and open the file.

    remix-new-folder

  3. In the editor, paste in the following source code into the empty file:

    4_Counter.sol
    // SPDX-License-Identifier: MIT

    pragma solidity ^0.8.0;

    contract Counter {
    uint256 value = 0;

    event Increment(uint256 indexed newValue);

    function get() public view returns (uint256) {
    return value;
    }

    function increment() public returns (uint256) {
    unchecked { // let the value wrap to zero instead of failing
    value++;
    }
    emit Increment(value);
    return value;
    }

    function set(uint256 n) public {
    value = n;
    }
    }
  4. You will then get a warning about pasting code into the editor:

    pasted-code-alert

    Since you will be using it in a test environment and this is a very simple "Hello world!" style contract that allows for only incrementing an integer and asking for current value of the integer, then it's safe to click OK.

  5. Select the 4_Counter.sol contract (if not already selected) and compile the contract by pressing the green Compile button.

    compile-contract

  6. Initially, the "contracts" directory contains three smart contracts named 1_Storage.sol, 2_Owner.sol and 3_Ballot.sol. You can also use any of the three pre-written contracts that are already in the mixer with the generation of the templates. The steps will be similar, but for simplicity, this guide is based on 4_Counter.sol.

    prewritten-contracts

  7. The following figure shows you how to access the function hashes and bytecode of the contract needed later when invoking get(), increment() and set() functions .

    compilation-details

    1. The Compile button

    2. The Solidity compiler tab

    3. The Compilation details button will give access to all necessary information about the contract, including to FUNCTIONHASHES, ABI and more.

    4. Function hashes are necessary for later. The hashes will be needed to call and execute the functions.

    5. The Bytecode button will copy the bytecode of the contract that will be needed to deploy it.

Deploy the Counter Smart Contract

Go to the build directoy where you have the Alphabill CLI binary and invoke the following command to deploy the smart contract. Note that the bytecode to be deployed is specified via the --data option. If you used the command-line Solidity compiler, the bytecode is in the Counter.bin file and you can use the command substitution:

./abwallet wallet evm deploy \
--alphabill-api-uri https://evm-partition.testnet.alphabill.org \
--data $(< counter/Counter.bin) \
--max-gas 300000

If you compiled the contract with the Remix online IDE, copy the bytecode from Remix IDE, and paste it behind the --data option.

info

Alphabill EVM Partition inherits the concept of gas from Ethereum. Currently, the cost of gas is fixed at 0.021 Tema for one unit of gas. Once you start deploying larger smart contract you may need to increase the value of --max-gas option. Make sure to keep the value smaller than the block gas limit which is currently set to 15 000 000.

After the deployment transaction succeeds, you should see output similar to this:

Evm transaction succeeded
Evm transaction processing fee: 0.000'032'09
Deployed smart contract address: ac241e528f6c303d6d5816bd381aef19b6a04b1a
Evm execution returned: 608060405234801561001057600080FD5B50600436106100415760003560E01C806360FE47B1146100465780636D4CE63C14610062578063D09DE08A14610080575B600080FD5B610060600480360381019061005B9190610136565B61009E565B005B61006A6100A8565B6040516100779190610172565B60405180910390F35B6100886100B1565B6040516100959190610172565B60405180910390F35B8060008190555050565B60008054905090565B600080600081548092919060010191905055506000547F51AF157C2EEE40F68107A47A49C32FBBEB0A3C9E5CD37AA56E88E6BE92368A8160405160405180910390A2600054905090565B600080FD5B6000819050919050565B61011381610100565B811461011E57600080FD5B50565B6000813590506101308161010A565B92915050565B60006020828403121561014C5761014B6100FB565B5B600061015A84828501610121565B91505092915050565B61016C81610100565B82525050565B60006020820190506101876000830184610163565B9291505056FEA2646970667358221220567C7E5FDC6353F0E1C8CF1771CB6D9A4E91532D997C577F52A72F3027B62DE464736F6C63430008150033

Congratulations! You have deployed your first smart contract on Alphabill EVM Partition. Now, let's try to use it.

important

Take note of the address of your smart contract shown on the line beginning with "Deployed smart contract address". In the commands given below, replace the string INSERT_YOUR_CONTRACT_ADDRESS with the actual address. The address will be unique every time you deploy your contract.

Invoke Smart Contract Functions

Read-Only Calls

Let's try to read the value of the counter. For read-only queries the EVM Partition provides a call interface that executes the called function immediately without recording the transaction and its effects in the ledger. No fee has to be paid for call requests (you still need to specify the --max-gas option), because the call function of the CLI tool executes the contract immediately without creating a transaction on the blockchain.

Execute the following command after replacing the placeholder with the address of your smart contract and verifying that the value of --data option equals to the get() function signature. When you compiled the contract using the command-line Solidity compiler, the signature is in your Counter.signatures file. In case you used Remix IDE, you can find the get() function signature under Compliation Details.

./abwallet wallet evm call \
--alphabill-api-uri https://evm-partition.testnet.alphabill.org \
--address INSERT_YOUR_CONTRACT_ADDRESS \
--data 6d4ce63c \
--max-gas 300000

This is the expected output showing that the value of the counter is, indeed, zero (represented by a 256-bit integer):

Evm transaction succeeded
Evm transaction processing fee: 0.000'000'00
Evm execution returned: 0000000000000000000000000000000000000000000000000000000000000000

Executing Transactions

In order to increment the value, you have to execute a transaction and pay a transaction fee. When a transaction is executed, the transaction is permanently recorded in the journal of transactions and the effects of the transaction are reflected in the state of the ledger. Increment the counter with the following command (again, making sure the --data option corresponds to the signature of increment() function and substituting the contract address):

./abwallet wallet evm execute \
--alphabill-api-uri https://evm-partition.testnet.alphabill.org \
--address INSERT_YOUR_CONTRACT_ADDRESS \
--data d09de08a \
--max-gas 300000

Example output (the "Evm log" line should be different):

Evm transaction succeeded
Evm transaction processing fee: 0.000'009'43
Evm log 0 : &{{} 0xAc241E528F6c303D6d5816Bd381Aef19b6a04b1a [0x51af157c2eee40f68107a47a49c32fbbeb0a3c9e5cd37aa56e88e6be92368a81 0x0000000000000000000000000000000000000000000000000000000000000001] []}
Evm execution returned: 0000000000000000000000000000000000000000000000000000000000000001

The last line contains the returned value of the counter as a 256-bit integer and it equals to one as expected.

Providing Arguments to Functions

Finally, let's set the counter value to a specific value in order to demonstrate how to specify arguments to function calls. The function set() expects an 256-bit integer argument. You can provide the argument by appending a hex-encoded value at the end of the function signature specified in the --data option. To set the counter to the maximum value, use the following command:

./abwallet wallet evm execute \
--alphabill-api-uri https://evm-partition.testnet.alphabill.org \
--address INSERT_YOUR_CONTRACT_ADDRESS \
--data 60fe47b1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF \
--max-gas 300000

Expected output:

Evm transaction succeeded
Evm transaction processing fee: 0.000'005'66

After setting the counter to the maximum value, as an exercise, try to increment the value of the counter once. What do you think will happen? After incrementing, check the value with the get() call.