This repository has been archived by the owner on Apr 15, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 69
/
TxRelay.sol
107 lines (92 loc) · 4.15 KB
/
TxRelay.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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
pragma solidity 0.4.15;
// This contract is meant as a "singleton" forwarding contract.
// Eventually, it will be able to forward any transaction to
// Any contract that is built to accept it.
contract TxRelay {
// Note: This is a local nonce.
// Different from the nonce defined w/in protocol.
mapping(address => uint) nonce;
// This mapping specifies a whitelist of allowed senders for transactions.
// There can be one whitelist per ethereum account, which is the owner of that
// whitelist. Users can specify which whitelist they want to use when signing
// a transaction. They can use their own whitelist, a whitelist belonging
// to another account, or skip using a whitelist by specifying the zero address.
mapping(address => mapping(address => bool)) public whitelist;
/*
* @dev Relays meta transactions
* @param sigV, sigR, sigS ECDSA signature on some data to be forwarded
* @param destination Location the meta-tx should be forwarded to
* @param data The bytes necessary to call the function in the destination contract.
* Note: The first encoded argument in data must be address of the signer. This means
* that all functions called from this relay must take an address as the first parameter.
*/
function relayMetaTx(
uint8 sigV,
bytes32 sigR,
bytes32 sigS,
address destination,
bytes data,
address listOwner
) public {
// only allow senders from the whitelist specified by the user,
// 0x0 means no whitelist.
require(listOwner == 0x0 || whitelist[listOwner][msg.sender]);
address claimedSender = getAddress(data);
// use EIP 191
// 0x19 :: version :: relay :: whitelistOwner :: nonce :: destination :: data
bytes32 h = keccak256(byte(0x19), byte(0), this, listOwner, nonce[claimedSender], destination, data);
address addressFromSig = ecrecover(h, sigV, sigR, sigS);
require(claimedSender == addressFromSig);
nonce[claimedSender]++; //if we are going to do tx, update nonce
require(destination.call(data));
}
/*
* @dev Gets an address encoded as the first argument in transaction data
* @param b The byte array that should have an address as first argument
* @returns a The address retrieved from the array
(Optimization based on work by tjade273)
*/
function getAddress(bytes b) public constant returns (address a) {
if (b.length < 36) return address(0);
assembly {
let mask := 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
a := and(mask, mload(add(b, 36)))
// 36 is the offset of the first parameter of the data, if encoded properly.
// 32 bytes for the length of the bytes array, and 4 bytes for the function signature.
}
}
/*
* @dev Returns the local nonce of an account.
* @param add The address to return the nonce for.
* @return The specific-to-this-contract nonce of the address provided
*/
function getNonce(address add) public constant returns (uint) {
return nonce[add];
}
/*
* @dev Adds a number of addresses to a specific whitelist. Only
* the owner of a whitelist can add to it.
* @param sendersToUpdate the addresses to add to the whitelist
*/
function addToWhitelist(address[] sendersToUpdate) public {
updateWhitelist(sendersToUpdate, true);
}
/*
* @dev Removes a number of addresses from a specific whitelist. Only
* the owner of a whitelist can remove from it.
* @param sendersToUpdate the addresses to add to the whitelist
*/
function removeFromWhitelist(address[] sendersToUpdate) public {
updateWhitelist(sendersToUpdate, false);
}
/*
* @dev Internal logic to update a whitelist
* @param sendersToUpdate the addresses to add to the whitelist
* @param newStatus whether to add or remove addresses
*/
function updateWhitelist(address[] sendersToUpdate, bool newStatus) private {
for (uint i = 0; i < sendersToUpdate.length; i++) {
whitelist[msg.sender][sendersToUpdate[i]] = newStatus;
}
}
}