@@ -92,6 +92,39 @@ abstract contract MultisigBase is Simulator {
92
92
});
93
93
}
94
94
95
+ function _encodeCall (IGnosisSafe _safe , bytes memory _data , bytes memory _signatures ) internal pure returns (bytes memory ) {
96
+ return abi.encodeCall (
97
+ _safe.execTransaction,
98
+ (
99
+ address (multicall),
100
+ 0 ,
101
+ _data,
102
+ Enum.Operation.DelegateCall,
103
+ 0 ,
104
+ 0 ,
105
+ 0 ,
106
+ address (0 ),
107
+ payable (address (0 )),
108
+ _signatures
109
+ )
110
+ );
111
+ }
112
+
113
+ function _execTransaction (IGnosisSafe _safe , bytes memory _data , bytes memory _signatures ) internal returns (bool ) {
114
+ return _safe.execTransaction ({
115
+ to: address (multicall),
116
+ value: 0 ,
117
+ data: _data,
118
+ operation: Enum.Operation.DelegateCall,
119
+ safeTxGas: 0 ,
120
+ baseGas: 0 ,
121
+ gasPrice: 0 ,
122
+ gasToken: address (0 ),
123
+ refundReceiver: payable (address (0 )),
124
+ signatures: _signatures
125
+ });
126
+ }
127
+
95
128
function _executeTransaction (address _safe , IMulticall3.Call3[] memory _calls , bytes memory _signatures )
96
129
internal
97
130
returns (Vm.AccountAccess[] memory , SimulationPayload memory )
@@ -101,39 +134,15 @@ abstract contract MultisigBase is Simulator {
101
134
bytes32 hash = _getTransactionHash (_safe, data);
102
135
_signatures = prepareSignatures (_safe, hash, _signatures);
103
136
137
+ bytes memory simData = _encodeCall (safe, data, _signatures);
104
138
logSimulationLink ({
105
139
_to: _safe,
106
140
_from: msg .sender ,
107
- _data: abi.encodeCall (
108
- safe.execTransaction,
109
- (
110
- address (multicall),
111
- 0 ,
112
- data,
113
- Enum.Operation.DelegateCall,
114
- 0 ,
115
- 0 ,
116
- 0 ,
117
- address (0 ),
118
- payable (address (0 )),
119
- _signatures
120
- )
121
- )
141
+ _data: simData
122
142
});
123
143
124
144
vm.startStateDiffRecording ();
125
- bool success = safe.execTransaction ({
126
- to: address (multicall),
127
- value: 0 ,
128
- data: data,
129
- operation: Enum.Operation.DelegateCall,
130
- safeTxGas: 0 ,
131
- baseGas: 0 ,
132
- gasPrice: 0 ,
133
- gasToken: address (0 ),
134
- refundReceiver: payable (address (0 )),
135
- signatures: _signatures
136
- });
145
+ bool success = _execTransaction (safe, data, _signatures);
137
146
Vm.AccountAccess[] memory accesses = vm.stopAndReturnStateDiff ();
138
147
require (success, "MultisigBase::_executeTransaction: Transaction failed " );
139
148
require (accesses.length > 0 , "MultisigBase::_executeTransaction: No state changes " );
@@ -143,18 +152,7 @@ abstract contract MultisigBase is Simulator {
143
152
SimulationPayload memory simPayload = SimulationPayload ({
144
153
from: msg .sender ,
145
154
to: address (safe),
146
- data: abi.encodeCall (safe.execTransaction, (
147
- address (multicall),
148
- 0 ,
149
- data,
150
- Enum.Operation.DelegateCall,
151
- 0 ,
152
- 0 ,
153
- 0 ,
154
- address (0 ),
155
- payable (address (0 )),
156
- _signatures
157
- )),
155
+ data: simData,
158
156
stateOverrides: new SimulationStateOverride [](0 )
159
157
});
160
158
return (accesses, simPayload);
@@ -241,15 +239,7 @@ abstract contract MultisigBase is Simulator {
241
239
uint256 j;
242
240
for (uint256 i; i < count; i++ ) {
243
241
(v, r, s) = signatureSplit (_signatures, i);
244
- address owner;
245
- if (v <= 1 ) {
246
- owner = address (uint160 (uint256 (r)));
247
- } else if (v > 30 ) {
248
- owner =
249
- ecrecover (keccak256 (abi.encodePacked ("\x19Ethereum Signed Message:\n32 " , dataHash)), v - 4 , r, s);
250
- } else {
251
- owner = ecrecover (dataHash, v, r, s);
252
- }
242
+ address owner = extractOwner (dataHash, r, s, v);
253
243
254
244
// skip duplicate owners
255
245
uint256 k;
@@ -281,13 +271,28 @@ abstract contract MultisigBase is Simulator {
281
271
282
272
// append the non-static part of the signatures (can contain EIP-1271 signatures if contracts are signers)
283
273
// if there were any duplicates detected above, they will be safely ignored by Safe's checkNSignatures method
284
- if (_signatures.length > sorted.length ) {
285
- sorted = bytes .concat (sorted, Bytes.slice (_signatures, sorted.length , _signatures.length - sorted.length ));
286
- }
274
+ sorted = appendRemainingBytes (sorted, _signatures);
287
275
288
276
return sorted;
289
277
}
290
278
279
+ function appendRemainingBytes (bytes memory a1 , bytes memory a2 ) internal pure returns (bytes memory ) {
280
+ if (a2.length > a1.length ) {
281
+ a1 = bytes .concat (a1, Bytes.slice (a2, a1.length , a2.length - a1.length ));
282
+ }
283
+ return a1;
284
+ }
285
+
286
+ function extractOwner (bytes32 dataHash , bytes32 r , bytes32 s , uint8 v ) internal pure returns (address ) {
287
+ if (v <= 1 ) {
288
+ return address (uint160 (uint256 (r)));
289
+ }
290
+ if (v > 30 ) {
291
+ return ecrecover (keccak256 (abi.encodePacked ("\x19Ethereum Signed Message:\n32 " , dataHash)), v - 4 , r, s);
292
+ }
293
+ return ecrecover (dataHash, v, r, s);
294
+ }
295
+
291
296
// see https://github.com/safe-global/safe-contracts/blob/1ed486bb148fe40c26be58d1b517cec163980027/contracts/common/SignatureDecoder.sol
292
297
function signatureSplit (bytes memory signatures , uint256 pos )
293
298
internal
0 commit comments