Solidity (Ethereum) vs SmartPy (Tezos)

  • Variables & Storage
  • Type
  • Function visibility
  • Other
  • Control flow statement
  • Key and signatures
  • Reference
  • This articles describes a correspondence table between the smart contract language Solidity used for Ethereum with SmartPy / Python used to develop smart contracts for the blockchain Tezos

    • SmartPy is a solution for developing, testing, and deploying smart contracts on the Tezos blockchain with the Python syntax.

    • Solidity is an object-oriented, high-level language for implementing smart contracts for Ethereum and EVM blockchain compatible.

    Warning: the SmartPy syntax used in this article may be outdated since it was written for the Legacy version of SmartPy

    [TOC]

    Start

    Define a contract

    Solidity

    We use the keyword contract

    contract MyEpicGame {}
    

    SmartPy

    Any class inheriting from sp.Contract defines a SmartPy contract.

    class A(sp.Contract):
    

    Reference: https://smartpy.io/guides/tutorial#summary

    Class inheritance

    Solidity

    Keyword is such asis ParentContractName

    Example

    contract MyEpicGame is ERC721
    

    SmartPy

    The syntax is the following:class className(parentClassName)

    Example:

    class B(A)
    

    Note that in SmartPy it is required that the superclass’s __init__ function be called explicitly.

    Reference: https://smartpy.io/manual/syntax/overview

    Library / Module

    Solidity

    Solidity allows to define libraries with the keyword library

    library Math {
        function sqrt(uint y) internal pure returns (uint z) {
        // Code
        }
    }
    

    Reference: https://solidity-by-example.org/library/

    SmartPy

    A module can be defined with@sp.module

    Example:

    @sp.module
    def main():
        class Calculator(sp.Contract):
            def __init__(self):
                self.data.result = 0
    
            @sp.entrypoint
            def multiply(self, x, y):
                self.data.result = x * y
    

    Constructor

    Solidity

    Use the keyword constructor

    constructor(string[] memory myParam)
    

    SmartPy

    The smart contract constructor is defined with the function __init__ , which initialize the storage by assigning to fields of self.data.

    Example 1

    def __init__(self):
    	# Define a value with initial integer 0
        self.init(storage=0)
    

    Example 2:

    import smartpy as sp
    
    @sp.module
    def main():
        class Ducat(sp.Contract):
            def __init__(self, admin):
                self.data.balances = {}
                self.data.admin = admin
    

    Here, the init function initialize:

    • balances is a map, which associates a balance to each address. Initially it is empty, indicating that nobody owns any Ducats.

    • There is an admin address that will special powers, e.g. to mint new Ducat

    Reference: https://smartpy.io/manual/syntax/overview, smartpy.io/guides/tutorial#summary

    Variables & Storage

    Solidity

    In solidity, there are 3 types of location for variables: local, state and global. Their location (local, state, global) depends of the place where they are declared or if a specific keyword is used (e.g memory and storage).

    Reference: https://solidity-by-example.org/variables/

    SmartPy

    • Local variable

    You can declare a local variable with sp.local

    x = sp.local("x", 0)
    

    Local variable values can be accessed to and updated with the .value field

    • Global variable

    SmartPy offers us self.data, which corresponds to the storage in Michelson.

    Example

    def repeat(self, params):
        self.data.storage= params
    

    Type

    General overview

    Solidity

    Solidity is a statically typed language, which means that the type of each variable (state and local) needs to be specified.

    Ref: https://docs.soliditylang.org/en/v0.8.20/types.html

    SmartPy

    In SmartPy as in Python you don’t need to specify the types of objects. However the contracts that you write in SmartPy will be compiled to Michelson and Michelson requires types. Therefore SmartPy automatically detects the types of expressions (Type Inference).

    Number

    Solidity

    int / uint: Signed and unsigned integers of various sizes.

    Keywords uint8 to uint256 in steps of 8 (unsigned of 8 up to 256 bits) and int8 to int256.

    SmartPy

    Integer: sp.int

    Unsigned integer: sp.nat

    Currency Units

    Solidity

    we can use the keywords wei and ether

    uint public oneWei = 1 wei;
    
    int public oneEther = 1 ether;
    

    Ref: https://betterprogramming.pub/solidity-tutorial-all-about-ether-units-eaebe55dd4dc

    Smartpy

    a = sp.tez(1

    sp.mutez(1000000)
    

    Ref: https://smartpy.io/docs/manual/syntax/integers-and-mutez

    Other types

    SmartPy allows to use Pairs, Tuples, Option and have a specific type called Record

    • Pairs (a1, a2)

    • Tuples

    sp.tuple[sp.int, sp.string, sp.bool].

    • Records

    sp.record(a=42, b="abc")

    x = sp.record(a=42, b="abc", c=True)
    assert x.a == 42
    assert x.b == "abc"
    assert x.c == True
    
    • Options, Variants

    And many others available in the references:

    Function visibility

    Function available from the outside of the contract

    Solidity

    external / public

    SmartPy

    @sp.entry_point
    

    An entry point is a method of a contract class that can be called from the outside.

    Reference: https://legacy.smartpy.io/docs/introduction/entrypoints

    Other

    Return a value

    Solidity

    The type returned is indicated with the keyword returns

    Example :

    function tokenURI(uint256 _tokenId) public returns (string memory) 
    

    SmartPy

    sp.result(value)

    Reference: https://smartpy.io/reference.html#_return_values

    Access control

    Solidity

    You can perform verification with the keywork require or with a if and a custom error.

    For example, here the contract will generate an error if the transaction sender is not equal to the admin address stored in the contract.

    require(msg.sender == admin);
    

    Or if a modifier, for example to verify the ownership with onlyOwner

    myFunction(uint256 value) public onlyOwner
    

    SmartPy

    sp.verify(sp.sender == self.data.admin);
    

    Current timestamp

    Solidity

    block.timestamp
    

    SmartPy

    sp.now 
    

    Control flow statement

    Switch

    Solidity

    Not available, you have to use the statement if else

    SmartPy

    <expr>.match_cases(v) Similar to a switch case statement, where expr is a variant.

    variant_type = sp.TVariant(
        action1 = sp.TNat,
        action2 = sp.TString,
    )
    variant = sp.variant("action1", 10)with variant.match_cases() as arg:
        with arg.match("action1") as a1:
            # Will be executed
            sp.verify(a1 == 10, 'Expected value to be (10).')
    

    Reference: https://legacy.smartpy.io/docs/types/variants#match-cases

    Loop

    Solidity

    for(uint256 i = 0; i < y; ++i)
    

    SmartPy

    sp.range(x, y, step = 1)
    

    Key and signatures

    SmartPy

    On Tezos, each tz address is determined by hashing a public key.

    Public keys are of type sp.key and can be defined with sp.key(). For example, sp.key("edpkv3w95AcgCWQeoYm5szaEqXX71JkZ261s4wjH1NYRtibX879rDv")

    Reference: smartpy.io/manual/syntax/keys-and-signatures

    Reference

    Here a quick list of the main references

    You might also enjoy