Skip to content

Commit deb5a48

Browse files
committed
Attempt to fix stack too deep
1 parent 6cb3d4f commit deb5a48

2 files changed

Lines changed: 128 additions & 60 deletions

File tree

src/ISafeSmartAccount.sol

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.13;
3+
4+
import {Enum} from "../lib/safe-smart-account/contracts/common/Enum.sol";
5+
6+
interface ISafeSmartAccount {
7+
function nonce() external view returns (uint256);
8+
9+
function getTransactionHash(
10+
address to,
11+
uint256 value,
12+
bytes calldata data,
13+
Enum.Operation operation,
14+
uint256 safeTxGas,
15+
uint256 baseGas,
16+
uint256 gasPrice,
17+
address gasToken,
18+
address refundReceiver,
19+
uint256 _nonce
20+
) external view returns (bytes32);
21+
22+
function execTransaction(
23+
address to,
24+
uint256 value,
25+
bytes calldata data,
26+
Enum.Operation operation,
27+
uint256 safeTxGas,
28+
uint256 baseGas,
29+
uint256 gasPrice,
30+
address gasToken,
31+
address payable refundReceiver,
32+
bytes memory signatures
33+
) external payable returns (bool success);
34+
}

src/Safe.sol

Lines changed: 94 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,18 @@ pragma solidity ^0.8.13;
33

44
import {Vm} from "forge-std/Vm.sol";
55
import {HTTP} from "../lib/solidity-http/src/HTTP.sol";
6-
import {Safe as SafeSmartAccount} from "../lib/safe-smart-account/contracts/Safe.sol";
76
import {MultiSendCallOnly} from "../lib/safe-smart-account/contracts/libraries/MultiSendCallOnly.sol";
87
import {Enum} from "../lib/safe-smart-account/contracts/common/Enum.sol";
8+
import {ISafeSmartAccount} from "./ISafeSmartAccount.sol";
99

1010
library Safe {
1111
using HTTP for *;
1212

1313
Vm constant vm = Vm(address(bytes20(uint160(uint256(keccak256("hevm cheat code"))))));
1414

15+
// https://github.com/safe-global/safe-smart-account/blob/release/v1.4.1/contracts/libraries/SafeStorage.sol
16+
bytes32 constant SAFE_THRESHOLD_STORAGE_SLOT = bytes32(uint256(4));
17+
1518
error ApiKitUrlNotFound(uint256 chainId);
1619
error MultiSendCallOnlyNotFound(uint256 chainId);
1720
error ArrayLengthsMismatch(uint256 a, uint256 b);
@@ -34,6 +37,16 @@ library Safe {
3437
Instance[] instances;
3538
}
3639

40+
struct ExecTransactionParams {
41+
address to;
42+
uint256 value;
43+
bytes data;
44+
Enum.Operation operation;
45+
address sender;
46+
bytes signature;
47+
uint256 nonce;
48+
}
49+
3750
function initialize(Client storage self, address safe) internal returns (Client storage) {
3851
self.instances.push();
3952
Instance storage i = self.instances[self.instances.length - 1];
@@ -88,7 +101,7 @@ library Safe {
88101
}
89102

90103
function getNonce(Client storage self) internal view returns (uint256) {
91-
return SafeSmartAccount(payable(instance(self).safe)).nonce();
104+
return ISafeSmartAccount(instance(self).safe).nonce();
92105
}
93106

94107
function getSafeTxHash(
@@ -99,35 +112,28 @@ library Safe {
99112
Enum.Operation operation,
100113
uint256 nonce
101114
) internal view returns (bytes32) {
102-
return SafeSmartAccount(payable(instance(self).safe)).getTransactionHash(
115+
return ISafeSmartAccount(instance(self).safe).getTransactionHash(
103116
to, value, data, operation, 0, 0, 0, address(0), address(0), nonce
104117
);
105118
}
106119

107120
// https://github.com/safe-global/safe-core-sdk/blob/r60/packages/api-kit/src/SafeApiKit.ts#L574
108-
function proposeTransaction(
109-
Client storage self,
110-
address to,
111-
uint256 value,
112-
bytes memory data,
113-
Enum.Operation operation,
114-
address sender,
115-
bytes memory signature,
116-
uint256 nonce
117-
) internal {
118-
instance(self).requestBody = vm.serializeAddress(".proposeTransaction", "to", to);
119-
instance(self).requestBody = vm.serializeUint(".proposeTransaction", "value", value);
120-
instance(self).requestBody = vm.serializeBytes(".proposeTransaction", "data", data);
121-
instance(self).requestBody = vm.serializeUint(".proposeTransaction", "operation", uint8(operation));
121+
function proposeTransaction(Client storage self, ExecTransactionParams memory params) internal {
122+
instance(self).requestBody = vm.serializeAddress(".proposeTransaction", "to", params.to);
123+
instance(self).requestBody = vm.serializeUint(".proposeTransaction", "value", params.value);
124+
instance(self).requestBody = vm.serializeBytes(".proposeTransaction", "data", params.data);
125+
instance(self).requestBody = vm.serializeUint(".proposeTransaction", "operation", uint8(params.operation));
122126
instance(self).requestBody = vm.serializeBytes32(
123-
".proposeTransaction", "contractTransactionHash", getSafeTxHash(self, to, value, data, operation, nonce)
127+
".proposeTransaction",
128+
"contractTransactionHash",
129+
getSafeTxHash(self, params.to, params.value, params.data, params.operation, params.nonce)
124130
);
125-
instance(self).requestBody = vm.serializeAddress(".proposeTransaction", "sender", sender);
126-
instance(self).requestBody = vm.serializeBytes(".proposeTransaction", "signature", signature);
131+
instance(self).requestBody = vm.serializeAddress(".proposeTransaction", "sender", params.sender);
132+
instance(self).requestBody = vm.serializeBytes(".proposeTransaction", "signature", params.signature);
127133
instance(self).requestBody = vm.serializeUint(".proposeTransaction", "safeTxGas", 0);
128134
instance(self).requestBody = vm.serializeUint(".proposeTransaction", "baseGas", 0);
129135
instance(self).requestBody = vm.serializeUint(".proposeTransaction", "gasPrice", 0);
130-
instance(self).requestBody = vm.serializeUint(".proposeTransaction", "nonce", nonce);
136+
instance(self).requestBody = vm.serializeUint(".proposeTransaction", "nonce", params.nonce);
131137

132138
instance(self).http.instance().POST(
133139
string.concat(
@@ -139,41 +145,36 @@ library Safe {
139145
).withBody(instance(self).requestBody).request();
140146
}
141147

142-
function proposeTransaction(
143-
Client storage self,
144-
address to,
145-
bytes memory data,
146-
Enum.Operation operation,
147-
address sender,
148-
bytes memory signature
149-
) internal {
150-
return proposeTransaction(self, to, 0, data, operation, sender, signature, getNonce(self));
151-
}
152-
153148
function proposeTransaction(Client storage self, address to, bytes memory data, address sender) internal {
154-
return proposeTransaction(self, to, data, sender, string(""));
149+
ExecTransactionParams memory params = ExecTransactionParams({
150+
to: to,
151+
value: 0,
152+
data: data,
153+
operation: Enum.Operation.Call,
154+
sender: sender,
155+
signature: sign(self, to, data, Enum.Operation.Call, sender, string("")),
156+
nonce: getNonce(self)
157+
});
158+
return proposeTransaction(self, params);
155159
}
156160

157161
function proposeTransaction(
158162
Client storage self,
159163
address to,
160164
bytes memory data,
161-
Enum.Operation operation,
162165
address sender,
163166
string memory derivationPath
164167
) internal {
165-
bytes memory signature = sign(self, to, data, operation, sender, derivationPath);
166-
return proposeTransaction(self, to, 0, data, operation, sender, signature, getNonce(self));
167-
}
168-
169-
function proposeTransaction(
170-
Client storage self,
171-
address to,
172-
bytes memory data,
173-
address sender,
174-
string memory derivationPath
175-
) internal {
176-
return proposeTransaction(self, to, data, Enum.Operation.Call, sender, derivationPath);
168+
ExecTransactionParams memory params = ExecTransactionParams({
169+
to: to,
170+
value: 0,
171+
data: data,
172+
operation: Enum.Operation.Call,
173+
sender: sender,
174+
signature: sign(self, to, data, Enum.Operation.Call, sender, derivationPath),
175+
nonce: getNonce(self)
176+
});
177+
return proposeTransaction(self, params);
177178
}
178179

179180
function getProposeTransactionsTargetAndData(Client storage self, address[] memory targets, bytes[] memory datas)
@@ -206,14 +207,32 @@ library Safe {
206207
) internal {
207208
(address to, bytes memory data) = getProposeTransactionsTargetAndData(self, targets, datas);
208209
// using DelegateCall to preserve msg.sender across sub-calls
209-
return proposeTransaction(self, to, data, Enum.Operation.DelegateCall, sender, derivationPath);
210+
ExecTransactionParams memory params = ExecTransactionParams({
211+
to: to,
212+
value: 0,
213+
data: data,
214+
operation: Enum.Operation.DelegateCall,
215+
sender: sender,
216+
signature: sign(self, to, data, Enum.Operation.DelegateCall, sender, derivationPath),
217+
nonce: getNonce(self)
218+
});
219+
return proposeTransaction(self, params);
210220
}
211221

212222
function getExecTransactionData(Client storage self, address to, bytes memory data, address sender)
213223
internal
214224
returns (bytes memory)
215225
{
216-
return getExecTransactionData(self, to, data, sender, string(""));
226+
ExecTransactionParams memory params = ExecTransactionParams({
227+
to: to,
228+
value: 0,
229+
data: data,
230+
operation: Enum.Operation.Call,
231+
sender: sender,
232+
signature: sign(self, to, data, Enum.Operation.Call, sender, string("")),
233+
nonce: getNonce(self)
234+
});
235+
return getExecTransactionData(self, params);
217236
}
218237

219238
function getExecTransactionData(
@@ -223,7 +242,16 @@ library Safe {
223242
address sender,
224243
string memory derivationPath
225244
) internal returns (bytes memory) {
226-
return getExecTransactionData(self, to, data, Enum.Operation.Call, sender, derivationPath);
245+
ExecTransactionParams memory params = ExecTransactionParams({
246+
to: to,
247+
value: 0,
248+
data: data,
249+
operation: Enum.Operation.Call,
250+
sender: sender,
251+
signature: sign(self, to, data, Enum.Operation.Call, sender, derivationPath),
252+
nonce: getNonce(self)
253+
});
254+
return getExecTransactionData(self, params);
227255
}
228256

229257
function getExecTransactionsData(
@@ -244,20 +272,26 @@ library Safe {
244272
) internal returns (bytes memory) {
245273
(address to, bytes memory data) = getProposeTransactionsTargetAndData(self, targets, datas);
246274
// using DelegateCall to preserve msg.sender across sub-calls
247-
return getExecTransactionData(self, to, data, Enum.Operation.DelegateCall, sender, derivationPath);
275+
ExecTransactionParams memory params = ExecTransactionParams({
276+
to: to,
277+
value: 0,
278+
data: data,
279+
operation: Enum.Operation.DelegateCall,
280+
sender: sender,
281+
signature: sign(self, to, data, Enum.Operation.DelegateCall, sender, derivationPath),
282+
nonce: getNonce(self)
283+
});
284+
return getExecTransactionData(self, params);
248285
}
249286

250-
function getExecTransactionData(
251-
Client storage self,
252-
address to,
253-
bytes memory data,
254-
Enum.Operation operation,
255-
address sender,
256-
string memory derivationPath
257-
) internal returns (bytes memory) {
258-
bytes memory signature = sign(self, to, data, operation, sender, derivationPath);
287+
function getExecTransactionData(Client storage, ExecTransactionParams memory params)
288+
internal
289+
pure
290+
returns (bytes memory)
291+
{
259292
return abi.encodeCall(
260-
SafeSmartAccount.execTransaction, (to, 0, data, operation, 0, 0, 0, address(0), payable(0), signature)
293+
ISafeSmartAccount.execTransaction,
294+
(params.to, 0, params.data, params.operation, 0, 0, 0, address(0), payable(0), params.signature)
261295
);
262296
}
263297

0 commit comments

Comments
 (0)