Skip to content

Commit

Permalink
Added data transformation documentation
Browse files Browse the repository at this point in the history
commit-id:f00574d8
  • Loading branch information
integraledelebesgue committed Oct 4, 2024
1 parent a8be152 commit 78f40e3
Show file tree
Hide file tree
Showing 3 changed files with 192 additions and 2 deletions.
3 changes: 2 additions & 1 deletion docs/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
* [Inspecting Transactions](starknet/tx-status.md)
* [Fees and Versions](starknet/fees-and-versions.md)
* [Verifying Contracts](starknet/verify.md)
* [Calldata Transformation](starknet/calldata-transformation.md)

---

Expand Down Expand Up @@ -131,4 +132,4 @@
* [tx_status](appendix/sncast-library/tx_status.md)
* [errors](appendix/sncast-library/errors.md)
* [ `snfoundry.toml` Reference](appendix/snfoundry-toml.md)
* [ `Scarb.toml` Reference](appendix/scarb-toml.md)
* [ `Scarb.toml` Reference](appendix/scarb-toml.md)
173 changes: 173 additions & 0 deletions docs/src/starknet/calldata-transformation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
# Calldata Transformation

For the examples below, we will consider a dedicated contract - `DataTransformerContract`, defined in `data_transformer_contract` project namespace.

It's declared on Sepolia network with class hash `0x02a9b456118a86070a8c116c41b02e490f3dcc9db3cad945b4e9a7fd7cec9168`.

It has a few methods accepting different types and items defined in its namespace:

```rust
// data_transformer_contract/src/lib.cairo

pub struct SimpleStruct {
a: felt252
}

pub struct NestedStructWithField {
a: SimpleStruct,
b: felt252
}

pub enum Enum {
One: (),
Two: u128,
Three: NestedStructWithField
}

#[starknet::contract]
pub mod DataTransformerContract {
/* ... */

use super::*;

fn tuple_fn(self: @ContractState, a: (felt252, u8, Enum)) { ... }

fn complex_struct_fn(self: @ContractState, a: ComplexStruct) { ... }

fn complex_fn(
self: @ContractState,
arr: Array<Array<felt252>>,
one: u8,
two: i16,
three: ByteArray,
four: (felt252, u32),
five: bool,
six: u256
) {
...
}
}
```

A default form of calldata passed to commands requiring it is a series of hex-encoded felts:

```shell
$ sncast --account myuser \
call \
--url http://127.0.0.1:5050 \
--contract-address 0x016ad425af4585102e139d4fb2c76ce786d1aaa1cfcd88a51f3ed66601b23cdd \
--function tuple_fn \
--calldata 0x10 0x3 0x0 \
--block-id latest
```

However, `sncast` allows passing the data in far more handy, human-readable form - as Cairo expressions.
When calldata is delivered in such form, Cast will perform serialization automatically, based on an ABI of the contract we interact with.

### Basic example

We can write the same command as above, but with expression calldata:

```shell
$ sncast --account myuser \
call \
--url http://127.0.0.1:5050 \
--contract-address 0x016ad425af4585102e139d4fb2c76ce786d1aaa1cfcd88a51f3ed66601b23cdd \
--function tuple_fn \
--calldata (0x10, 3, data_stransformer_contract::Enum::One) \
--block-id latest
```

getting the same result.

> 📝 **Note**
> All data types are serialized according to the official [Starknet specification](https://docs.starknet.io/architecture-and-concepts/smart-contracts/serialization-of-cairo-types/).
> 📝 **Note**
> User-defined items such as enums and structs should be referred to depending on a way they are defined in ABI.
> In general, paths to items have form: `<project-name>::<module-path>::<item-name>`.
### Supported expressions

> 💡 **Info**
> Only **constant** expressions are supported. Defining and referencing variables and calling functions (either builtin, user-defined or external) is not allowed.
Cast supports most important Cairo corelib types:
* `bool`
* signed integers (`i8`, `i16`, `i32`, `i64`, `i128`)
* unsigned integers (`u8`, `u16`, `u32`, `u64`, `u96`, `u128`, `u256`, `u384`, `u512`)
* `felt252` (numeric literals and so-called *shortstrings*)
* `ByteArray`
* `ContractAddress`
* `ClassHash`
* `StorageAddress`
* `EthAddress`
* `bytes31`
* `Array` - using `array![]` macro

Numeric types (primitives and `felt252`) can be paseed with type suffix specified - for example `--calldata 420_u64`.

### More complex examples

1. `complex_fn` - different data types:

```shell
$ sncast --account myuser \
call \
--url http://127.0.0.1:5050 \
--contract-address 0x016ad425af4585102e139d4fb2c76ce786d1aaa1cfcd88a51f3ed66601b23cdd \
--function complex_fn \
--calldata \
array![array![1, 2], array![3, 4, 5], array![6]] \
12 \
-128_i8 \
"Some string (a ByteArray)" \
('a shortstring', 32_u32) \
true \
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff \
--block-id latest
```
2. `nested_struct_fn` - struct nesting:
```shell
$ sncast --account myuser \
call \
--url http://127.0.0.1:5050 \
--contract-address 0x016ad425af4585102e139d4fb2c76ce786d1aaa1cfcd88a51f3ed66601b23cdd \
--function nested_struct_fn \
--calldata \
data_transformer_contract::NestedStructWithField { \
a: data_transformer_contract::SimpleStruct { a: 10 }, \
b: 12 \
} \
--block-id latest
```
### Caveats
Reasoning about calldata serialization logic is not always possible for Cast. **In particular, Cast doesn't verify serialized calldata against the ABI**.
When given a calldata, Cast first tries to transform it according to the contract ABI.
When failed, in case of type or length mismatch, it will then try to interpret it as an already serialized data.
Thus, calldata written in hex-encoded form is not always going to be interpreted as a list of felts and treated as serialized. Let's see an example:
Our `DataTransformerContract` exposes a method with signature:
```rust
fn u256_fn(self: @ContractState, a: u256) { ... }
```
We can write:
```shell
$ sncast --account myuser \
call \
--url http://127.0.0.1:5050 \
--contract-address 0x016ad425af4585102e139d4fb2c76ce786d1aaa1cfcd88a51f3ed66601b23cdd \
--function u256_fn \
--calldata 0x10 \
--block-id latest
```
Despite the call data **not being** the proper serialization of an `u256` (which would be `0x10 0x0`), call succeeds.
That's because Cast interpreted `0x10` as a hex-encoded `u256`, not `felt252`.
18 changes: 17 additions & 1 deletion docs/src/starknet/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,22 @@ response: [0x0]
> 📝 **Note**
> In the above example we supply `sncast` with `--account` and `--url` flags. If `snfoundry.toml` is present, and have these properties set, values provided using these flags will override values from `snfoundry.toml`. Learn more about `snfoundry.toml` configuration [here](../projects/configuration.md#sncast).

### Calldata

Some `sncast` commands (namely `call`, `deploy` and `invoke`) allow passing *calldata* - a series of arguments to perform an action with on blockchain.

In the example above we called a function with an argument: `0x0`, passed using `--calldata` flag.

Please note the notation of the argument. The default way of passing calldata is a list of hexadecimally encoded field elements - the *serialized* calldata.
To obtain the serialized form of the wished data, one must write a Cairo program calling `Serde::serialize` on subsequent arguments and displaying the results.

It is also possible to pass calldata in more friendly, human readable form thanks to the [calldata transformation](./calldata-transformation.md) feature present in Cast.

> ⚠️ **Warning**
> Cast will not verify the serialized calldata. Any errors caused by passing improper calldata in a serialized form will originate from the network.
> Basic static analysis is possible only when passing expressions - see [calldata transformation](./calldata-transformation.md).
### How to Use `--wait` Flag

Let's invoke a transaction and wait for it to be `ACCEPTED_ON_L2`.
Expand All @@ -53,7 +69,7 @@ $ sncast --account myuser \
deploy \
--url http://127.0.0.1:5050 \
--class-hash 0x8448a68b5ea1affc45e3fd4b8b480ea36a51dc34e337a16d2567d32d0c6f8a

Transaction hash: 0x3062310a1e40d4b66d8987ba7447d1c7317381d0295d62cb12f2fe3f11e6983
Waiting for transaction to be received. Retries left: 11
Waiting for transaction to be received. Retries left: 10
Expand Down

0 comments on commit 78f40e3

Please sign in to comment.