// SPDX-License-Identifier: Apache-2.0 use parity_scale_codec::{Decode, Encode}; use crate::build_solidity; #[test] fn external_call_value() { let mut runtime = build_solidity( r##" contract b { a f; function step1() public { f = new a(); } function step2() public { f.test{value: 1023}(501); } } contract a { function test(int32 l) public payable { } }"##, ); runtime.constructor(0, Vec::new()); runtime.function("step1", Vec::new()); runtime.function("step2", Vec::new()); for (address, account) in runtime.accounts { if address == runtime.vm.account { continue; } assert_eq!(account.1, 1523); } let mut runtime = build_solidity( r##" contract b { function step1() public { a f = new a(); try f.test{value: 1023}(501) { // } catch (bytes) { // } } } contract a { function test(int32 l) public payable { } }"##, ); runtime.constructor(0, Vec::new()); runtime.function("step1", Vec::new()); for (address, account) in runtime.accounts { if address == runtime.vm.account { continue; } assert_eq!(account.1, 1523); } } #[test] fn constructor_value() { let mut runtime = build_solidity( r##" contract b { function step1() public { a f = new a(); } } contract a { function test(int32 l) public payable { } }"##, ); runtime.constructor(0, Vec::new()); runtime.function("step1", Vec::new()); for (address, account) in runtime.accounts { if address == runtime.vm.account { continue; } assert_eq!(account.1, 500); } let mut runtime = build_solidity( r##" contract b { function step1() public { a f = (new a){value: 0}(); } } contract a { function test(int32 l) public payable { } }"##, ); runtime.constructor(0, Vec::new()); runtime.function("step1", Vec::new()); for (address, account) in runtime.accounts { if address == runtime.vm.account { continue; } assert_eq!(account.1, 0); } let mut runtime = build_solidity( r##" contract b { function step1() public { a f = new a{value: 499}(); } } contract a { function test(int32 l) public payable { } }"##, ); runtime.constructor(0, Vec::new()); runtime.function("step1", Vec::new()); for (address, account) in runtime.accounts { if address == runtime.vm.account { continue; } assert_eq!(account.1, 499); } let mut runtime = build_solidity( r##" contract b { function step1() public { try (new a{value: 511})() { // } catch (bytes) { // } } } contract a { function test(int32 l) public payable { } }"##, ); runtime.constructor(0, Vec::new()); runtime.function("step1", Vec::new()); for (address, account) in runtime.accounts { if address == runtime.vm.account { continue; } assert_eq!(account.1, 511); } let mut runtime = build_solidity( r##" contract b { function step1() public { try (new a){value: 511}() returns (a) { // } catch (bytes) { // } } } contract a { function test(int32 l) public payable { } }"##, ); runtime.constructor(0, Vec::new()); runtime.function("step1", Vec::new()); for (address, account) in runtime.accounts { if address == runtime.vm.account { continue; } assert_eq!(account.1, 511); } } #[test] fn constructor_salt() { let mut runtime = build_solidity( r##" contract b { function step1() public { a f = new a{salt: 0}(); } } contract a { function test(int32 l) public payable { } }"##, ); runtime.constructor(0, Vec::new()); runtime.function("step1", Vec::new()); let mut runtime = build_solidity( r##" contract b { function step1() public { a f = new a{salt: 1}(); } } contract a { function test(int32 l) public payable { } }"##, ); runtime.constructor(0, Vec::new()); runtime.function("step1", Vec::new()); // we can instantiate the same contract if we provide a different contract let mut runtime = build_solidity( r##" contract b { function step1() public { a f = new a{salt: 1}(); f = new a{salt: 2}(); } } contract a { function test(int32 l) public payable { } }"##, ); runtime.constructor(0, Vec::new()); runtime.function("step1", Vec::new()); } #[test] fn this_address() { let mut runtime = build_solidity( r##" contract b { function step1() public returns (address) { return address(this); } }"##, ); runtime.constructor(0, Vec::new()); runtime.function("step1", Vec::new()); assert_eq!(runtime.vm.output, runtime.vm.account); let mut runtime = build_solidity( r##" contract b { function step1() public returns (b) { return this; } }"##, ); runtime.constructor(0, Vec::new()); runtime.function("step1", Vec::new()); assert_eq!(runtime.vm.output, runtime.vm.account); #[derive(Debug, PartialEq, Eq, Encode, Decode)] struct Ret(u32); let mut runtime = build_solidity( r##" contract b { int32 s; function step1() public returns (int32) { this.other(102); return s; } function other(int32 n) public { s = n; } }"##, ); runtime.constructor(0, Vec::new()); runtime.function("step1", Vec::new()); assert_eq!(runtime.vm.output, Ret(102).encode()); let mut runtime = build_solidity( r##" contract b { function step1() public returns (b) { return this; } }"##, ); runtime.constructor(0, Vec::new()); runtime.function("step1", Vec::new()); assert_eq!(runtime.vm.output, runtime.vm.account); } #[test] fn balance() { let mut runtime = build_solidity( r##" contract b { other o; constructor() public { o = new other(); } function step1() public returns (uint128) { return address(this).balance; } function step2() public returns (uint128) { return o.balance(); } } contract other { function balance() public returns (uint128) { return address(this).balance; } }"##, ); runtime.constructor(0, Vec::new()); runtime.accounts.get_mut(&runtime.vm.account).unwrap().1 = 315; runtime.function("step1", Vec::new()); assert_eq!(runtime.vm.output, 315u128.to_le_bytes()); runtime.function("step2", Vec::new()); assert_eq!(runtime.vm.output, 500u128.to_le_bytes()); } #[test] fn selfdestruct() { let mut runtime = build_solidity( r##" contract c { other o; function step1() public { o = new other{value: 511}(); } function step2() public { o.goaway(payable(address(this))); } } contract other { function goaway(address payable recipient) public returns (bool) { selfdestruct(recipient); } }"##, ); runtime.constructor(0, Vec::new()); runtime.function("step1", Vec::new()); assert_eq!(runtime.accounts.get_mut(&runtime.vm.account).unwrap().1, 0); runtime.function_expect_failure("step2", Vec::new()); assert_eq!( runtime.accounts.get_mut(&runtime.vm.account).unwrap().1, 511 ); } #[test] fn send_and_transfer() { let mut runtime = build_solidity( r##" contract c { other o; constructor() public { o = new other(); } function step1() public returns (bool) { return payable(o).send(511); } } contract other { function giveme() public payable { } }"##, ); runtime.constructor(0, Vec::new()); runtime.function("step1", Vec::new()); // no receive() required for send/transfer assert_eq!(runtime.vm.output, true.encode()); for (address, account) in runtime.accounts { if address == runtime.vm.account { continue; } assert_eq!(account.1, 1011); } let mut runtime = build_solidity( r##" contract c { other o; constructor() public { o = new other(); } function step1() public returns (bool) { return payable(o).send(511); } } contract other { receive() external payable { } }"##, ); runtime.constructor(0, Vec::new()); runtime.function("step1", Vec::new()); assert_eq!(runtime.vm.output, true.encode()); for (address, account) in runtime.accounts { if address == runtime.vm.account { continue; } assert_eq!(account.1, 1011); } let mut runtime = build_solidity( r##" contract c { other o; constructor() public { o = new other(); } function step1() public { payable(o).transfer(511); } } contract other { function giveme() public { } }"##, ); runtime.constructor(0, Vec::new()); runtime.function("step1", Vec::new()); for (address, account) in runtime.accounts { if address == runtime.vm.account { continue; } assert_eq!(account.1, 1011); } let mut runtime = build_solidity( r##" contract c { other o; constructor() public { o = new other(); } function step1() public { payable(o).transfer(511); } } contract other { receive() external payable { } }"##, ); runtime.constructor(0, Vec::new()); runtime.function("step1", Vec::new()); for (address, account) in runtime.accounts { if address == runtime.vm.account { continue; } assert_eq!(account.1, 1011); } }