DCIPs/assets/eip-3448/MetaProxyTest.sol

191 lines
5.6 KiB
Solidity

// SPDX-License-Identifier: CC0-1.0
pragma solidity >=0.7.6;
import './MetaProxyFactory.sol';
/// @notice This contract includes test cases for the MetaProxy standard.
contract MetaProxyTest is MetaProxyFactory {
uint256 public someValue;
event SomeEvent(
address a,
uint256 b,
uint256[] c
);
event SomeData(bytes data);
/// @notice One-time initializer.
function init () external payable {
require(someValue == 0);
(, uint256 b, ) = MetaProxyTest(this).getMetadataViaCall();
require(b > 0);
someValue = b;
}
/// @notice MetaProxy construction via abi encoded bytes.
/// Arguments are reversed for testing purposes.
function createFromBytes (
uint256[] calldata c,
uint256 b,
address a
) external payable returns (address proxy) {
// creates a new proxy where the metadata is the result of abi.encode()
proxy = MetaProxyFactory._metaProxyFromBytes(address(this), abi.encode(a, b, c));
require(proxy != address(0));
// optional one-time setup, a constructor() substitute
MetaProxyTest(proxy).init{ value: msg.value }();
}
/// @notice MetaProxy construction via calldata.
function createFromCalldata (
address a,
uint256 b,
uint256[] calldata c
) external payable returns (address proxy) {
// creates a new proxy where the metadata is everything after the 4th byte from calldata.
proxy = MetaProxyFactory._metaProxyFromCalldata(address(this));
require(proxy != address(0));
// optional one-time setup, a constructor() substitute
MetaProxyTest(proxy).init{ value: msg.value }();
}
/// @notice Returns the metadata of this (MetaProxy) contract.
/// Only relevant with contracts created via the MetaProxy standard.
/// @dev This function is aimed to be invoked with- & without a call.
function getMetadataWithoutCall () public pure returns (
address a,
uint256 b,
uint256[] memory c
) {
bytes memory data;
assembly {
let posOfMetadataSize := sub(calldatasize(), 32)
let size := calldataload(posOfMetadataSize)
let dataPtr := sub(posOfMetadataSize, size)
data := mload(64)
// increment free memory pointer by metadata size + 32 bytes (length)
mstore(64, add(data, add(size, 32)))
mstore(data, size)
let memPtr := add(data, 32)
calldatacopy(memPtr, dataPtr, size)
}
return abi.decode(data, (address, uint256, uint256[]));
}
/// @notice Returns the metadata of this (MetaProxy) contract.
/// Only relevant with contracts created via the MetaProxy standard.
/// @dev This function is aimed to to be invoked via a call.
function getMetadataViaCall () public pure returns (
address a,
uint256 b,
uint256[] memory c
) {
assembly {
let posOfMetadataSize := sub(calldatasize(), 32)
let size := calldataload(posOfMetadataSize)
let dataPtr := sub(posOfMetadataSize, size)
calldatacopy(0, dataPtr, size)
return(0, size)
}
}
/// @notice Runs all test cases
function testAll () external payable {
(address a, uint256 b, uint256[] memory c) = abc();
MetaProxyTest self = MetaProxyTest(address(this));
{
address proxy = self.createFromCalldata(a, b, c);
testProxy(proxy);
}
{
address proxy = self.createFromBytes(c, b, a);
testProxy(proxy);
}
}
function abc () public returns (address a, uint256 b, uint256[] memory c) {
a = address(this);
b = 0xc0ffe;
c = new uint256[](9);
}
function testProxy (address _proxy) public {
require(_proxy != address(0));
(address a, uint256 b, uint256[] memory c) = abc();
MetaProxyTest proxy = MetaProxyTest(_proxy);
{
(address x, uint256 y, uint256[] memory z) = proxy.getMetadataViaCall();
require(a == x && b == y && keccak256(abi.encode(c)) == keccak256(abi.encode(z)));
}
{
(address x, uint256 y, uint256[] memory z) = proxy.getMetadataWithoutCall();
require(a == x && b == y && keccak256(abi.encode(c)) == keccak256(abi.encode(z)));
}
require(proxy.someValue() == b);
require(proxy.testReturnSingle() == b);
bytes memory _bytes = hex'68656c6c6f20776f726c64';
(uint256 x, uint256[] memory y) = proxy.testReturnMulti(_bytes, uint160(address(this)) + b);
require(x == b);
require(y.length == c.length);
(bool success, bytes memory returnData) = _proxy.call(abi.encodeWithSignature('testRevert(string)', _bytes));
require(success == false);
require(keccak256(returnData) == keccak256(abi.encodeWithSignature('Error(string)', _bytes)));
}
function testReturnSingle () public returns (uint256) {
(
address a,
uint256 b,
uint256[] memory c
) = MetaProxyTest(this).getMetadataViaCall();
require(a == msg.sender);
require(b == someValue);
require(c.length == 9);
emit SomeEvent(a, b, c);
return b;
}
function testReturnMulti (bytes memory data, uint256 xyz) public returns (uint256, uint256[] memory) {
(
address a,
uint256 b,
uint256[] memory c
) = getMetadataWithoutCall();
require(a == msg.sender);
require(b == someValue);
require(c.length == 9);
require(xyz == uint160(a) + b);
bytes memory expected = hex'68656c6c6f20776f726c64';
require(data.length == expected.length);
for (uint256 i = 0; i < expected.length; i++) {
require(data[i] == expected[i]);
}
emit SomeEvent(a, b, c);
emit SomeData(data);
return (b, c);
}
function testRevert (string memory data) public {
(address a,,) = getMetadataWithoutCall();
// should evaluate to `true`
if (a != address(0)) {
revert(data);
}
}
}