// 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); // 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 = 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 = 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 = 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())); }