Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Mevshare protocol #8

Merged
merged 6 commits into from
Jan 16, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,27 @@ 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);
}
}
```
78 changes: 78 additions & 0 deletions src/protocols/MevShare.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// 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 {
string version;
uint64 inclusionBlock;
bytes[] bodies;
bool[] canRevert;
uint8[] refundPercents;
}

function encodeBundle(Bundle memory bundle) internal pure returns (bytes 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":[{');

// -> 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, "]}");
return body;
}

function sendBundle(string memory url, Bundle memory bundle) internal view {
Suave.HttpRequest memory request;
request.url = url;
request.headers = new string[](1);
request.headers[0] = "Content-Type:application/json";
request.body = encodeBundle(bundle);
// TODO: Add Flashbots signature
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's needed to add the FB signature? I think we can just add the private key as a param to this function, then it's basically copypasta from the ethers lib


Suave.doHTTPRequest(request);
}
}
28 changes: 28 additions & 0 deletions test/protocols/MevShare.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

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

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

bundle.bodies = new bytes[](1);
bundle.bodies[0] = abi.encode(1234);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just a nit but might change 1234 to 0x1234. I like to use hex values directly in cases like this where you'd want to see [where] the same number shows up in the test assertion


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

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

bytes memory res = MevShare.encodeBundle(bundle);
assertEq(
string(res),
'{"jsonrpc":"2.0","method":"mev_sendBundle","params":[{"inclusion":{"block":"0x1"},"body":[{"tx":"0x00000000000000000000000000000000000000000000000000000000000004d2","canRevert":true}],"validity":{"refund":[{"bodyIdx":0,"percent":10}]}'
);
}
}
Loading