20 releases (8 stable)

3.0.1 May 18, 2023
2.2.1 Apr 29, 2023
2.1.0 Mar 10, 2023
2.0.0-beta.1 Dec 7, 2022
0.1.0 Jun 8, 2022

#875 in Magic Beans

Download history 593/week @ 2023-02-03 602/week @ 2023-02-10 562/week @ 2023-02-17 583/week @ 2023-02-24 983/week @ 2023-03-03 1310/week @ 2023-03-10 1504/week @ 2023-03-17 1159/week @ 2023-03-24 763/week @ 2023-03-31 456/week @ 2023-04-07 735/week @ 2023-04-14 683/week @ 2023-04-21 522/week @ 2023-04-28 607/week @ 2023-05-05 1128/week @ 2023-05-12 872/week @ 2023-05-19

3,241 downloads per month
Used in 3 crates (2 directly)

Apache-2.0

165KB
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

# use contract_metadata::ContractMetadata;
# use contract_transcode::ContractMessageTranscoder;
# use std::{path::Path, fs::File};
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
~210K SLoC