32 releases (14 stable)

4.1.1 Apr 17, 2024
4.0.2 Mar 14, 2024
4.0.0-rc.1 Dec 1, 2023
4.0.0-rc Nov 30, 2023
0.1.0 Jun 8, 2022

#1785 in Magic Beans

Download history 1231/week @ 2024-03-13 621/week @ 2024-03-20 480/week @ 2024-03-27 509/week @ 2024-04-03 691/week @ 2024-04-10 871/week @ 2024-04-17 821/week @ 2024-04-24 359/week @ 2024-05-01 1002/week @ 2024-05-08 1109/week @ 2024-05-15 826/week @ 2024-05-22 1554/week @ 2024-05-29 432/week @ 2024-06-05 649/week @ 2024-06-12 780/week @ 2024-06-19 839/week @ 2024-06-26

3,264 downloads per month
Used in 9 crates (6 directly)

Apache-2.0

175KB
4K SLoC

Contract Transcode

Contains utilities for encoding smart contract calls to SCALE.

Currently part of cargo-contract, the build tool for smart contracts written in ink!.

See crate docs for example usage.


lib.rs:

For interacting with contracts from the command line, arguments need to be "transcoded" from the string representation to the SCALE encoded representation.

e.g. "false" -> 0x00

And for displaying SCALE encoded data from events and RPC responses, it must be "transcoded" in the other direction from the SCALE encoded representation to a human readable string.

e.g. 0x00 -> "false"

Transcoding depends on scale-info metadata in order to dynamically determine the expected types.

Encoding

First the string is parsed into an intermediate Value:

"false" -> Value::Bool(false)

This value is then matched with the metadata for the expected type in that context. e.g. the flipper contract accepts a bool argument to its new constructor, which will be reflected in the contract metadata as scale_info::TypeDefPrimitive::Bool.

#[ink(constructor)]
pub fn new(init_value: bool) -> Self {
    Self { value: init_value }
}

The parsed Value::Bool(false) argument value is then matched with the scale_info::TypeDefPrimitive::Bool type metadata, and then the value can be safely encoded as a bool, resulting in 0x00, which can then be appended as data to the message to invoke the constructor.

Decoding

First the type of the SCALE encoded data is determined from the metadata. e.g. the return type of a message when it is invoked as a "dry run" over RPC:

#[ink(message)]
pub fn get(&self) -> bool {
    self.value
}

The metadata will define the return type as scale_info::TypeDefPrimitive::Bool, so that when the raw data is received it can be decoded into the correct Value, which is then converted to a string for displaying to the user:

0x00 -> Value::Bool(false) -> "false"

SCALE Object Notation (SCON)

Complex types can be represented as strings using SCON for human-computer interaction. It is intended to be similar to Rust syntax for instantiating types. e.g.

Foo { a: false, b: [0, 1, 2], c: "bar", d: (0, 1) }

This string could be parsed into a Value::Map and together with scale_info::TypeDefComposite metadata could be transcoded into SCALE encoded bytes.

As with the example for the primitive bool above, this works in the other direction for decoding SCALE encoded bytes and converting them into a human readable string.

Example

let metadata_path = Path::new("/path/to/contract.json");
let transcoder = ContractMessageTranscoder::load(metadata_path).unwrap();

let constructor = "new";
let args = ["foo", "bar"];
let data = transcoder.encode(&constructor, &args).unwrap();

println!("Encoded constructor data {:?}", data);

Dependencies

~9MB
~196K SLoC