-
Notifications
You must be signed in to change notification settings - Fork 4
/
BribeMod.sol
117 lines (91 loc) · 4.61 KB
/
BribeMod.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
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.24;
/// @title Ether Deck Mk2 Flash Mod
/// @author jtriley.eth
/// @notice a reasonably optimized bribe mod for Ether Deck Mk2
contract BribeMod {
mapping(bytes4 => address) internal dispatch;
address internal runner;
/// @notice returns the nonce of the runner
/// @dev directives:
/// 01. move nonce from storage to memory
/// 02. return nonce
/// @dev the nonce slot is defined as `keccak256("EtherDeckMk2.BribeMod.nonce") - 1`
/// @return nonce the nonce of the runner
function nonce() external view returns (uint256) {
assembly {
mstore(0x00, sload(0x35cc143ea48486ca62296c4e48389c5f5abbd342fc1b39ad2da3d145f4b0d6bb))
return(0x00, 0x20)
}
}
/// @notice bribes the block builder to run with zero gas value
/// @dev directives:
/// 01. check if caller is runner; cache as success
/// 02. copy payload to memory
/// 03. make external call to coinbase with bribe; compose success
/// 04. make external call to target with callvalue and payload; compose success
/// 05. copy returndata to memory
/// 06. if success, return with returndata
/// 07. else, revert with revertdata
/// @param target the call target address
/// @param payload the call payload
function bribeBuilder(address target, bytes calldata payload, uint256 bribe) external payable {
assembly {
let success := eq(caller(), sload(runner.slot))
calldatacopy(0x00, payload.offset, payload.length)
success := and(success, call(gas(), coinbase(), bribe, 0x00, 0x00, 0x00, 0x00))
success := and(success, call(gas(), target, callvalue(), 0x00, payload.length, 0x00, 0x00))
returndatacopy(0x00, 0x00, returndatasize())
if success { return(0x00, returndatasize()) }
revert(0x00, returndatasize())
}
}
/// @notice bribes the caller to run on behalf of the runner
/// @dev directives:
/// 01. copy sigdata to memory
/// 02. ecrecover; cache as success
/// 03. check if recovered address is runner; compose success
/// 04. copy payload to memory
/// 05. store target after payload in memory
/// 06. store callvalue after target in memory
/// 07. store bribe after callvalue in memory
/// 08. load nonce from storage; cache as nonce
/// 09. store nonce after payload, target, callvalue, and bribe in memory
/// 10. check if hash matches sigdata hash; compose success
/// 11. store incremented nonce in storage
/// 12. make external call to caller with bribe; compose success
/// 13. make external call to target with callvalue and payload; compose success
/// 14. copy returndata to memory
/// 15. if success, return with returndata
/// 16. else, revert with revertdata
/// @dev sighash is `keccak256(abi.encode(payload, target, callvalue, bribe, nonce))`
/// @dev the nonce slot is defined as `keccak256("EtherDeckMk2.BribeMod.nonce") - 1`
/// @param target the call target address
/// @param payload the call payload
/// @param sigdata the ecrecover signature data
function bribeCaller(
address target,
bytes calldata payload,
bytes calldata sigdata,
uint256 bribe
) external payable {
assembly {
calldatacopy(0x00, sigdata.offset, sigdata.length)
let success := staticcall(gas(), 0x01, 0x00, sigdata.length, 0x00, 0x20)
success := and(success, eq(mload(0x00), sload(runner.slot)))
calldatacopy(0x00, payload.offset, payload.length)
mstore(payload.length, target)
mstore(add(0x20, payload.length), callvalue())
mstore(add(0x40, payload.length), bribe)
let nonce := sload(0x35cc143ea48486ca62296c4e48389c5f5abbd342fc1b39ad2da3d145f4b0d6bb)
mstore(add(0x60, payload.length), nonce)
success := and(success, eq(keccak256(0x00, add(0x80, payload.length)), calldataload(sigdata.offset)))
sstore(0x35cc143ea48486ca62296c4e48389c5f5abbd342fc1b39ad2da3d145f4b0d6bb, add(nonce, 0x01))
success := and(success, call(gas(), caller(), bribe, 0x00, 0x00, 0x00, 0x00))
success := and(success, call(gas(), target, callvalue(), 0x00, payload.length, 0x00, 0x00))
returndatacopy(0x00, 0x00, returndatasize())
if success { return(0x00, returndatasize()) }
revert(0x00, returndatasize())
}
}
}