-
Notifications
You must be signed in to change notification settings - Fork 911
/
GnosisSafePersonalEdition.sol
156 lines (144 loc) · 6.76 KB
/
GnosisSafePersonalEdition.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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
pragma solidity 0.4.24;
import "./interfaces/ERC20Token.sol";
import "./GnosisSafe.sol";
import "./MasterCopy.sol";
/// @title Gnosis Safe Personal Edition - A multisignature wallet with support for confirmations using signed messages based on ERC191.
/// @author Stefan George - <stefan@gnosis.pm>
/// @author Richard Meissner - <richard@gnosis.pm>
/// @author Ricardo Guilherme Schmidt - (Status Research & Development GmbH) - Gas Token Payment
contract GnosisSafePersonalEdition is MasterCopy, GnosisSafe {
string public constant NAME = "Gnosis Safe Personal Edition";
string public constant VERSION = "0.0.1";
uint256 internal constant BASE_TX_GAS_COSTS = 21000;
uint256 internal constant PAYMENT_GAS_COSTS = 11000;
event ExecutionFailed();
uint256 public nonce;
/// @dev Allows to execute a Safe transaction confirmed by required number of owners.
/// @param to Destination address of Safe transaction.
/// @param value Ether value of Safe transaction.
/// @param data Data payload of Safe transaction.
/// @param operation Operation type of Safe transaction.
/// @param safeTxGas Gas that should be used for the Safe transaction.
/// @param dataGas Gas costs for data used to trigger the safe transaction.
/// @param gasPrice Gas price that should be used for the payment calculation.
/// @param gasToken Token address (or 0 if ETH) that is used for the payment.
/// @param v Array of signature V values sorted by owner addresses.
/// @param r Array of signature R values sorted by owner addresses.
/// @param s Array of signature S values sorted by owner addresses.
function execAndPayTransaction(
address to,
uint256 value,
bytes data,
Enum.Operation operation,
uint256 safeTxGas,
uint256 dataGas,
uint256 gasPrice,
address gasToken,
uint8[] v,
bytes32[] r,
bytes32[] s
)
public
{
uint256 startGas = gasleft();
checkHash(getTransactionHash(to, value, data, operation, safeTxGas, dataGas, gasPrice, gasToken, nonce), v, r, s);
// Increase nonce and execute transaction.
nonce++;
require(gasleft() - PAYMENT_GAS_COSTS >= safeTxGas, "Not enough gas to execute safe transaction");
if (!execute(to, value, data, operation, safeTxGas)) {
emit ExecutionFailed();
}
// We transfer the calculated tx costs to the tx.origin to avoid sending it to intermediate contracts that have made calls
if (gasPrice > 0) {
uint256 gasCosts = totalGasCosts(startGas - gasleft(), dataGas);
uint256 amount = gasCosts * gasPrice;
if (gasToken == address(0)) {
// solium-disable-next-line security/no-tx-origin
tx.origin.transfer(amount);
} else {
// solium-disable-next-line security/no-tx-origin
require(ERC20Token(gasToken).transfer(tx.origin, amount), "Could not pay gas costs with token");
}
}
}
/// @dev Calculates the total gas costs for a safe transaction with the gas costs for the execution of the transaction.
/// @param executionGas Gas costs for the execution of the safe transaction.
/// @param dataGas Gas costs for data used to trigger the safe transaction.
/// @return Total gas costs for the execution (this includes gas costs for the payment to tx.origin, base transaction and payload data).
function totalGasCosts(uint256 executionGas, uint256 dataGas)
public
pure
returns (uint256)
{
return executionGas + dataGas + PAYMENT_GAS_COSTS + BASE_TX_GAS_COSTS;
}
/// @dev Allows to estimate a Safe transaction.
/// This method is only meant for estimation purpose, therfore two different protection mechanism against execution in a transaction have been made:
/// 1.) The method can only be called from the safe itself
/// 2.) The response is returned with a revert
/// When estimating set `from` to the address of the safe.
/// Since the `estimateGas` function includes refunds, call this method to get an estimated of the costs that are deducted from the safe with `execAndPayTransaction`
/// @param to Destination address of Safe transaction.
/// @param value Ether value of Safe transaction.
/// @param data Data payload of Safe transaction.
/// @param operation Operation type of Safe transaction.
/// @return Estimate without refunds and overhead fees (base transaction and payload data gas costs).
function requiredTxGas(address to, uint256 value, bytes data, Enum.Operation operation)
public
authorized
returns (uint256)
{
uint256 startGas = gasleft();
// We don't provide an error message here, as we use it to return the estimate
require(execute(to, value, data, operation, gasleft()));
uint256 requiredGas = startGas - gasleft();
// Convert response to string and return via error message
revert(string(abi.encodePacked(requiredGas)));
}
function checkHash(bytes32 hash, uint8[] v, bytes32[] r, bytes32[] s)
internal
view
{
// There cannot be an owner with address 0.
address lastOwner = address(0);
address currentOwner;
uint256 i;
// Validate threshold is reached.
for (i = 0; i < threshold; i++) {
currentOwner = ecrecover(hash, v[i], r[i], s[i]);
require(owners[currentOwner] != 0, "Signature not provided by owner");
require(currentOwner > lastOwner, "Signatures are not ordered by owner address");
lastOwner = currentOwner;
}
}
/// @dev Returns hash to be signed by owners.
/// @param to Destination address.
/// @param value Ether value.
/// @param data Data payload.
/// @param operation Operation type.
/// @param safeTxGas Fas that should be used for the safe transaction.
/// @param dataGas Gas costs for data used to trigger the safe transaction.
/// @param gasPrice Maximum gas price that should be used for this transaction.
/// @param gasToken Token address (or 0 if ETH) that is used for the payment.
/// @param _nonce Transaction nonce.
/// @return Transaction hash.
function getTransactionHash(
address to,
uint256 value,
bytes data,
Enum.Operation operation,
uint256 safeTxGas,
uint256 dataGas,
uint256 gasPrice,
address gasToken,
uint256 _nonce
)
public
view
returns (bytes32)
{
return keccak256(
abi.encodePacked(byte(0x19), byte(0), this, to, value, data, operation, safeTxGas, dataGas, gasPrice, gasToken, _nonce)
);
}
}