# Cairo v2.2.0 is out!

**URL:** <https://community.starknet.io/t/cairo-v2-2-0-is-out/99263>\
**Category:** Cairo Development\
**Tags:** cairo\
**Created:** [August 24, 2023, 1:23pm UTC](https://community.starknet.io/t/cairo-v2-2-0-is-out/99263 "2023-08-24T13:23:59Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![FeedTheFed](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/feedthefed/32/72981_2.png) [@FeedTheFed](https://community.starknet.io/u/FeedTheFed)\
**Post date:** [August 24, 2023, 1:23pm UTC](https://community.starknet.io/t/cairo-v2-2-0-is-out/99263/1 "2023-08-24T13:23:59Z")

</div>

# Cairo v2.2.0

- [TL;Dr](#tldr)
- [Language server mprovements](#LS)
- [Hash trait refactored and can be derived](#hash)
- [Added derive default and a default impl for small tuples](#default)
- [Added a `PartialEq` implementation for arrays and spans to the corelib](#array_eq)
- [Nullable new](#null)
- [Added the ability to test L2→L1 messages](#test_messages)
- [Added the `selector!` macro](#selector)
- [Many use statements are no longer necessary](#use)

## TL;DR

Cairo [v2.2.0](https://github.com/starkware-libs/cairo/releases/tag/v2.2.0) was just released. Since there were only high-level upgrades (i.e., no Sierra changes), it is associated with Sierra [v1.3.0](https://github.com/starkware-libs/cairo/releases/tag/sierra-v1.3.0) (same as Cairo v2.1.0) which is compatible with Starknet ≥0.12.1 (that is, it is supported on all Starknet environments).

The full changelog is found in the [release notes](https://github.com/starkware-libs/cairo/releases/tag/v2.2.0). In this post we’ll go over a few notable mentions in more detail.

Missing from this post are the new `ByteArray` struct and `bytes31` type that will serve as the basis for strings in Cairo, as it is still experimental, and thus, contracts using it **cannot yet be deployed on Starknet**. Soon, they will get their due attention in a standalone post. For now, you can find usage examples in [byte\_array\_test.cairo](https://github.com/starkware-libs/cairo/blob/c8f0da0c5053600fd6d4c2fd3aff8f79d1256fc5/corelib/src/test/byte_array_test.cairo).

## Language server improvements

We now have many more autocompletions:

 ![image](https://europe1.discourse-cdn.com/flex005/uploads/starknet1/original/3X/0/c/0cdf9e408676ad8d0aa2c3ceba5a94cb41f4790d.png)

 ![image](https://europe1.discourse-cdn.com/flex005/uploads/starknet1/original/3X/7/7/771543e5d9b08e470cacc3b9cc32681c27cf90a7.png)

and templates for various common blocks in the language:

 ![image](https://europe1.discourse-cdn.com/flex005/uploads/starknet1/original/3X/d/7/d74b417771419b1dcba3824af4db40d06cc10cd5.png)

the above completions generate the following templates:

```auto
// enum template
enum {
    : ,
}

// event dictionary template
#[event]
#[derive(Drop, starknet::Event)]
enum Event {
    : ,
}

// external impl template
#[external(v0)]
impl of <ContractState>{
    
}

// external function template
fn (ref self: ContractState, ) {
    
}

```

## Hash trait refactored and can be derived

The following traits are now available in the core lib:

```auto
/// A trait for values that can be hashed.
trait Hash<T, S, impl SHashState: HashStateTrait<S>> {
    /// Updates the hash state with the given value.
    fn update_state(state: S, value: T) -> S;
}

```

```auto
/// A trait for hash state accumulators.
trait HashStateTrait<S> {
    fn update(self: S, value: felt252) -> S;
    fn finalize(self: S) -> felt252;
}

```

```auto
/// Extension trait for hash state accumulators.
trait HashStateExTrait<S, T> {
    /// Updates the hash state with the given value.
    fn update_with(self: S, value: T) -> S;
}

```

These traits provide a convenient hashing interface that is general enough to support both Pedersen (which should only be used for backward-compatibility purposes, as Poseidon is more STARK friendly and thus cheaper) and Poseidon. The following example illustrates how we can hash a user-defined type:

```auto
use core::hash::HashStateExTrait;
use poseidon::{PoseidonTrait, HashState};
use hash::{HashStateTrait, Hash};

#[derive(Hash)]
struct MyMessage {
    message_type: u256,
    content: u256
}

fn main() {
  let hash_state = PoseidonTrait::new();
  let message = MyMessage { message_type: 1, content: 2 };
  let hash = hash_state.update_with(message).finalize();
}

```

The resulting hash from using a new Poseidon `HashState` and the derived implementation is `poseidon(message_type.low, message_type.high, content.low, content.high)`, where the specs for the Poseidon hash implementation can be found in the [Starknet documentation](https://docs.starknet.io/documentation/architecture_and_concepts/Cryptography/hash-functions/#poseidon_array_hash).

Thanks to the flexibility of the new hashing mechanism, to use a different underlying hash function, we only need to change the hash state while using the same derived implementation:

```auto
use core::hash::HashStateExTrait;
use pedersen::{PedersenTrait, HashState};
use hash::{HashStateTrait, Hash};

let hash_state = PedersenTrait::new();
let message = MyMessage { message_type: 1, content: 2 };
let hash = hash_state.update_with(message).finalize();

```

Note that to use the `update_with` function directly on `hash_state`, we needed to import the `HashStateExTrait` trait, which has the following generic implementation in the corelib:

```auto
impl HashStateEx<
    S, impl SHashState: HashStateTrait<S>, T, impl THash: Hash<T, S, SHashState>
> of HashStateExTrait<S, T> {
    #[inline(always)]
    fn update_with(self: S, value: T) -> S {
        THash::update_state(self, value)
    }
} 

```

## Added derive default and a default impl for small tuples

You can now use `derive(Default)` on structs and enums that specify that default variant (via annotating one of the variants with `#[default]`):

```auto
#[derive(Copy, Drop, Default)]
struct MyStruct {
    a: u128,
    b: (u64, u128, u256, bool)
}

#[derive(Copy, Drop, Default, PartialEq)]
enum MyEnum {
    A,
    #[default]
    B: u128
}

let my_struct: MyStruct = Default::default();
let my_enum: MyEnum = Default::default();
assert(my_enum == MyEnum::B(0), 'unexpected default');

```

Note that the corelib now contains a default implementation for tuples of size up to 4.

## Added a `PartialEq` implementation for arrays and spans to the corelib

You can now compare arrays and spans using the corelib’s implementation of `PartialEq`:

```auto
use array::ArrayTrait;

let first = array![1, 2, 3];
let second = array![1, 2, 3];
assert(first == second, 'should be equal');
assert(first.span() == second.span(), 'should be equal')

```

## Nullable new

Implementing `NullableTrait<T>` allows using `T` as dictionary values. Up until now, to create `Nullable<T>` you first had to get `Box<T>` and then call the `nullable_from_box` libfunc. Using the `new` function in the trait `NullableTrait`, you can do the following:

```auto
let mut dict: Felt252Dict<Nullable<u256>> = felt252_dict_new::<Nullable<u256>>();
dict.insert(0, NullableTrait::new(5));

```

## Added the ability to test L2→L1 messages

You can now use the test runner to test sending L2→L1 messages via the `pop_l2_to_l1_message` function from `starknet::testing`:

```auto
#[test]
#[available_gas(300000)]
fn test_pop_l2_to_l1_message() {
    let contract_address = starknet::contract_address_const::<0x42>();
    testing::set_contract_address(contract_address);

    let mut to_address = 1234;
    let mut payload = array![2345];

    starknet::send_message_to_l1_syscall(to_address, payload.span());
    starknet::send_message_to_l1_syscall(to_address, payload.span());

    let (to_address, payload) = starknet::testing::pop_l2_to_l1_message(contract_address).unwrap();
    assert_eq(@payload.len(), @1, 'unexpected payload size');
    assert_eq(@to_address, @1234, 'unexpected to_address');
    assert_eq(payload.at(0), @2345, 'unexpected payload');

    let (to_address, payload) = starknet::testing::pop_l2_to_l1_message(contract_address).unwrap();
    assert_eq(@payload.len(), @1, 'unexpected payload size');
    assert_eq(@to_address, @1234, 'unexpected to_address');
    assert_eq(payload.at(0), @2345, 'unexpected payload');
}

```

You can find more examples in [l2\_to\_l1\_messages.cairo](https://github.com/starkware-libs/cairo/blob/98af2f86dfd19a75a8ebe7870e4f69b57fdeb756/crates/cairo-lang-starknet/cairo_level_tests/l2_to_l1_messages.cairo).

## Added the `selector!` macro

You can now use the `selector!` macro instead of hardcoding certain selectors in your code (particularly relevant for testing):

```auto
let selector: felt252 = selector!("my_function");

```

The selector of an external function in Starknet is defined to be the [sn\_keccak](https://docs.starknet.io/documentation/architecture_and_concepts/Cryptography/hash-functions/#starknet_keccak) of the big-endian ASCII encoding of the function’s name.

## Many use statements are no longer necessary

Everything under [lib.cairo](https://github.com/starkware-libs/cairo/blob/82ce69322356b75bc84912adb9791b3b2d5f6789/corelib/src/lib.cairo) doesn’t need to bee imported explicitly. This includes all common traits: `Default`, `PartialEq`, `Into`, `TryInto` and many others.

Additionally, as long as the relevant trait has at least one impl in the current context, the trait itself does not need to be imported. For example, we no longer need to import a trait when we have a generic impl parameter:

```auto
// no longer need "use another_module::SomeTrait"
fn some_func<impl X: another_module::SomeTrait>() {
    SomeTrait::some_other_func();
}

```
