Mev-share-java is a Java library for working with MEV-share.
Based on Specs
<dependency>
<groupId>me.grapebaba</groupId>
<artifactId>mev-share-java</artifactId>
<version>0.1.1</version>
</dependency>implementation 'me.grapebaba:mev-share-java:0.1.1'To get started you need to install JDK17+, then run the following command:
./gradlew clean build -x testFor the latest javadocs for the main branch, run ./gradlew javadoc and open
the document under the build/docs/javadoc/index.html in your browser.
GOERLI_RPC_URL=<GOERLI_RPC_URL> SIGNER_PRIVATE_KEY=<SIGNER_PRIVATE_KEY> ./gradlew test
// Create a credential instance for authentication using Web3jCredentialsauthSigner = Credentials.create("<hex string of privateKey>");
// Create an ethereum provider instance using Web3jWeb3jweb3j = Web3j.build(newHttpService("<ethereum network rpc url>"));
// Create a Mev share network options instance or use built-in optionsNetworknetwork = newNetwork()
.setName("<network name>")
.setChainId("<chain id>")
.setRpcUrl("<mev share network rpc url>")
.setStreamUrl("<mev share network stream url>");
Networknetwork = Network.GOERLI;
Networknetwork = Network.MAINNET;
// Create a Mev share instanceMevShareClientmevShareClient = newMevShareClient(network, authSigner, web3j);// Query the Event infoCompletableFuture<EventHistoryInfo> historyInfoFuture = mevShareClient.getEventHistoryInfo();
// Query the Event List by paramsEventHistoryParamshistoryParams = newEventHistoryParams().setLimit(20).setBlockStart(BigInteger.valueOf(1_000_000L));
CompletableFuture<List<EventHistoryEntry>> eventHistory = mevShareClient.getEventHistory(historyParams);// Create an event listener which handles the eventConsumer<MevShareEvent> eventListener = mevShareEvent -> {
// do something and do not block here...
};
// Subscribe to events streamDisposabledisposable = mevShareClient.subscribe(eventListener);
// remember to release when no longer to subscribe eventsdisposable.dispose();// Listen to the event stream and capture the bundle hashCompletableFuture<MevShareEvent> future = newCompletableFuture<>();
DisposableeventSource = mevShareClient.subscribe(mevShareEvent -> {
if (mevShareEvent.getHash() != null) {
future.complete(mevShareEvent);
}
});
MevShareEventmevShareEvent = future.get();
eventSource.dispose();
BigIntegernumber = web3j.ethGetBlockByNumber(DefaultBlockParameterName.LATEST, false)
.send()
.getBlock()
.getNumber();
Inclusioninclusion =
newInclusion().setBlock(number.add(BigInteger.ONE)).setMaxBlock(number.add(BigInteger.valueOf(4)));
BundleItemType.HashItembundleItem = newBundleItemType.HashItem().setHash(mevShareEvent.getHash());
// Create a backrun transactionCredentialssigner = Credentials.create("<private key>");
BigIntegernonce = web3j.ethGetTransactionCount(signer.getAddress(), DefaultBlockParameterName.PENDING)
.send()
.getTransactionCount();
BigIntegergasPrice = web3j.ethGasPrice().send().getGasPrice();
BigIntegergasLimit = DefaultGasProvider.GAS_LIMIT;
finalStringto = "<to address>";
finalStringamount = "<ether amount>";
RawTransactionrawTransaction = RawTransaction.createEtherTransaction(
nonce,
gasPrice,
gasLimit,
to,
Convert.toWei(amount, Convert.Unit.ETHER).toBigInteger());
byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, Network.GOERLI.chainId(), signer);
StringhexValue = Numeric.toHexString(signedMessage);
BundleItemType.TxItemtxItem =
newBundleItemType.TxItem().setTx(hexValue).setCanRevert(true);
// Construct the bundle with bundle hash item and backrun transaction itemBundleParamsbundleParams = newBundleParams().setInclusion(inclusion).setBody(List.of(bundleItem, txItem));
// Send the bundleCompletableFuture<SendBundleResponse> res = mevShareClient.sendBundle(bundleParams);Bundles that only contain signed transactions can share hints about the transactions in their bundle by setting the privacy parameter
// Create a transactionCredentialssigner = Credentials.create("<private key>");
BigIntegernonce = web3j.ethGetTransactionCount(signer.getAddress(), DefaultBlockParameterName.PENDING)
.send()
.getTransactionCount();
BigIntegergasPrice = web3j.ethGasPrice().send().getGasPrice();
BigIntegergasLimit = DefaultGasProvider.GAS_LIMIT;
finalStringto = "<to address>";
finalStringamount = "<ether amount>";
RawTransactionrawTransaction = RawTransaction.createEtherTransaction(
nonce,
gasPrice,
gasLimit,
to,
Convert.toWei(amount, Convert.Unit.ETHER).toBigInteger());
byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, Network.GOERLI.chainId(), signer);
StringhexValue = Numeric.toHexString(signedMessage);
BundleItemType.TxItemtxItem =
newBundleItemType.TxItem().setTx(hexValue).setCanRevert(true);
// Set privacy parameterHintPreferenceshintPreferences = newHintPreferences()
.setCalldata(true)
.setContractAddress(true)
.setFunctionSelector(true)
.setLogs(true)
.setTxHash(true);
List<String> builders = newArrayList<>();
builders.add("flashbots");
BundlePrivacybundlePrivacy =
newBundlePrivacy().setHints(hintPreferences).setBuilders(builders);
// Construct the bundle with transaction itemBundleParamsbundleParams = newBundleParams()
.setInclusion(inclusion)
.setBody(List.of(txItem))
.setPrivacy(bundlePrivacy);
// Send the bundleCompletableFuture<SendBundleResponse> res = MEV_SHARE_CLIENT.sendBundle(bundleParams);// Create a transactionvarlatestBlock = web3j.ethGetBlockByNumber(DefaultBlockParameterName.LATEST, false)
.send()
.getBlock();
varparentBlock = web3j.ethGetBlockByNumber(
DefaultBlockParameter.valueOf(latestBlock.getNumber().subtract(BigInteger.ONE)), false)
.send()
.getBlock();
Inclusioninclusion = newInclusion()
.setBlock(latestBlock.getNumber().subtract(BigInteger.ONE))
.setMaxBlock(latestBlock.getNumber().add(BigInteger.valueOf(10)));
Credentialssigner = Credentials.create("<private key>");
BigIntegernonce = web3j.ethGetTransactionCount(signer.getAddress(), DefaultBlockParameterName.PENDING)
.send()
.getTransactionCount();
finalStringto = "<to address>";
RawTransactionrawTransaction = 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);
StringhexValue = Numeric.toHexString(signedMessage);
// Construct the bundle params with transaction itemBundleItemType.TxItembundleItem =
newBundleItemType.TxItem().setTx(hexValue).setCanRevert(true);
BundleParamsbundleParams = newBundleParams().setInclusion(inclusion).setBody(List.of(bundleItem));
// Create a simbundle optionsSimBundleOptionsoptions = newSimBundleOptions()
.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 bundleCompletableFuture<SimBundleResponse> res = mevShareClient.simBundle(bundleParams, options);// Create a transactionEthBlock.Blocklatest = web3j.ethGetBlockByNumber(DefaultBlockParameterName.LATEST, false)
.send()
.getBlock();
BigIntegermaxPriorityFeePerGas = BigInteger.valueOf(1_000_000_000L);
Credentialssigner = Credentials.create("<private key>");
BigIntegernonce = web3j.ethGetTransactionCount(signer.getAddress(), DefaultBlockParameterName.PENDING)
.send()
.getTransactionCount();
finalStringto = "<to address>";
RawTransactionrawTransaction = 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);
StringsignRawTx = Numeric.toHexString(signedMessage);
// Create a private transaction optionsPrivateTxOptionstxOptions = newPrivateTxOptions()
.setHints(newHintPreferences()
.setCalldata(true)
.setContractAddress(true)
.setFunctionSelector(true)
.setLogs(true));
// Send the private transactionCompletableFuture<String> res = mevShareClient.sendPrivateTransaction(signRawTx, txOptions);For more examples, you can see example
Examples can be run with the following commands:
./gradlew execute -PmainClassName=bundle.RpcSendPrivateTx
./gradlew execute -PmainClassName=event.SseHistoricalExamples require a
.envfile (or that you populate your environment directly with the appropriate variables).
cd src/examples
cp .env.example .env
vim .envTo help mev-share-java grow, follow Contributing to mev-share-java.