Skip to content

Commit ed86dda

Browse files
authored
Add ExecuteBatchSimulator for coinbase wallet simulations (as bytecode only deploy) (#724)
* Add ExecuteBatchSimulator for coinbase wallet simulations (as bytecode only deploy) * fix recieving eth * update debugger with call information
1 parent 5cc89d4 commit ed86dda

File tree

1 file changed

+92
-0
lines changed

1 file changed

+92
-0
lines changed
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.23;
3+
4+
contract EchoerContract {
5+
function balance(uint256 _value) external {}
6+
function call(address target, uint256 value, bytes memory data) external {}
7+
}
8+
9+
/**
10+
* @author iainnash
11+
* @notice This shim contract allows for better error reporting and catches for smart wallet multi-execution
12+
* This shim contract replaces the Coinbase wallet simulator and more explicitly throws errors with additional information and context around operations failing.
13+
* This is used for simulating execution success along with better error reporting and debugging for our users.
14+
*/
15+
contract ExecuteBatchSimulator {
16+
/// @notice Call has failed to execute.
17+
error CallExecuteFailure(address target, uint256 value, bytes data, bytes errorMessage);
18+
/// @notice Call does not have enough value.
19+
error CallHasNotEnoughValue(address target, uint256 value, bytes data, uint256 balance);
20+
/// @notice Call target has no code but data is being sent. 99% of the time this is incorrect.
21+
error CallExecuteTargetNoCodeButData(address target, uint256 value, bytes data);
22+
/// @notice Function call does not match any public selectors in this contract.
23+
error InvalidFunctionCall(uint256 value);
24+
25+
EchoerContract echoer;
26+
27+
/// @notice Represents a call to make.
28+
struct Call {
29+
/// @dev The address to call.
30+
address target;
31+
/// @dev The value to send when making the call.
32+
uint256 value;
33+
/// @dev The data of the call.
34+
bytes data;
35+
}
36+
37+
event ReceivedEth(address sender, uint256 value);
38+
event CallOp(address target, uint256 value, bytes data);
39+
40+
/// @notice Shims coinbase wallet's executeBatch function
41+
/// @param calls calls to execute
42+
function executeBatch(Call[] calldata calls) external payable {
43+
echoer = new EchoerContract();
44+
for (uint256 i = 0; i < calls.length; i++) {
45+
echoer.call(calls[i].target, calls[i].value, calls[i].data);
46+
}
47+
for (uint256 i = 0; i < calls.length; i++) {
48+
echoer.balance(address(this).balance);
49+
_call(calls[i].target, calls[i].value, calls[i].data);
50+
}
51+
}
52+
53+
/// @notice Shims coinbase wallet's execute function
54+
/// @param target target to execute
55+
/// @param value value to use to execute
56+
/// @param data calldata to execute
57+
function execute(address target, uint256 value, bytes calldata data) external payable {
58+
echoer = new EchoerContract();
59+
echoer.balance(address(this).balance);
60+
_call(target, value, data);
61+
}
62+
63+
/// @notice Internal underlying call function
64+
function _call(address target, uint256 value, bytes memory data) public {
65+
emit CallOp(target, value, data);
66+
echoer.call(target, value, data);
67+
68+
uint256 balance = address(this).balance;
69+
if (balance < value) {
70+
revert CallHasNotEnoughValue(target, value, data, balance);
71+
}
72+
73+
if (target.code.length == 0 && data.length > 0) {
74+
revert CallExecuteTargetNoCodeButData(target, value, data);
75+
}
76+
77+
(bool success, bytes memory result) = target.call{value: value}(data);
78+
if (!success) {
79+
revert CallExecuteFailure(target, value, data, result);
80+
}
81+
}
82+
83+
/// @notice Function handling for unknown calls to help more clearly debug
84+
fallback() external payable {
85+
revert InvalidFunctionCall(0);
86+
}
87+
88+
/// @notice Function handling for unknown calls to help more clearly debug
89+
receive() external payable {
90+
emit ReceivedEth(msg.sender, msg.value);
91+
}
92+
}

0 commit comments

Comments
 (0)