solang 0.2.1

Solang Solidity Compiler
Documentation
// SPDX-License-Identifier: Apache-2.0

use crate::build_solidity;
use parity_scale_codec::{Decode, Encode};

#[derive(Debug, PartialEq, Eq, Encode, Decode)]
struct RevertReturn(u32, String);

#[test]
fn external_call() {
    #[derive(Debug, PartialEq, Eq, Encode, Decode)]
    struct Ret(u32);

    let mut runtime = build_solidity(
        r##"
        contract c {
            b x;
            constructor() public {
                x = new b(102);
            }
            function test() public returns (int32) {
                return x.get_x({ t: 10 });
            }
        }

        contract b {
            int32 x;
            constructor(int32 a) public {
                x = a;
            }
            function get_x(int32 t) public returns (int32) {
                return x * t;
            }
        }"##,
    );

    runtime.constructor(0, Vec::new());

    runtime.function("test", Vec::new());

    assert_eq!(runtime.vm.output, Ret(1020).encode());
}

#[test]
fn revert_external_call() {
    let mut runtime = build_solidity(
        r##"
        contract c {
            b x;
            constructor() public {
                x = new b(102);
            }
            function test() public returns (int32) {
                return x.get_x({ t: 10 });
            }
        }

        contract b {
            int32 x;
            constructor(int32 a) public {
                x = a;
            }
            function get_x(int32 t) public returns (int32) {
                revert("The reason why");
            }
        }"##,
    );

    runtime.constructor(0, Vec::new());

    runtime.function_expect_failure("test", Vec::new());
}

#[test]
fn revert_constructor() {
    let mut runtime = build_solidity(
        r##"
        contract c {
            b x;
            constructor() public {
            }
            function test() public returns (int32) {
                x = new b(102);
                return x.get_x({ t: 10 });
            }
        }

        contract b {
            int32 x;
            constructor(int32 a) public {
                require(a == 0, "Hello,\
 World!");
            }

            function get_x(int32 t) public returns (int32) {
                return x * t;
            }
        }"##,
    );

    runtime.constructor(0, Vec::new());

    runtime.function_expect_failure("test", Vec::new());

    assert_eq!(runtime.vm.output.len(), 0);
}

#[test]
fn external_datatypes() {
    #[derive(Debug, PartialEq, Eq, Encode, Decode)]
    struct Ret(u64);

    let mut runtime = build_solidity(
        r##"
        contract c {
            b x;
            constructor() public {
                x = new b(102);
            }

            function test() public returns (int64) {
                strukt k = x.get_x(10, "foobar", true, strukt({ f1: "abcd", f2: address(555555), f3: -1 }));

                assert(k.f1 == "1234");
                assert(k.f2 == address(102));
                return int64(k.f3);
            }
        }

        contract b {
            int x;
            constructor(int a) public {
                x = a;
            }

            function get_x(int t, string s, bool y, strukt k) public returns (strukt) {
                assert(y == true);
                assert(t == 10);
                assert(s == "foobar");
                assert(k.f1 == "abcd");

                return strukt({ f1: "1234", f2: address(102), f3: x * t });
            }
        }

        struct strukt {
            bytes4 f1;
            address f2;
            int f3;
        }"##,
    );

    runtime.constructor(0, Vec::new());

    runtime.function("test", Vec::new());

    assert_eq!(runtime.vm.output, Ret(1020).encode());
}

#[test]
fn creation_code() {
    let mut runtime = build_solidity(
        r##"
        contract c {
            function test() public returns (bytes) {
                bytes runtime = type(b).runtimeCode;

                assert(runtime[0] == 0);
                assert(runtime[1] == 0x61); // a
                assert(runtime[2] == 0x73); // s
                assert(runtime[3] == 0x6d); // m

                bytes creation = type(b).creationCode;

                // on Substrate, they are the same
                assert(creation == runtime);

                return creation;
            }
        }

        contract b {
            int public x;
            constructor(int a) public {
                x = a;
            }
        }"##,
    );

    runtime.constructor(0, Vec::new());

    runtime.function("test", Vec::new());

    #[derive(Debug, PartialEq, Eq, Encode, Decode)]
    struct Ret(Vec<u8>);

    // return value should be the code for the second contract
    assert_eq!(
        runtime.vm.output,
        Ret(runtime.programs[1].code.clone()).encode()
    );
}

#[test]
fn issue666() {
    let mut runtime = build_solidity(
        r##"
        contract Flipper {
            function flip () pure public {
                print("flip");
            }
        }

        contract Inc {
            Flipper _flipper;

            constructor (Flipper _flipperContract) {
                _flipper = _flipperContract;
            }

            function superFlip () pure public {
                _flipper.flip();
            }
        }"##,
    );

    runtime.constructor(0, Vec::new());

    let flipper_address = runtime.vm.account;

    println!("flipper_address={}", hex::encode(flipper_address));

    runtime.set_program(1);

    runtime.constructor(0, flipper_address.to_vec());

    runtime.function("superFlip", Vec::new());

    assert!(runtime.vm.output.is_empty());
}

#[test]
fn mangle_function_names_in_abi() {
    let runtime = build_solidity(
        r##"
        enum E { v1, v2 }
        struct S { int256 i; bool b; address a; }

        contract C {
            // foo_
            function foo() public pure {}

            // foo_uint256_addressArray2Array
            function foo(uint256 i, address[2][] memory a) public pure {}

            // foo_uint8Array2__int256_bool_address
            function foo(E[2] memory e, S memory s) public pure {}
        }"##,
    );

    let messages: Vec<String> = runtime
        .programs
        .get(0)
        .unwrap()
        .abi
        .spec()
        .messages()
        .iter()
        .map(|m| m.label().clone())
        .collect();

    assert!(!messages.contains(&"foo".to_string()));
    assert!(messages.contains(&"foo_".to_string()));
    assert!(messages.contains(&"foo_uint256_addressArray2Array".to_string()));
    assert!(messages.contains(&"foo_uint8Array2__int256_bool_address".to_string()));
}

#[test]
fn mangle_overloaded_function_names_in_abi() {
    let runtime = build_solidity(
        r##"
        contract A {
            function foo(bool x) public {}
        }

        contract B is A {
            function foo(int x) public {}
        }"##,
    );

    let messages_a: Vec<String> = runtime
        .programs
        .get(0)
        .unwrap()
        .abi
        .spec()
        .messages()
        .iter()
        .map(|m| m.label().clone())
        .collect();

    assert!(messages_a.contains(&"foo".to_string()));
    assert!(!messages_a.contains(&"foo_bool".to_string()));

    let messages_b: Vec<String> = runtime
        .programs
        .get(1)
        .unwrap()
        .abi
        .spec()
        .messages()
        .iter()
        .map(|m| m.label().clone())
        .collect();

    assert!(!messages_b.contains(&"foo".to_string()));
    assert!(messages_b.contains(&"foo_bool".to_string()));
}