Skip to content

Commit

Permalink
feat:add README
Browse files Browse the repository at this point in the history
Signed-off-by: grapebaba <281165273@qq.com>
  • Loading branch information
GrapeBaBa committed Aug 31, 2023
1 parent 958782d commit 613d97b
Show file tree
Hide file tree
Showing 2 changed files with 342 additions and 0 deletions.
41 changes: 41 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Contribute to mev-share-java

## Create a fork

First, create a fork of the mev-share-java repo in your own account so that you can work with your own copy.

**To create a fork using the website**

1. Log in to your Github account.
1. Browse to the [mev-share-java repo](https://github.com/optimism-java/mev-share-java) on GitHub.
1. Choose **Fork** in the top-right, then choose **Create new fork**.
1. For **Owner**, select your username.
1. For **Repository name**, we suggest keeping the name mev-share-java, but you can use any name.
1. Optional. To contribute you need only the main branch of the repo. To include all branches, unselect the checkbox for **Copy the `main` branch only**.
1. Click **Create fork**.

### Clone your fork

Next, clone your fork of the repo to your local workspace.

**To clone your fork to your local workspace**
1. Open the GitHub page for your fork of the repo, then click **Sync fork**.
1. Click **Code**, then click **HTTPS** and copy the web URL displayed.
1. Open a terminal session and navigate to the folder to use, then run the following command, replacing the URL with the URL you copied from the Git page:

`git clone https://github.com/github-user-name/mev-share-java.git`

The repo is automatically cloned into the `mev-share-java` folder in your workspace.
Create a branch of your fork with following command (or follow the [GitHub topic on branching](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-and-deleting-branches-within-your-repository))

`git checkout -b your-branch-name`

Use the following command to set the [remote upstream repo](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/configuring-a-remote-repository-for-a-fork):

`git remote add upstream https://github.com/optimism-java/mev-share-java.git`

You now have a fork of the mev-share-java repo set up in your local workspace. You can make changes to the files in the workspace, add commits, then push your changes to your fork of the repo to then create a Pull Request.

`./gradlew build`

Run build before you submit a Pull Request.
301 changes: 301 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,305 @@
[![License](https://img.shields.io/badge/license-MIT-blue)](https://opensource.org/licenses/MIT)
![Coverage](.github/badges/jacoco.svg)
![Branches](.github/badges/branches.svg)

# mev-share-java

Mev-share-java is a Java library for working with MEV-share.

Based on [Specs](https://github.com/flashbots/mev-share)

## Using

Download the latest jar from maven central.

### Maven

```xml
<dependency>
<groupId>me.grapebaba</groupId>
<artifactId>mev-share-java</artifactId>
<version>0.1.0</version>
</dependency>
```

### Gradle

```groovy
implementation 'me.grapebaba:mev-share-java:0.1.0'
```

## Building Locally

To get started you need to install JDK17+, then run the following command:

```bash
GOERLI_RPC_URL=<GOERLI_RPC_URL> SIGNER_PRIVATE_KEY=<SIGNER_PRIVATE_KEY> ./gradlew clean build
```

## Javadoc

For the latest javadocs for the `main` branch, run `./gradlew javadoc` and open
the document under the `build/docs/javadoc/index.html` in your browser.

## Testing

### To run unit tests

```
GOERLI_RPC_URL=<GOERLI_RPC_URL> SIGNER_PRIVATE_KEY=<SIGNER_PRIVATE_KEY> ./gradlew test
```

## How to use it

### Create a MEVShare instance

```java
// Create a credential instance for authentication using Web3j
Credentials authSigner = Credentials.create("<hex string of privateKey>");

// Create an ethereum provider instance using Web3j
Web3j web3j = Web3j.build(new HttpService("<ethereum network rpc url>"));

// Create a Mev share network options instance or use built-in options
Network network = new Network()
.setName("<network name>")
.setChainId("<chain id>")
.setRpcUrl("<mev share network rpc url>")
.setStreamUrl("<mev share network stream url>");

Network network = Network.GOERLI;
Network network = Network.MAINNET;

// Create a Mev share instance
MevShareClient mevShareClient = new MevShareClient(network, authSigner, web3j);
```

### History events Query

```java
// Query the Event info
CompletableFuture<EventHistoryInfo> historyInfoFuture = mevShareClient.getEventHistoryInfo();

// Query the Event List by params
EventHistoryParams historyParams = new EventHistoryParams().setLimit(20).setBlockStart(BigInteger.valueOf(1_000_000L));
CompletableFuture<List<EventHistoryEntry>> eventHistory = mevShareClient.getEventHistory(historyParams);
```

### Subscribe to events stream

```java
// Create an event listener which handles the event
Consumer<MevShareEvent> eventListener = mevShareEvent -> {
// do something and do not block here...
};

// Subscribe to events stream
Disposable disposable = mevShareClient.subscribe(eventListener);

// remember to release when no longer to subscribe events
disposable.dispose();
```

### Send bundle

#### Send a bundle including a hash item

```java

// Listen to the event stream and capture the bundle hash
CompletableFuture<MevShareEvent> future = new CompletableFuture<>();
Disposable eventSource = mevShareClient.subscribe(mevShareEvent -> {
if (mevShareEvent.getHash() != null) {
future.complete(mevShareEvent);
}
});
MevShareEvent mevShareEvent = future.get();
eventSource.dispose();

BigInteger number = web3j.ethGetBlockByNumber(DefaultBlockParameterName.LATEST, false)
.send()
.getBlock()
.getNumber();

Inclusion inclusion =
new Inclusion().setBlock(number.add(BigInteger.ONE)).setMaxBlock(number.add(BigInteger.valueOf(4)));

BundleItemType.HashItem bundleItem = new BundleItemType.HashItem().setHash(mevShareEvent.getHash());

// Create a backrun transaction
Credentials signer = Credentials.create("<private key>");
BigInteger nonce = web3j.ethGetTransactionCount(signer.getAddress(), DefaultBlockParameterName.PENDING)
.send()
.getTransactionCount();
BigInteger gasPrice = web3j.ethGasPrice().send().getGasPrice();
BigInteger gasLimit = DefaultGasProvider.GAS_LIMIT;
final String to = "<to address>";
final String amount = "<ether amount>";
RawTransaction rawTransaction = RawTransaction.createEtherTransaction(
nonce,
gasPrice,
gasLimit,
to,
Convert.toWei(amount, Convert.Unit.ETHER).toBigInteger());
byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, Network.GOERLI.chainId(), signer);
String hexValue = Numeric.toHexString(signedMessage);

BundleItemType.TxItem txItem =
new BundleItemType.TxItem().setTx(hexValue).setCanRevert(true);

// Construct the bundle with bundle hash item and backrun transaction item
BundleParams bundleParams = new BundleParams().setInclusion(inclusion).setBody(List.of(bundleItem, txItem));

// Send the bundle
CompletableFuture<SendBundleResponse> res = mevShareClient.sendBundle(bundleParams);
```

#### Send a bundle with privacy
Bundles that only contain signed transactions can share hints about the transactions in their bundle by setting the privacy parameter
```java
// Create a transaction
Credentials signer = Credentials.create("<private key>");
BigInteger nonce = web3j.ethGetTransactionCount(signer.getAddress(), DefaultBlockParameterName.PENDING)
.send()
.getTransactionCount();
BigInteger gasPrice = web3j.ethGasPrice().send().getGasPrice();
BigInteger gasLimit = DefaultGasProvider.GAS_LIMIT;
final String to = "<to address>";
final String amount = "<ether amount>";
RawTransaction rawTransaction = RawTransaction.createEtherTransaction(
nonce,
gasPrice,
gasLimit,
to,
Convert.toWei(amount, Convert.Unit.ETHER).toBigInteger());
byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, Network.GOERLI.chainId(), signer);
String hexValue = Numeric.toHexString(signedMessage);

BundleItemType.TxItem txItem =
new BundleItemType.TxItem().setTx(hexValue).setCanRevert(true);

// Set privacy parameter
HintPreferences hintPreferences = new HintPreferences()
.setCalldata(true)
.setContractAddress(true)
.setFunctionSelector(true)
.setLogs(true)
.setTxHash(true);
List<String> builders = new ArrayList<>();
builders.add("flashbots");

BundlePrivacy bundlePrivacy =
new BundlePrivacy().setHints(hintPreferences).setBuilders(builders);

// Construct the bundle with transaction item
BundleParams bundleParams = new BundleParams()
.setInclusion(inclusion)
.setBody(List.of(txItem))
.setPrivacy(bundlePrivacy);

// Send the bundle
CompletableFuture<SendBundleResponse> res = MEV_SHARE_CLIENT.sendBundle(bundleParams);
```

### Simulate bundle

```java
// Create a transaction
var latestBlock = web3j.ethGetBlockByNumber(DefaultBlockParameterName.LATEST, false)
.send()
.getBlock();
var parentBlock = web3j.ethGetBlockByNumber(
DefaultBlockParameter.valueOf(latestBlock.getNumber().subtract(BigInteger.ONE)), false)
.send()
.getBlock();

Inclusion inclusion = new Inclusion()
.setBlock(latestBlock.getNumber().subtract(BigInteger.ONE))
.setMaxBlock(latestBlock.getNumber().add(BigInteger.valueOf(10)));

Credentials signer = Credentials.create("<private key>");
BigInteger nonce = web3j.ethGetTransactionCount(signer.getAddress(), DefaultBlockParameterName.PENDING)
.send()
.getTransactionCount();
final String to = "<to address>";
RawTransaction rawTransaction = RawTransaction.createEtherTransaction(
nonce,
web3j.ethGasPrice().send().getGasPrice(),
DefaultGasProvider.GAS_LIMIT,
to,
Convert.toWei("0", Convert.Unit.ETHER).toBigInteger());
byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, Network.GOERLI.chainId(), signer);
String hexValue = Numeric.toHexString(signedMessage);

// Construct the bundle params with transaction item
BundleItemType.TxItem bundleItem =
new BundleItemType.TxItem().setTx(hexValue).setCanRevert(true);

BundleParams bundleParams = new BundleParams().setInclusion(inclusion).setBody(List.of(bundleItem));

// Create a simbundle options
SimBundleOptions options = new SimBundleOptions()
.setParentBlock(latestBlock.getNumber().subtract(BigInteger.ONE))
.setBlockNumber(latestBlock.getNumber())
.setTimestamp(parentBlock.getTimestamp().add(BigInteger.valueOf(12)))
.setGasLimit(parentBlock.getGasLimit())
.setBaseFee(parentBlock.getBaseFeePerGas())
.setTimeout(30);

// Simulate the bundle
CompletableFuture<SimBundleResponse> res = mevShareClient.simBundle(bundleParams, options);
```

### Send private transaction

```java
// Create a transaction
EthBlock.Block latest = web3j.ethGetBlockByNumber(DefaultBlockParameterName.LATEST, false)
.send()
.getBlock();

BigInteger maxPriorityFeePerGas = BigInteger.valueOf(1_000_000_000L);

Credentials signer = Credentials.create("<private key>");
BigInteger nonce = web3j.ethGetTransactionCount(signer.getAddress(), DefaultBlockParameterName.PENDING)
.send()
.getTransactionCount();
final String to = "<to address>";

RawTransaction rawTransaction = RawTransaction.createTransaction(
5L,
nonce,
latest.getGasLimit(),
to,
Convert.toWei("0", Convert.Unit.ETHER).toBigInteger(),
Numeric.toHexString("<data>".getBytes(StandardCharsets.UTF_8)),
maxPriorityFeePerGas,
latest.getBaseFeePerGas().multiply(BigInteger.TWO).add(maxPriorityFeePerGas));
byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, Network.GOERLI.chainId(), signer);
String signRawTx = Numeric.toHexString(signedMessage);

// Create a private transaction options
PrivateTxOptions txOptions = new PrivateTxOptions()
.setHints(new HintPreferences()
.setCalldata(true)
.setContractAddress(true)
.setFunctionSelector(true)
.setLogs(true));

// Send the private transaction
CompletableFuture<String> res = mevShareClient.sendPrivateTransaction(signRawTx, txOptions);
```

## Examples
For more examples, you can see [example](https://github.com/optimism-java/mev-share-java/tree/main/example)

> Examples require a `.env` file (or that you populate your environment directly with the appropriate variables).
```sh
cd src/examples
cp .env.example .env
vim .env
```

## Contribution
To help mev-share-java grow, follow [Contributing to mev-share-java](CONTRIBUTING.md).

0 comments on commit 613d97b

Please sign in to comment.