Skip to content

Commit

Permalink
Add eth_sendBundle protocol
Browse files Browse the repository at this point in the history
  • Loading branch information
ferranbt committed Jan 16, 2024
1 parent 667d6eb commit 46bafe1
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 3 deletions.
23 changes: 20 additions & 3 deletions src/protocols/Bundle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ pragma solidity ^0.8.13;

import "../suavelib/Suave.sol";
import "solady/src/utils/LibString.sol";
import "solady/src/utils/JSONParserLib.sol";

// https://docs.flashbots.net/flashbots-auction/advanced/rpc-endpoint#eth_sendbundle
library Bundle {
Expand All @@ -15,14 +14,32 @@ library Bundle {
bytes[] txns;
}

function sendBundle(string memory url, Bundle memory bundle) internal view {
function sendBundle(string memory url, BundleObj memory bundle) internal view {
Suave.HttpRequest memory request = encodeBundle(bundle);
request.url = url;
Suave.doHTTPRequest(request);
}

function encodeBundle(BundleObj memory args) internal pure returns (Suave.HttpRequest memory) {
bytes memory params = abi.encodePacked("{", '"txs": [', txn, "],", '"blockNumber": "', args.blockNumber, '"}');
require(args.txns.length > 0, "Bundle: no txns");

bytes memory params = abi.encodePacked('{"blockNumber": "', LibString.toString(args.blockNumber), '", "txs": [');
for (uint256 i = 0; i < args.txns.length; i++) {
params = abi.encodePacked(params, '"', LibString.toHexString(args.txns[i]), '"');
if (i < args.txns.length - 1) {
params = abi.encodePacked(params, ",");
} else {
params = abi.encodePacked(params, "]");
}
}
if (args.minTimestamp > 0) {
params = abi.encodePacked(params, ', "minTimestamp": ', LibString.toString(args.minTimestamp));
}
if (args.maxTimestamp > 0) {
params = abi.encodePacked(params, ', "maxTimestamp": ', LibString.toString(args.maxTimestamp));
}
params = abi.encodePacked(params, "}");

bytes memory body =
abi.encodePacked('{"jsonrpc":"2.0","method":"eth_sendBundle","params":[', params, '],"id":1}');

Expand Down
40 changes: 40 additions & 0 deletions test/protocols/Bundle.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import "forge-std/Test.sol";
import "src/protocols/Bundle.sol";
import "src/suavelib/Suave.sol";

contract EthSendBundle is Test {
function testEthSendBundleEncode() public {
Bundle.BundleObj memory bundle;
bundle.blockNumber = 1;
bundle.txns = new bytes[](1);
bundle.txns[0] = hex"1234";

Suave.HttpRequest memory request = Bundle.encodeBundle(bundle);
assertEq(
string(request.body),
'{"jsonrpc":"2.0","method":"eth_sendBundle","params":[{"blockNumber": "1", "txs": ["0x1234"]}],"id":1}'
);
assertTrue(request.withFlashbotsSignature);

// encode with 'minTimestamp'
bundle.minTimestamp = 2;

Suave.HttpRequest memory request2 = Bundle.encodeBundle(bundle);
assertEq(
string(request2.body),
'{"jsonrpc":"2.0","method":"eth_sendBundle","params":[{"blockNumber": "1", "txs": ["0x1234"], "minTimestamp": 2}],"id":1}'
);

// encode with 'maxTimestamp'
bundle.maxTimestamp = 3;

Suave.HttpRequest memory request3 = Bundle.encodeBundle(bundle);
assertEq(
string(request3.body),
'{"jsonrpc":"2.0","method":"eth_sendBundle","params":[{"blockNumber": "1", "txs": ["0x1234"], "minTimestamp": 2, "maxTimestamp": 3}],"id":1}'
);
}
}

0 comments on commit 46bafe1

Please sign in to comment.