Skip to content
This repository was archived by the owner on Aug 27, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions tests/EvmAcceptanceTests/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ node_modules/
artifacts/
cache/
typechain-types/
.openzeppelin/
2 changes: 1 addition & 1 deletion tests/EvmAcceptanceTests/artifacts/scilla.cache

Large diffs are not rendered by default.

24 changes: 23 additions & 1 deletion tests/EvmAcceptanceTests/contracts/BasicInterop.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pragma abicoder v2;
// Returned value is encoded via abi so you should call abi.decode() with proper type to obtain underlying value

contract BasicInterop {
event ResultWas(bool);

function callSimpleMap(address contract_address, string memory tran_name, address recipient, uint128 amount) public {
bytes memory encodedArgs = abi.encode(contract_address, tran_name, recipient, amount);
Expand Down Expand Up @@ -115,4 +116,25 @@ contract BasicInterop {
(retVal) = abi.decode(output, (string));
return retVal;
}
}

function callAndIgnoreResult(address contract_address, string memory tran_name) external returns (bool) {
bytes memory encodedArgs = abi.encode(contract_address, tran_name);
uint256 argsLength = encodedArgs.length;
bool success;
assembly {
success := call(21000, 0x5a494c52, 0, add(encodedArgs, 0x20), argsLength, 0x20, 0)
}
emit ResultWas(success);
return success;
}

function callIndirectAndIgnoreResult(address contract_address, address other_contract_address, string memory tran_name, string memory second_tran_name)
external returns (bool) {
bytes memory encodedArgs = abi.encode(contract_address, tran_name, other_contract_address, second_tran_name);
uint256 argsLength = encodedArgs.length;
bool success;
assembly { success := call(21000, 0x5a494c52, 0, add(encodedArgs, 0x20), argsLength, 0x20, 0) }
emit ResultWas(success);
return success;
}
}
169 changes: 169 additions & 0 deletions tests/EvmAcceptanceTests/contracts/DelegateDouble.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
// SPDX-License-Identifier: SEE LICENSE IN LICENSE
pragma solidity ^0.8.0;

// Similar to non-working proxy -> proxy code provided by @NFTs2Me in discord.
// - rrw 2023-05-06

contract DDContractA {
mapping(uint256 => address) private _owners;

event Msg(string message);
event Value(address val);
event Bool(bool val);
event Int(uint256 val);

function setOwner(uint256 tokenId) external {
emit Msg("SetOwnerA");
_owners[tokenId] = msg.sender;
}

function _ownerOf(uint256 tokenId) internal view virtual returns (address) {
return _owners[tokenId];
}

function ownerOf(uint256 tokenId) public view virtual returns (address) {
address owner = _ownerOf(tokenId);
require(owner != address(0), "ERC721: Invalid token ID");
return owner;
}

function getOwnerX(uint256 val) public returns (address) {
emit Msg("AOwnerX");
emit Value(_owners[val]);
return _owners[val];
}

}


// Proxy to Contract A
contract DDContractB {
mapping(uint256 => address) private _owners;
address public _impl;

event Msg(string message);
event Value(address val);
event Bool(bool val);
event Int(uint256 val);

function setImplementation(address _impl_in) external payable {
_impl = _impl_in;
}

function getOwnerX(uint256 val) public returns (address) {
emit Msg("BOwnerX");
emit Value(_owners[val]);
return _owners[val];
}

fallback() external payable virtual {
_delegate(_impl);
}

function _delegate(address implementation) internal virtual {
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize())
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)

// Copy the returned data.
returndatacopy(0, 0, returndatasize())

switch result
// delegatecall returns 0 on error.
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}

// Exists purely to get the solidity compiler to shut up about the lack of one
receive() external payable {
// Do nothing.
}
}

// Contract C
contract DDContractC {
address public _contract_b;

event Msg(string message);
event Value(address val);
event Bool(bool val);
event Int(uint256 val);


// msg.sender here should be ContractC (or ContractD if proxied)
function setOwner(uint256 tokenId) public {
emit Msg("SetOwnerC");
DDContractA(_contract_b).setOwner(tokenId);
emit Msg("SetOwnerC done");
emit Value(_contract_b);
}

function owner() public returns (address collectionOwner) {
emit Msg("Hello");
try DDContractA(_contract_b).ownerOf(uint256(uint160(address(this)))) returns (address ownerOf) {
emit Value(ownerOf);
return ownerOf;
} catch {
emit Msg("Caught exception");
}
}
}

// Contract D
contract DDContractD {
address public _contract_b;
address public _impl;

event Msg(string message);
event Value(address val);
event Bool(bool val);
event Int(uint256 val);

function setImplementation(address _impl_in, address _contract_b_in) external payable {
_impl = _impl_in;
_contract_b = _contract_b_in;
}

fallback() external payable virtual {
_delegate(_impl);
}

function _delegate(address implementation) internal virtual {
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize())
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)

// Copy the returned data.
returndatacopy(0, 0, returndatasize())

switch result
// delegatecall returns 0 on error.
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}

// Exists purely to get the solidity compiler to shut up about the lack of one
receive() external payable {
// Do nothing.
}
}
52 changes: 52 additions & 0 deletions tests/EvmAcceptanceTests/contracts/PizzaPlusUUPS.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

// Open Zeppelin libraries for controlling upgradability and access.
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

// Sample upgradeable contract from https://blog.logrocket.com/using-uups-proxy-pattern-upgrade-smart-contracts/
contract PizzaPlusUUPS is Initializable, UUPSUpgradeable, OwnableUpgradeable {
uint256 public slices;
mapping(address => address) public addresses;

event AddressIs(address);
event AddressIsNot();

///@dev no constructor in upgradable contracts. Instead we have initializers
///@param _sliceCount initial number of slices for the pizza
function initialize(uint256 _sliceCount) public initializer {
slices = _sliceCount;

///@dev as there is no constructor, we need to initialise the OwnableUpgradeable explicitly
__Ownable_init();
}

///@dev required by the OZ UUPS module
function _authorizeUpgrade(address) internal override onlyOwner {}

///@dev decrements the slices when called
function eatSlice() external {
require(slices > 1, "no slices left");
slices -= 1;
}

function setAddress() external {
addresses[msg.sender] = msg.sender;
}

function getAddress() external returns (address) {
if (addresses[msg.sender] != address(0)) {
emit AddressIs(addresses[msg.sender]);
return addresses[msg.sender];
} else {
emit AddressIsNot();
return address(0);
}
}

function getAddressPure() external view returns (address) {
return addresses[msg.sender];
}
}
33 changes: 33 additions & 0 deletions tests/EvmAcceptanceTests/contracts/PizzaUUPS.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

// Open Zeppelin libraries for controlling upgradability and access.
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

// Sample upgradeable contract from https://blog.logrocket.com/using-uups-proxy-pattern-upgrade-smart-contracts/
contract PizzaUUPS is Initializable, UUPSUpgradeable, OwnableUpgradeable {
uint256 public slices;

///@dev no constructor in upgradable contracts. Instead we have initializers
///@param _sliceCount initial number of slices for the pizza
function initialize(uint256 _sliceCount) public initializer {
slices = _sliceCount;

///@dev as there is no constructor, we need to initialise the OwnableUpgradeable explicitly
__Ownable_init();
}

///@dev required by the OZ UUPS module
function _authorizeUpgrade(address) internal override onlyOwner {}

///@dev decrements the slices when called
function eatSlice() external {
require(slices > 1, "no slices left");
slices -= 1;
}
function getSlices() external view returns (uint256) {
return slices;
}
}
Loading