forked from toknapp/contracts
/
Forward.sol
82 lines (67 loc) · 2.13 KB
/
Forward.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
pragma solidity ^0.4.24;
contract Forward {
address private owner;
uint256 private nonce;
constructor(address _owner) public {
owner = _owner;
nonce = 0;
}
function forward(
uint8 v, bytes32 r, bytes32 s,
address target, uint256 value, bytes input
) public payable returns (bool) {
require(
ecrecover(signingData(target, value, input), v, r, s) == owner,
"invalid signature"
);
nonce += 1;
// TODO: handle output data? maybe annoying to do in solidity
return target.call.value(value)(input);
}
function signingData(
address target,
uint256 value,
bytes input
) public view returns (bytes32) {
bytes memory sd = new bytes(32+32+32+32+input.length);
uint sd_;
uint i_;
uint256 n = nonce;
address a = this;
assembly {
sd_ := add(sd, 32)
i_ := add(input, 32)
mstore(sd_, a)
sd_ := add(sd_, 32)
mstore(sd_, n)
sd_ := add(sd_, 32)
mstore(sd_, target)
sd_ := add(sd_, 32)
mstore(sd_, value)
sd_ := add(sd_, 32)
}
memcpy(sd_, i_, input.length);
return keccak256(sd);
}
// https://github.com/Arachnid/solidity-stringutils/blob/3c63f18245645ba600cae2191deba7221512f753/src/strings.sol#L45
function memcpy(uint dest, uint src, uint len) private pure {
// Copy word-length chunks while possible
for(; len >= 32; len -= 32) {
assembly {
mstore(dest, mload(src))
}
dest += 32;
src += 32;
}
// Copy remaining bytes
uint mask = 256 ** (32 - len) - 1;
assembly {
let srcpart := and(mload(src), not(mask))
let destpart := and(mload(dest), mask)
mstore(dest, or(destpart, srcpart))
}
}
function getNonce() public view returns (uint256) { return nonce; }
function getOwner() public view returns (address) { return owner; }
function() public payable { }
}