Skip to content

Commit eab6b72

Browse files
committed
meta-txs: add solidity tests
1 parent d83a209 commit eab6b72

File tree

7 files changed

+151
-4
lines changed

7 files changed

+151
-4
lines changed

contracts/common/MemoryHelpers.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ library MemoryHelpers {
2828
}
2929

3030
// From https://github.com/Arachnid/solidity-stringutils/blob/master/src/strings.sol
31-
function memcpy(uint256 dest, uint256 src, uint256 len) private pure {
31+
function memcpy(uint256 dest, uint256 src, uint256 len) internal pure {
3232
// Copy word-length chunks while possible
3333
for(; len >= 32; len -= 32) {
3434
assembly {

contracts/relayer/RelayedAragonApp.sol

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,15 @@ contract RelayedAragonApp is AragonApp {
1515
}
1616

1717
function _decodeSigner() internal returns (address signer) {
18-
bytes memory calldata = msg.data;
19-
assembly { signer := mload(add(calldata, calldatasize)) }
18+
// Note that calldatasize includes one word more than the original calldata array, due to the address of the
19+
// that is being appended at the end of it. Thus, we are loading the last word of the calldata array to fetch
20+
// the actual signed of the relayed call
21+
assembly {
22+
let ptr := mload(0x40)
23+
mstore(0x40, add(ptr, 0x20))
24+
calldatacopy(ptr, sub(calldatasize, 0x20), 0x20)
25+
signer := mload(ptr)
26+
}
2027
}
2128

2229
function _relayer() internal returns (IRelayer) {

contracts/relayer/Relayer.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ contract Relayer is IRelayer, AragonApp, DepositableStorage {
8989
return keccak256(abi.encodePacked(keccak256(calldata), nonce));
9090
}
9191

92-
function relayCall(address from, address to, bytes calldata) private {
92+
function relayCall(address from, address to, bytes calldata) internal {
9393
bytes memory encodedSignerCalldata = calldata.append(from);
9494
assembly {
9595
let success := call(gas, to, 0, add(encodedSignerCalldata, 0x20), mload(encodedSignerCalldata), 0, 0)
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
pragma solidity 0.4.24;
2+
3+
import "../helpers/Assert.sol";
4+
import "../../common/MemoryHelpers.sol";
5+
6+
7+
contract TestMemoryHelpers {
8+
using MemoryHelpers for bytes;
9+
10+
uint256 constant internal FIRST = uint256(10);
11+
uint256 constant internal SECOND = uint256(1);
12+
uint256 constant internal THIRD = uint256(15);
13+
14+
function testBytesArrayCopy() public {
15+
bytes memory blob = _initializeArbitraryBytesArray();
16+
uint256 blobSize = blob.length;
17+
bytes memory copy = new bytes(blobSize);
18+
uint256 input;
19+
uint256 output;
20+
assembly {
21+
input := add(blob, 0x20)
22+
output := add(copy, 0x20)
23+
}
24+
MemoryHelpers.memcpy(output, input, blobSize);
25+
26+
Assert.equal(blob.length, copy.length, "should have correct length");
27+
28+
uint256 firstWord = _assertEqualMemoryWord(blob, copy, 0);
29+
Assert.equal(firstWord, FIRST, "first value should match");
30+
31+
uint256 secondWord = _assertEqualMemoryWord(blob, copy, 1);
32+
Assert.equal(secondWord, SECOND, "second value should match");
33+
34+
uint256 thirdWord = _assertEqualMemoryWord(blob, copy, 2);
35+
Assert.equal(thirdWord, THIRD, "third value should match");
36+
}
37+
38+
function testAppendAddressToBytesArray() public {
39+
bytes memory blob = _initializeArbitraryBytesArray();
40+
address addr = address(0x000000000000000000000000000000000000dEaD);
41+
bytes memory result = blob.append(addr);
42+
43+
Assert.equal(blob.length + 32, result.length, "should have correct length");
44+
45+
uint256 firstWord = _assertEqualMemoryWord(blob, result, 0);
46+
Assert.equal(firstWord, FIRST, "first value should match");
47+
48+
uint256 secondWord = _assertEqualMemoryWord(blob, result, 1);
49+
Assert.equal(secondWord, SECOND, "second value should match");
50+
51+
uint256 thirdWord = _assertEqualMemoryWord(blob, result, 2);
52+
Assert.equal(thirdWord, THIRD, "third value should match");
53+
54+
bytes32 storedAddress;
55+
assembly { storedAddress := mload(add(result, 0x80))}
56+
Assert.equal(storedAddress, bytes32(0x000000000000000000000000000000000000000000000000000000000000dEaD), "appended address should match");
57+
}
58+
59+
function _assertEqualMemoryWord(bytes _actual, bytes _expected, uint256 _index) private returns (uint256) {
60+
uint256 actualValue;
61+
uint256 expectedValue;
62+
uint256 pos = _index * 32;
63+
assembly {
64+
actualValue := mload(add(add(_actual, 0x20), pos))
65+
expectedValue := mload(add(add(_expected, 0x20), pos))
66+
}
67+
Assert.equal(actualValue, expectedValue, "memory values should match");
68+
return expectedValue;
69+
}
70+
71+
function _initializeArbitraryBytesArray() private pure returns (bytes memory) {
72+
bytes memory blob = new bytes(96);
73+
74+
uint256 first = FIRST;
75+
uint256 second = SECOND;
76+
uint256 third = THIRD;
77+
assembly {
78+
mstore(add(blob, 0x20), first)
79+
mstore(add(blob, 0x40), second)
80+
mstore(add(blob, 0x60), third)
81+
}
82+
83+
return blob;
84+
}
85+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
pragma solidity 0.4.24;
2+
3+
import "../helpers/Assert.sol";
4+
import "../../relayer/Relayer.sol";
5+
import "../../common/MemoryHelpers.sol";
6+
7+
8+
contract RelayedAppTest is RelayedAragonApp {
9+
function callme(uint8 x, bytes32 y, string z) public {
10+
bytes memory calldata = msg.data;
11+
// 4 32 32 32 32 32 32
12+
// [sig][uint8][bytes32][string starting offset][string size][string word][signer]
13+
Assert.equal(calldata.length, 4 + 32 * 6, "should have correct length");
14+
15+
_assertCalldataWord(0x04, bytes32(0x000000000000000000000000000000000000000000000000000000000000000f));
16+
_assertCalldataWord(0x24, bytes32(0x0000000000000000000000000000000000000000000000000000000000000f00));
17+
_assertCalldataWord(0x44, bytes32(0x0000000000000000000000000000000000000000000000000000000000000060));
18+
_assertCalldataWord(0x64, bytes32(0x0000000000000000000000000000000000000000000000000000000000000007));
19+
_assertCalldataWord(0x84, bytes32(0x72656c6179656400000000000000000000000000000000000000000000000000));
20+
_assertCalldataWord(0xa4, bytes32(TestRelayerCalldata(msg.sender).signer()));
21+
}
22+
23+
function _assertCalldataWord(uint256 _pos, bytes32 _expectedValue) private {
24+
bytes32 actualValue;
25+
assembly {
26+
let ptr := mload(0x40)
27+
mstore(0x40, add(ptr, 0x20))
28+
calldatacopy(ptr, _pos, 0x20)
29+
actualValue := mload(ptr)
30+
}
31+
Assert.equal(actualValue, _expectedValue, "calldata values should match");
32+
}
33+
}
34+
35+
contract TestRelayerCalldata is Relayer {
36+
RelayedAppTest public appTest;
37+
38+
address public signer;
39+
40+
constructor () public {
41+
appTest = new RelayedAppTest();
42+
}
43+
44+
function testSignerEncodedCalls() public {
45+
signer = msg.sender;
46+
bytes memory calldata = abi.encodeWithSelector(appTest.callme.selector, uint8(15), bytes32(0xf00), "relayed");
47+
relayCall(signer, address(appTest), calldata);
48+
}
49+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
const runSolidityTest = require('../../helpers/runSolidityTest')
2+
3+
runSolidityTest('TestMemoryHelpers')
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
const runSolidityTest = require('../../helpers/runSolidityTest')
2+
3+
runSolidityTest('TestRelayerCalldata')

0 commit comments

Comments
 (0)