/Seriality

Seriality is a library for serializing and de-serializing all the Solidity types in a very efficient way which mostly written in solidity-assembly

Primary LanguageSolidityApache License 2.0Apache-2.0

Seriality

Seriality is a library for serializing and de-serializing all the Solidity types in a very efficient way which mostly written in solidity-assembly.


Important points you need to know befor using this library

  • Seriality supports all the solidity types.

  • Please be aware that this library is written with assembly and could be unsafe, so use it if you really know what you are doing and how you should use the library.

  • The buffer size must be chosen very carefully, if you are not sure about that choose your biggest guess.

  • You must start serializing from the end of the buffer as well as deserializing.

  • You can use the SizeOf library independently to get the size of your variables.


What kind of problems can be addressed by Seriality?

(Proposal if the solidity allows passing dynamically sized type through contracts and libraries)

  • By means of Seriality you can easily serialize and deserialize your variables, structs, arrays, tuples, ... and pass them through the contracts and libraries.

  • You can decouple your contract from libraries by serializing parameters into a byte array.

  • It also can be used as an alternative for RLP protocol in Solidity.

Example

pragma solidity ^0.5.0;

import {Seriality} from "./Seriality.sol";


contract SerialitySample is Seriality {

    function testSample1() public pure returns(int n1, int8 n2, uint24 n3, string memory n4, string memory n5) {

        bytes memory buffer = new bytes(200);
        string memory out4  = new string(32);
        string memory out5  = new string(32);
        n4 = new string(32);
        n5 = new string(32);
        int     out1 = 34444445;
        int8    out2 = 87;
        uint24  out3 = 76545;
        out4 = "Copy kon lashi";
        out5 = "Bia inja dahan service";

        // Serializing
        uint offset = 200;

        intToBytes(offset, out2, buffer);
        offset -= sizeOfInt(8);

        uintToBytes(offset, out3, buffer);
        offset -= sizeOfUint(24);

        stringToBytes(offset, bytes(out5), buffer);
        offset -= sizeOfString(out5);

        stringToBytes(offset, bytes(out4), buffer);
        offset -= sizeOfString(out4);

        intToBytes(offset, out1, buffer);
        offset -= sizeOfInt(256);

        // Deserializing
        offset = 200;

        n2 = bytesToInt8(offset, buffer);
        offset -= sizeOfInt(8);

        n3 = bytesToUint24(offset, buffer);
        offset -= sizeOfUint(24);

        bytesToString(offset, buffer, bytes(n5));
        offset -= sizeOfString(out5);

        bytesToString(offset, buffer, bytes(n4));
        offset -= sizeOfString(out4);

        n1 = bytesToInt256(offset, buffer);

    }

    function testSample2() public pure returns(int8 n1, int24 n2, uint32 n3, int128 n4, address n5, address n6) {

        bytes memory buffer = new bytes(64);
        int8    out1 = -12;
        int24   out2 = 838860;
        uint32  out3 = 123;
        int128  out4 = -44444444444;
        address out5 = 0x90c2EA76336410195498E76E28c80922Bb495B53;
        address out6 = 0x313b1C7b270492214e011B7D36fde0Eb072A2798;

        // Serializing
        uint offset = 64;

        intToBytes(offset, out1, buffer);
        offset -= sizeOfInt(8);

        intToBytes(offset, out2, buffer);
        offset -= sizeOfUint(24);

        uintToBytes(offset, out3, buffer);
        offset -= sizeOfInt(32);

        intToBytes(offset, out4, buffer);
        offset -= sizeOfUint(128);

        addressToBytes(offset, out5, buffer);
        offset -= sizeOfAddress();

        addressToBytes(offset, out6, buffer);

        // Deserializing
        offset = 64;

        n1 = bytesToInt8(offset, buffer);
        offset -= sizeOfInt(8);

        n2 = bytesToInt24(offset, buffer);
        offset -= sizeOfUint(24);

        n3 = bytesToUint8(offset, buffer);
        offset -= sizeOfInt(32);

        n4 = bytesToInt128(offset, buffer);
        offset -= sizeOfUint(128);

        n5 = bytesToAddress(offset, buffer);
        offset -= sizeOfAddress();

        n6 = bytesToAddress(offset, buffer);

    }
}
// testSample1 output:
{
 "0": "int256: n1 34444445",
 "1": "int8: n2 87",
 "2": "uint24: n3 76545",
 "3": "string: n4 Copy kon lashi",
 "4": "string: n5 Bia inja dahan service"
}

// testSample2:
{
 "0": "int8: n1 -12",
 "1": "int24: n2 838860",
 "2": "uint32: n3 123",
 "3": "int128: n4 -44444444444",
 "4": "address: n5 0x90c2EA76336410195498E76E28c80922Bb495B53",
 "5": "address: n6 0x313b1C7b270492214e011B7D36fde0Eb072A2798"
}

Serializing types including strings

pragma solidity ^0.5.0;

import "./Seriality.sol";

contract StringsReturn is Seriality {

    function stringCaller() public pure returns(  string memory out1,
                                            string memory out2,
                                            string memory out3,
                                            string memory out4,
                                            string memory out5)
                                            {

        bytes memory buffer = new bytes(320);
        uint offset = stringCallee(buffer);

        //deserializing
        out1 = new string (getStringSize(offset, buffer));
        bytesToString(offset, buffer, bytes(out1));
        offset -= sizeOfString(out1);

        out2 = new string (getStringSize(offset, buffer));
        bytesToString(offset, buffer, bytes(out2));
        offset -= sizeOfString(out2);

        out3 = new string (getStringSize(offset, buffer));
        bytesToString(offset, buffer, bytes(out3));
        offset -= sizeOfString(out3);

        out4 = new string (getStringSize(offset, buffer));
        bytesToString(offset, buffer, bytes(out4));
        offset -= sizeOfString(out4);

        out5 = new string (getStringSize(offset, buffer));
        bytesToString(offset, buffer, bytes(out5));

    }

    function stringCallee(bytes memory buffer) public pure returns (uint buffer_size) {

        string memory out1  = new string(32);
        string memory out2  = new string(32);
        string memory out3  = new string(32);
        string memory out4  = new string(32);
        string memory out5  = new string(32);

        out1 = "Come on baby lets dance!";
        out2 = "May I buy you a drink?";
        out3 = "I am an itinerant programmer";
        out4 = "Inam javab lashi!";
        out5 = "Bia inja dahan service";

        // Serializing
        buffer_size = sizeOfString(out5) +
                       sizeOfString(out4) +
                       sizeOfString(out3) +
                       sizeOfString(out2) +
                       sizeOfString(out1);

        uint offset = buffer_size;

        stringToBytes(offset, bytes(out1), buffer);
        offset -= sizeOfString(out1);

        stringToBytes(offset, bytes(out2), buffer);
        offset -= sizeOfString(out2);

        stringToBytes(offset, bytes(out3), buffer);
        offset -= sizeOfString(out3);

        stringToBytes(offset, bytes(out4), buffer);
        offset -= sizeOfString(out4);

        stringToBytes(offset, bytes(out5), buffer);

        return buffer_size;

    }

}
// output buffer :

   [42696120696e6a6120646168616e207365727669636500000000000000000000
    0000000000000000000000000000000000000000000000000000000000000016
    496e616d206a61766162206c6173686921000000000000000000000000000000
    0000000000000000000000000000000000000000000000000000000000000011
    4920616d20616e206974696e6572616e742070726f6772616d6d657200000000
    000000000000000000000000000000000000000000000000000000000000001c
    4d617920492062757920796f752061206472696e6b3f00000000000000000000
    0000000000000000000000000000000000000000000000000000000000000016
    436f6d65206f6e2062616279206c6574732064616e6365210000000000000000
    0000000000000000000000000000000000000000000000000000000000000018]

 "0": "string: out1 Come on baby lets dance!",
 "1": "string: out2 May I buy you a drink?",
 "2": "string: out3 I am an itinerant programmer",
 "3": "string: out4 Inam javab lashi!",
 "4": "string: out5 Bia inja dahan service"

There is also an article in Hacker Noon written by Vasa which explains how you can use seriality for your project. https://hackernoon.com/serializing-string-arrays-in-solidity-db4b6037e520 Thanks to Vasa!

Using Seriality in your Hardhat project?

Install Seriality

// npm
npm install git+https://github.com/pouladzade/Seriality.git

// pnpm
pnpm install git+https://github.com/pouladzade/Seriality.git

// yarn
yarn add git+https://github.com/pouladzade/Seriality.git

Use Seriality as a library in your Solidity code

pragma solidity ^0.5.0;

import { Seriality } from "seriality/src/Seriality.sol";