> For the complete documentation index, see [llms.txt](https://docs.ont.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ont.io/guides-and-tutorials/development-guides/smart-contract-dev/wasm/fundamentals.md).

# Contract Fundamentals

Some common aspects of smart contract development process are:&#x20;

1. Parameter processing upon contract invocation&#x20;
2. Storing the user-defined data structures on the blockchain
3. Fetching and reading the on-chain data and processing and resolving them to original data types
4. Transferring the parameters to the target contract when carrying out cross-contract invocation

Most of these aspects involve serialization and deserialization of data. Here we talk about data serialization and deserialization in Ontology **WASM** contracts.

{% hint style="success" %}
A template contract has been made available [**here**](https://github.com/ontio/rust-wasm-contract-template) on Github for the developers to make **WASM** contract development in Rust convenient. The template provides a script to compile the contract and a basic structure to start working with.&#x20;
{% endhint %}

### Encoder and Decoder Interfaces

The Encoder and Decoder interfaces define serialization and deserialization methods respectively for different data types. For the specific implementation logic, please refer to the `sink.rs` file. The `ontology-wasm-cdt-rust` library supports most commonly used data types, for e.g. **\&str**, **u8**, **u16**, **u32**, **u64**, **u128**, **bool**, **H256**, **Address**, **Vec**, **String**, and **tuple**. Sample code for serialization and deserialization of different data types:

```rust
let mut sink = Sink::new(16);
sink.write(1u128);
sink.write(true);
let addr = Address::repeat_byte(1);
sink.write(addr);
sink.write("test");
let vec_data = vec!["hello","world"];
sink.write(&vec_data);
let tuple_data = (1u8, "hello");
sink.write(tuple_data);
let mut source = Source::new(sink.bytes());
let res1:u128 = source.read().unwrap_or_default();
let res2:bool = source.read().unwrap_or_default();
let res3:Address = source.read().unwrap_or_default();
let res4:&str = source.read().unwrap_or_default();
let res5:Vec<&str> = source.read().unwrap_or_default();
let res6:(u8, &str) = source.read().unwrap_or_default();
assert_eq!(res1, 1u128);
assert_eq!(res2, true);
assert_eq!(res3, addr);
assert_eq!(res4, "test");
assert_eq!(res5, vec_data);
assert_eq!(res6, tuple_data);
```

All the parameters passed to the `sink.write()` method support all the data types that implement the Encoder interface. Their data types need to be declared when serializing, for example `1u128`. The `source.read()` method can fetch and read all the data types that implement the Decoder interface. The target data type needs to be specified when deserializing as follows:

```rust
let res1:u8 = source.read().unwrap_or_default();
```

The data type needs to be specified after `res1`. Here, the data type is `u8`.

```rust
let res1 = source.read_byte().unwrap_or_default();
```

Since reading is carried out using the the `read_byte` method it is not necessary to specify the data type.

### Processing Contract Invocation Parameters

The contract fetches the invocation parameters using the `runtime::input()` method. But, this method can only fetch parameters of the `bytearray` type. This parameter can be deserialized to the corresponding method name and method parameters. Sample code for serialization and deserialization:

```rust
let input = runtime::input();
let mut source = Source::new(&input);
let method_name: &str = source.read().unwrap();
let mut sink = Sink::new();
match method_name {
    "transfer" => {
        let (from, to, amount) = source.read().unwrap();
        sink.write(ont::transfer(from, to, amount));
    }
    _ => panic!("unsupported action!"),
}
```

Rust supports type derivation. For most cases, type declaration is not necessary. For example, `ont::transfer()` method declares the data type for `from`, `to`, and `amount` variables, and so data type declaration is not required for these variables.

Deserialization for the `Vec<&str>` data type can be carried out in the following way:

```rust
let param:Vec<&str> = source.read().unwrap();
```

Deserialization for the `Vec<(&str, U128, Address)>` data type can be carried out in the following way:

### ONT and ONG Transfers

The WASM contract development tools already encapsulate methods that can used to invoke **ONT** and **ONG** native contracts. The `contract` module contains these methods, and can be invoked in the following fashion:

```rust
#![no_std]
use ostd::contract::ont;
fn ont_transfer(&self, from: &Address, to: &Address, amount: U128) -> bool {
    ont::transfer(&from, &to, amount)
}
fn ong_transfer(&self, from: &Address, to: &Address, amount: U128) -> bool {
    ong::transfer(&from, &to, amount)
}
#[no_mangle]
pub fn invoke() {
    let input = runtime::input();
    let mut source = Source::new(&input);
    let action = source.read().unwrap();
    let mut sink = Sink::new(12);
    match action {
        "ont_transfer" => {
            let (from, to, amount) = source.read().unwrap();
            sink.write(ont_transfer(from, to, amount));
          },
          "ong_transfer" => {
              let (from, to, amount) = source.read().unwrap();
              sink.write(ong_transfer(from, to, amount));
            },
        _ => panic!("unsupported action!"),
    }

    runtime::ret(sink.bytes())
}
```

```rust
let param:Vec<(&str,U128,Address)>= source.read().unwrap();
```

### Serializing the User-defined Data Structures

While developing smart contracts we often need to serialize and deserialize data of type `struct`. To achieve this function, `#[derive(Encoder, Decoder)]` can be conveniently added above the struct declaration statement. Refer to the code:

```rust
#[derive(Encoder, Decoder)]
struct ReceiveRecord {
    account: Address,
    amount: u64,
}

#[derive(Encoder, Decoder)]
struct EnvlopeStruct {
    token_addr: Address,
    total_amount: u64,
    total_package_count: u64,
    remain_amount: u64,
    remain_package_count: u64,
    records: Vec<ReceiveRecord>,
}
```

{% hint style="info" %}
When using this feature to carry out serialization and deserialization, it is important to ensure that all the fields of `struct` implement the `Encoder` and `Decoder` interface.
{% endhint %}

```rust
let addr = Address::repeat_byte(1);
let rr = ReceiveRecord{
    account: addr,
    amount: 1u64,
};
let es = EnvlopeStruct{
    token_addr: addr,
    total_amount: 1u64,
    total_package_count: 1u64,
    remain_amount: 1u64,
    remain_package_count: 1u64,
    records: vec![rr],
};
let mut sink = Sink::new(16);
sink.write(&es);

let mut source = Source::new(sink.bytes());
let es2:EnvlopeStruct = source.read().unwrap();

assert_eq!(&es.token_addr,&es2.token_addr);
assert_eq!(&es.total_amount,&es2.total_amount);
assert_eq!(&es.total_package_count,&es2.total_package_count);
assert_eq!(&es.remain_amount,&es2.remain_amount);
assert_eq!(&es.remain_package_count,&es2.remain_package_count);
```

### Fetching On-chain Data of Specific Data Types

The different types of data that are handled in a contract can be stored on the blockchain. But these different data types first need to be converted to `bytearray` type using serialization. Similarly, the data that is fetched from the blockchain is in the `bytearray` form and needs to be deserialized to obtain results in specific data types. The `database` module provides several simple API methods that are available for the developer to use.

```rust
put<K: AsRef<[u8]>, T: Encoder>(key: K, val: T)
```

The `T` data type is saved based on the `key`, and the type `T` is to implement the **Encoder** interface.

#### Sample code

```rust
let es = EnvlopeStruct{
    token_addr: addr,
    total_amount: 1u64,
    total_package_count: 1u64,
    remain_amount: 1u64,
    remain_package_count: 1u64,
    records: vec![rr],
};
database::put("key", es);
```

From the above example it is clear that when using the `database::put` method, first we serialize the `es` parameter, and then save the result on the blockchain.

```rust
fn get<K: AsRef<[u8]>, T>(key: K) -> Option<T> where for<'a> T: Decoder<'a> + 'static,
```

Here we fetch data of type `T` using the `key`. The `T` data type requires implementation of the Decoder interface.

#### Example

```rust
let res:EnvelopeStruct = database::get("key").unwrap();
```

From the example above we can see that the `database::get` method fetches data of the type `bytearray` from the chain, and then needs to be deserialized to obtain the result in the `EnvelopeStruct` format.

### Cross Contract Parameter Transfer

In the case of cross contract invocation, the parameters are transferred in the `bytearray` format. Thus, it is necessary to serialize different data types to `bytearray` format. An example for a cross contract invocation in the case of a WASM contract:

```rust
let (contract_address,method,a, b): (&Address,&str,u128, u128) = source.read().unwrap();
let mut sink = Sink::new(16);
sink.write(method);
sink.write(a);
sink.write(b);
let resv = runtime::call_contract(contract_address, sink.bytes()).expect("get no return");
```
