Skip to content

Commit

Permalink
Add Mevshare protocol (#8)
Browse files Browse the repository at this point in the history
* Add Mevshare protocol

* Update README.md

* Add flashbots signature

* Merge final version
  • Loading branch information
ferranbt authored Jan 16, 2024
1 parent 5cb15b5 commit f69be79
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 0 deletions.
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,30 @@ contract Example {
}
```

### protocols/MevShare.sol

Helper library to send bundle requests with the Mev-Share protocol.

#### Example usage

```solidity
import "suave-std/protocols/MevShare.sol";
contract Example {
function example() {
Transactions.Legacy memory legacyTxn0 = Transactions.Legacy({});
bytes memory rlp = Transactions.encodeRLP(legacyTxn0);
MevShare.Bundle memory bundle;
bundle.bodies = new bytes[](1);
bundle.bodies[0] = rlp;
// ...
MevShare.sendBundle(bundle);
}
}
```

## Forge integration

In order to use `forge`, you need to have a running `Suave` node and the `suave` binary in your path.
Expand Down
79 changes: 79 additions & 0 deletions src/protocols/MevShare.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.13;

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

// https://github.com/flashbots/mev-share/blob/main/specs/bundles/v0.1.md#json-rpc-request-scheme
library MevShare {
struct Bundle {
uint64 inclusionBlock;
bytes[] bodies;
bool[] canRevert;
uint8[] refundPercents;
}

function encodeBundle(Bundle memory bundle) internal pure returns (Suave.HttpRequest memory) {
require(bundle.bodies.length == bundle.canRevert.length, "MevShare: bodies and canRevert length mismatch");
bytes memory body = abi.encodePacked('{"jsonrpc":"2.0","method":"mev_sendBundle","params":[{"version":"v0.1",');

// -> inclusion
body =
abi.encodePacked(body, '"inclusion":{"block":"', LibString.toMinimalHexString(bundle.inclusionBlock), '"},');

// -> body
body = abi.encodePacked(body, '"body":[');

for (uint256 i = 0; i < bundle.bodies.length; i++) {
body = abi.encodePacked(
body,
'{"tx":"',
LibString.toHexString(bundle.bodies[i]),
'","canRevert":',
bundle.canRevert[i] ? "true" : "false",
"}"
);

if (i < bundle.bodies.length - 1) {
body = abi.encodePacked(body, ",");
}
}

body = abi.encodePacked(body, "],");

// -> validity
body = abi.encodePacked(body, '"validity":{"refund":[');

for (uint256 i = 0; i < bundle.refundPercents.length; i++) {
body = abi.encodePacked(
body,
'{"bodyIdx":',
LibString.toString(i),
',"percent":',
LibString.toString(bundle.refundPercents[i]),
"}"
);

if (i < bundle.refundPercents.length - 1) {
body = abi.encodePacked(body, ",");
}
}

body = abi.encodePacked(body, "]}");

Suave.HttpRequest memory request;
request.headers = new string[](1);
request.headers[0] = "Content-Type:application/json";
request.body = body;
request.withFlashbotsSignature = true;

return request;
}

function sendBundle(string memory url, Bundle memory bundle) internal view {
Suave.HttpRequest memory request = encodeBundle(bundle);
request.url = url;
Suave.doHTTPRequest(request);
}
}
29 changes: 29 additions & 0 deletions test/protocols/MevShare.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

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

contract MevShareTest is Test {
function testEncodeMevShare() public {
MevShare.Bundle memory bundle;
bundle.inclusionBlock = 1;

bundle.bodies = new bytes[](1);
bundle.bodies[0] = hex"1234";

bundle.canRevert = new bool[](1);
bundle.canRevert[0] = true;

bundle.refundPercents = new uint8[](1);
bundle.refundPercents[0] = 10;

Suave.HttpRequest memory request = MevShare.encodeBundle(bundle);
assertEq(
string(request.body),
'{"jsonrpc":"2.0","method":"mev_sendBundle","params":[{"version":"v0.1","inclusion":{"block":"0x1"},"body":[{"tx":"0x1234","canRevert":true}],"validity":{"refund":[{"bodyIdx":0,"percent":10}]}'
);
assertTrue(request.withFlashbotsSignature);
}
}

0 comments on commit f69be79

Please sign in to comment.