Skip to content

Commit

Permalink
Update readme
Browse files Browse the repository at this point in the history
Create startBundler method to avoid needing shell args externally.
Make gasFactor, minStake, and minUnstakeDelay optional.
  • Loading branch information
matthewwalsh0 committed Jan 11, 2024
1 parent 026edd1 commit faca18d
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 7 deletions.
69 changes: 67 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,73 @@
# Test Bundler

An EIP-4337 bundler used in MetaMask client E2E tests.

> [!NOTE]
> Forked from [eth-infinitism/bundler](https://github.com/eth-infinitism/bundler).
An EIP-4337 bundler to be used in client E2E tests.
## Usage

### Start Server

```typescript
import { startBundler, BundlerServer } from '@metamask/test-bundler';

const server = await startBundler({
configFile: './some-directory/bundler.config.json',
unsafe: true, // Disable extra validations requiring RPC debug methods.
});
```

The server is accessible at `http://localhost:3000/rpc` by default.

### Stop Server

```typescript
await server.stop();
```

## Configuration

The server is primarily configured using a JSON file:

```json
{
// Delay in seconds before submitting any pending user operations in a transaction.
"autoBundleInterval": 3,
// Max number of user operations in a single transaction.
"autoBundleMempoolSize": 10,
// Account to be compensated for the gas cost of the transaction.
"beneficiary": "0x8890d2dAB1922Bec92922f7E6879D5c65ba333f4",
// Address of the entrypoint smart contract.
"entryPoint": "0x18b06605539dc02ecD3f7AB314e38eB7c1dA5c9b",
// Max total gas of user operations in a single transaction.
"maxBundleGas": 5e6,
// Minimum allowed balance of the signing account.
"minBalance": "0",
// Path to a text file containing the mnemonic for the account signing the transactions.
"mnemonic": "./test/e2e/bundler.mnemonic.txt",
// URL of an RPC provider for the desired network.
"network": "http://127.0.0.1:8545",
// Local port to run the server on.
"port": "3000"
}
```

## Build

```shell
# Install dependencies.
yarn

# 1. Compile smart contracts using Hardhat.
# 2. Compile typescript sources to `dist` folder.
yarn setup
```

## Test

Run the unit tests using Hardhat:

Creates the bundler server at `http://localhost:3000/rpc` by default.
```
yarn test
```
6 changes: 3 additions & 3 deletions src/bundler/BundlerConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export type BundlerConfig = {
export const BundlerConfigShape = {
beneficiary: ow.string,
entryPoint: ow.string,
gasFactor: ow.string,
gasFactor: ow.optional.string,
minBalance: ow.string,
mnemonic: ow.string,
network: ow.string,
Expand All @@ -40,8 +40,8 @@ export const BundlerConfigShape = {
whitelist: ow.optional.array.ofType(ow.string),
blacklist: ow.optional.array.ofType(ow.string),
maxBundleGas: ow.number,
minStake: ow.string,
minUnstakeDelay: ow.number,
minStake: ow.optional.string,
minUnstakeDelay: ow.optional.number,
autoBundleInterval: ow.number,
autoBundleMempoolSize: ow.number,
};
Expand Down
2 changes: 1 addition & 1 deletion src/bundler/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ function getCommandLineParams(programOpts: any): Partial<BundlerConfig> {
* @param sources
*/
function mergeConfigs(...sources: Partial<BundlerConfig>[]): BundlerConfig {
const mergedConfig = Object.assign({}, ...sources);
const mergedConfig = Object.assign({}, ...sources) as BundlerConfig;
ow(mergedConfig, ow.object.exactShape(BundlerConfigShape));
return mergedConfig;
}
Expand Down
25 changes: 25 additions & 0 deletions src/bundler/runBundler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,31 @@ export async function connectContracts(
};
}

/**
* Start the bundler server.
* @param options - Options for the bundler server.
* @param options.configFile - Path to the config file.
* @param options.unsafe - Whether to disable additional validations requiring the RPC debug methods.
* @returns The bundler server instance.
*/
export async function startBundler({
configFile,
unsafe,
}: {
configFile: string;
unsafe?: boolean;
}): Promise<BundlerServer> {
const args = [
'-',
'-',
unsafe ? '--unsafe' : undefined,
'--config',
configFile,
].filter((arg) => arg !== undefined) as string[];

return await runBundler(args);
}

/**
* start the bundler server.
* this is an async method, but only to resolve configuration. after it returns, the server is only active after asyncInit()
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export { runBundler } from './bundler/runBundler';
export { startBundler } from './bundler/runBundler';
export { BundlerServer } from './bundler/BundlerServer';

0 comments on commit faca18d

Please sign in to comment.