@flashbots/ethers-provider-bundle
Advanced tools
Comparing version 0.4.0 to 0.4.1
@@ -7,4 +7,4 @@ "use strict"; | ||
const GWEI = ethers_1.BigNumber.from(10).pow(9); | ||
const PRIORITY_FEE = GWEI.mul(6); | ||
const LEGACY_GAS_PRICE = GWEI.mul(8); | ||
const PRIORITY_FEE = GWEI.mul(3); | ||
const LEGACY_GAS_PRICE = GWEI.mul(12); | ||
const BLOCKS_IN_THE_FUTURE = 2; | ||
@@ -66,3 +66,4 @@ // ===== Uncomment this for mainnet ======= | ||
]); | ||
const simulation = await flashbotsProvider.simulate(signedTransactions, blockNumber + BLOCKS_IN_THE_FUTURE); | ||
const targetBlock = blockNumber + BLOCKS_IN_THE_FUTURE; | ||
const simulation = await flashbotsProvider.simulate(signedTransactions, targetBlock); | ||
// Using TypeScript discrimination | ||
@@ -76,3 +77,3 @@ if ('error' in simulation) { | ||
} | ||
const bundleSubmission = await flashbotsProvider.sendRawBundle(signedTransactions, blockNumber + BLOCKS_IN_THE_FUTURE); | ||
const bundleSubmission = await flashbotsProvider.sendRawBundle(signedTransactions, targetBlock); | ||
console.log('bundle submitted, waiting'); | ||
@@ -87,2 +88,8 @@ if ('error' in bundleSubmission) { | ||
} | ||
else { | ||
console.log({ | ||
bundleStats: await flashbotsProvider.getBundleStats(simulation.bundleHash, targetBlock), | ||
userStats: await flashbotsProvider.getUserStats(), | ||
}); | ||
} | ||
}); | ||
@@ -89,0 +96,0 @@ } |
@@ -87,2 +87,11 @@ import { BlockTag, TransactionReceipt, TransactionRequest } from '@ethersproject/abstract-provider'; | ||
export declare type GetUserStatsResponse = GetUserStatsResponseSuccess | RelayResponseError; | ||
export interface GetBundleStatsResponseSuccess { | ||
isSimulated: boolean; | ||
isSentToMiners: boolean; | ||
isHighPriority: boolean; | ||
simulatedAt: string; | ||
submittedAt: string; | ||
sentToMinersAt: string; | ||
} | ||
export declare type GetBundleStatsResponse = GetBundleStatsResponseSuccess | RelayResponseError; | ||
export declare class FlashbotsBundleProvider extends providers.JsonRpcProvider { | ||
@@ -101,2 +110,3 @@ private genericProvider; | ||
getUserStats(): Promise<GetUserStatsResponse>; | ||
getBundleStats(bundleHash: string, blockNumber: number): Promise<GetBundleStatsResponse>; | ||
simulate(signedBundledTransactions: Array<string>, blockTag: BlockTag, stateBlockTag?: BlockTag, blockTimestamp?: number): Promise<SimulationResponse>; | ||
@@ -103,0 +113,0 @@ private request; |
@@ -162,3 +162,3 @@ "use strict"; | ||
} | ||
const bundleIncluded = transactionAccountNonces.every((transaction) => blockTransactionsHash[transaction.hash] === true); | ||
const bundleIncluded = transactionAccountNonces.every((transaction) => blockTransactionsHash[transaction.hash]); | ||
resolve(bundleIncluded ? FlashbotsBundleResolution.BundleIncluded : FlashbotsBundleResolution.BlockPassedWithoutInclusion); | ||
@@ -208,2 +208,17 @@ } | ||
} | ||
async getBundleStats(bundleHash, blockNumber) { | ||
const evmBlockNumber = `0x${blockNumber.toString(16)}`; | ||
const params = [{ bundleHash, blockNumber: evmBlockNumber }]; | ||
const request = JSON.stringify(this.prepareBundleRequest('flashbots_getBundleStats', params)); | ||
const response = await this.request(request); | ||
if (response.error !== undefined && response.error !== null) { | ||
return { | ||
error: { | ||
message: response.error.message, | ||
code: response.error.code | ||
} | ||
}; | ||
} | ||
return response.result; | ||
} | ||
async simulate(signedBundledTransactions, blockTag, stateBlockTag, blockTimestamp) { | ||
@@ -210,0 +225,0 @@ let evmBlockNumber; |
{ | ||
"name": "@flashbots/ethers-provider-bundle", | ||
"version": "0.4.0", | ||
"version": "0.4.1", | ||
"description": "", | ||
@@ -5,0 +5,0 @@ "main": "build/index.js", |
@@ -72,2 +72,21 @@ # ethers-provider-flashbots-bundle | ||
## Gas Prices and EIP-1559 | ||
Before EIP-1559 was activated, the most common way for searchers to submit transactions is with `gasPrice=0`, with an on-chain payment to `block.coinbase` conditional on the transaction's success. All transactions must pay `baseFee` now, an attribute of a block. For an example of how to ensure you are using this `baseFee`, see `demo.ts` in this repository. | ||
``` | ||
const block = await provider.getBlock(blockNumber) | ||
const maxBaseFeeInFutureBlock = FlashbotsBundleProvider.getMaxBaseFeeInFutureBlock(block.baseFeePerGas, BLOCKS_IN_THE_FUTURE) | ||
const eip1559Transaction = { | ||
to: wallet.address, | ||
type: 2, | ||
maxFeePerGas: PRIORITY_FEE.add(maxBaseFeeInFutureBlock), | ||
maxPriorityFeePerGas: PRIORITY_FEE, | ||
gasLimit: 21000, | ||
data: '0x', | ||
chainId: CHAIN_ID | ||
} | ||
``` | ||
`FlashbotsBundleProvider.getMaxBaseFeeInFutureBlock` calculates the maximum baseFee that is possible `BLOCKS_IN_THE_FUTURE` blocks, given maximum expansion on each block. You won't pay this fee, so long as it is specified as `maxFeePerGas`, you will only pay the block's `baseFee`. | ||
## Simulate and Send | ||
@@ -150,2 +169,8 @@ | ||
## Bundle and User Statistics | ||
The Flashbots relay can also return statistics about you as a user (identified solely by your signing address) and any bundle previously submitted. | ||
- `getUserStats()` returns aggregate metrics about past performance, including if your signing key is currently eligible for the "high priority" queue. [Read more about searcher reputation here](https://docs.flashbots.net/flashbots-auction/searchers/advanced/reputation) | ||
- `getBundleStats(bundleHash, targetBlockNumber)` returns data specific to a single bundle submission, including detailed timestamps for the various phases a bundle goes before reaching miners. | ||
## How to run demo.ts | ||
@@ -152,0 +177,0 @@ |
@@ -8,4 +8,4 @@ import { BigNumber, providers, Wallet } from 'ethers' | ||
const GWEI = BigNumber.from(10).pow(9) | ||
const PRIORITY_FEE = GWEI.mul(6) | ||
const LEGACY_GAS_PRICE = GWEI.mul(8) | ||
const PRIORITY_FEE = GWEI.mul(3) | ||
const LEGACY_GAS_PRICE = GWEI.mul(12) | ||
const BLOCKS_IN_THE_FUTURE = 2 | ||
@@ -73,4 +73,4 @@ | ||
]) | ||
const simulation = await flashbotsProvider.simulate(signedTransactions, blockNumber + BLOCKS_IN_THE_FUTURE) | ||
const targetBlock = blockNumber + BLOCKS_IN_THE_FUTURE; | ||
const simulation = await flashbotsProvider.simulate(signedTransactions, targetBlock) | ||
// Using TypeScript discrimination | ||
@@ -83,3 +83,3 @@ if ('error' in simulation) { | ||
} | ||
const bundleSubmission = await flashbotsProvider.sendRawBundle(signedTransactions, blockNumber + BLOCKS_IN_THE_FUTURE) | ||
const bundleSubmission = await flashbotsProvider.sendRawBundle(signedTransactions, targetBlock) | ||
console.log('bundle submitted, waiting') | ||
@@ -93,2 +93,7 @@ if ('error' in bundleSubmission) { | ||
process.exit(0) | ||
} else { | ||
console.log({ | ||
bundleStats: await flashbotsProvider.getBundleStats(simulation.bundleHash, targetBlock), | ||
userStats: await flashbotsProvider.getUserStats(), | ||
}) | ||
} | ||
@@ -95,0 +100,0 @@ }) |
@@ -106,2 +106,13 @@ import { BlockTag, TransactionReceipt, TransactionRequest } from '@ethersproject/abstract-provider' | ||
export interface GetBundleStatsResponseSuccess { | ||
isSimulated: boolean | ||
isSentToMiners: boolean | ||
isHighPriority: boolean | ||
simulatedAt: string | ||
submittedAt: string | ||
sentToMinersAt: string | ||
} | ||
export type GetBundleStatsResponse = GetBundleStatsResponseSuccess | RelayResponseError | ||
type RpcParams = Array<string[] | string | number | Record<string, unknown>> | ||
@@ -289,3 +300,3 @@ | ||
} | ||
const bundleIncluded = transactionAccountNonces.every((transaction) => blockTransactionsHash[transaction.hash] === true) | ||
const bundleIncluded = transactionAccountNonces.every((transaction) => blockTransactionsHash[transaction.hash]) | ||
resolve(bundleIncluded ? FlashbotsBundleResolution.BundleIncluded : FlashbotsBundleResolution.BlockPassedWithoutInclusion) | ||
@@ -343,2 +354,20 @@ } | ||
public async getBundleStats(bundleHash: string, blockNumber: number): Promise<GetBundleStatsResponse> { | ||
const evmBlockNumber = `0x${blockNumber.toString(16)}` | ||
const params = [{bundleHash, blockNumber: evmBlockNumber}] | ||
const request = JSON.stringify(this.prepareBundleRequest('flashbots_getBundleStats', params)) | ||
const response = await this.request(request) | ||
if (response.error !== undefined && response.error !== null) { | ||
return { | ||
error: { | ||
message: response.error.message, | ||
code: response.error.code | ||
} | ||
} | ||
} | ||
return response.result | ||
} | ||
public async simulate( | ||
@@ -405,3 +434,3 @@ signedBundledTransactions: Array<string>, | ||
private prepareBundleRequest(method: 'eth_callBundle' | 'eth_sendBundle' | 'flashbots_getUserStats', params: RpcParams) { | ||
private prepareBundleRequest(method: 'eth_callBundle' | 'eth_sendBundle' | 'flashbots_getUserStats' | 'flashbots_getBundleStats', params: RpcParams) { | ||
return { | ||
@@ -408,0 +437,0 @@ method: method, |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
180093
1025
196