Skip to content

Commit

Permalink
Merge pull request #326 from pimlicolabs/re-write
Browse files Browse the repository at this point in the history
Make config simpler
  • Loading branch information
plusminushalf authored Oct 14, 2024
2 parents 06a10e1 + aac1aae commit 6f9eb33
Show file tree
Hide file tree
Showing 22 changed files with 829 additions and 1,132 deletions.
49 changes: 49 additions & 0 deletions src/cli/deploySimulationsContract.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { PimlicoEntryPointSimulationsDeployBytecode } from "@alto/types"
import {
type Chain,
createWalletClient,
type Hex,
http,
type PublicClient,
type Transport
} from "viem"
import type { CamelCasedProperties } from "./parseArgs"
import type { IOptions } from "@alto/cli"

export const deploySimulationsContract = async ({
args,
publicClient
}: {
args: CamelCasedProperties<IOptions>
publicClient: PublicClient<Transport, Chain>
}): Promise<Hex> => {
const utilityPrivateKey = args.utilityPrivateKey
if (!utilityPrivateKey) {
throw new Error(
"Cannot deploy entryPoint simulations without utility-private-key"
)
}

const walletClient = createWalletClient({
transport: http(args.rpcUrl),
account: utilityPrivateKey
})

const deployHash = await walletClient.deployContract({
chain: publicClient.chain,
abi: [],
bytecode: PimlicoEntryPointSimulationsDeployBytecode
})

const receipt = await publicClient.getTransactionReceipt({
hash: deployHash
})

const simulationsContract = receipt.contractAddress

if (simulationsContract === null || simulationsContract === undefined) {
throw new Error("Failed to deploy simulationsContract")
}

return simulationsContract
}
208 changes: 55 additions & 153 deletions src/cli/handler.ts
Original file line number Diff line number Diff line change
@@ -1,60 +1,38 @@
import { SenderManager } from "@alto/executor"
import { GasPriceManager } from "@alto/handlers"
import {
type Logger,
createMetrics,
initDebugLogger,
initProductionLogger
} from "@alto/utils"
import { Registry } from "prom-client"
import {
http,
type Chain,
type PublicClient,
type Transport,
createPublicClient,
createWalletClient,
formatEther
} from "viem"
import { fromZodError } from "zod-validation-error"
import { UtilityWalletMonitor } from "../executor/utilityWalletMonitor"
import { PimlicoEntryPointSimulationsDeployBytecode } from "../types/contracts"
import {
type IBundlerArgs,
type IOptions,
type IOptionsInput,
optionArgsSchema
} from "./config"
import type { IOptionsInput } from "./config"
import { customTransport } from "./customTransport"
import { setupServer } from "./setupServer"
import { type AltoConfig, createConfig } from "../createConfig"
import { parseArgs } from "./parseArgs"
import { deploySimulationsContract } from "./deploySimulationsContract"

const parseArgs = (args: IOptionsInput): IOptions => {
// validate every arg, make type safe so if i add a new arg i have to validate it
const parsing = optionArgsSchema.safeParse(args)
if (!parsing.success) {
const error = fromZodError(parsing.error)
throw new Error(error.message)
}

return parsing.data
}

const preFlightChecks = async (
publicClient: PublicClient<Transport, Chain>,
parsedArgs: IBundlerArgs
): Promise<void> => {
for (const entrypoint of parsedArgs.entrypoints) {
const entryPointCode = await publicClient.getBytecode({
const preFlightChecks = async (config: AltoConfig): Promise<void> => {
for (const entrypoint of config.entrypoints) {
const entryPointCode = await config.publicClient.getBytecode({
address: entrypoint
})
if (entryPointCode === "0x") {
throw new Error(`entry point ${entrypoint} does not exist`)
}
}

if (parsedArgs["entrypoint-simulation-contract"]) {
const simulations = parsedArgs["entrypoint-simulation-contract"]
const simulationsCode = await publicClient.getBytecode({
if (config.entrypointSimulationContract) {
const simulations = config.entrypointSimulationContract
const simulationsCode = await config.publicClient.getBytecode({
address: simulations
})
if (simulationsCode === undefined || simulationsCode === "0x") {
Expand All @@ -65,115 +43,77 @@ const preFlightChecks = async (
}
}

export async function bundlerHandler(args: IOptionsInput): Promise<void> {
const parsedArgs = parseArgs(args)

let logger: Logger
if (parsedArgs.json) {
logger = initProductionLogger(parsedArgs["log-level"])
} else {
logger = initDebugLogger(parsedArgs["log-level"])
}

const rootLogger = logger.child(
{ module: "root" },
{ level: parsedArgs["log-level"] }
)
export async function bundlerHandler(args_: IOptionsInput): Promise<void> {
const args = parseArgs(args_)
const logger = args.json
? initProductionLogger(args.logLevel)
: initDebugLogger(args.logLevel)

const getChainId = async () => {
const client = createPublicClient({
transport: customTransport(parsedArgs["rpc-url"], {
transport: customTransport(args.rpcUrl, {
logger: logger.child(
{ module: "public_client" },
{
level:
parsedArgs["public-client-log-level"] ||
parsedArgs["log-level"]
level: args.publicClientLogLevel || args.logLevel
}
)
})
})
return await client.getChainId()
}

const chainId = await getChainId()

const chain: Chain = {
id: chainId,
name: args["network-name"],
name: args.networkName,
nativeCurrency: {
name: "ETH",
symbol: "ETH",
decimals: 18
},
rpcUrls: {
default: { http: [args["rpc-url"]] },
public: { http: [args["rpc-url"]] }
default: { http: [args.rpcUrl] },
public: { http: [args.rpcUrl] }
}
}

const client = createPublicClient({
transport: customTransport(args["rpc-url"], {
const publicClient = createPublicClient({
transport: customTransport(args.rpcUrl, {
logger: logger.child(
{ module: "public_client" },
{
level:
parsedArgs["public-client-log-level"] ||
parsedArgs["log-level"]
level: args.publicClientLogLevel || args.logLevel
}
)
}),
chain
})

// if flag is set, use utility wallet to deploy the simulations contract
if (parsedArgs["deploy-simulations-contract"]) {
if (!parsedArgs["utility-private-key"]) {
throw new Error(
"Cannot deploy entryPoint simulations without utility-private-key"
const walletClient = createWalletClient({
transport: customTransport(args.sendTransactionRpcUrl ?? args.rpcUrl, {
logger: logger.child(
{ module: "wallet_client" },
{
level: args.walletClientLogLevel || args.logLevel
}
)
}

const walletClient = createWalletClient({
transport: http(args["rpc-url"]),
account: parsedArgs["utility-private-key"]
})

const deployHash = await walletClient.deployContract({
chain,
abi: [],
bytecode: PimlicoEntryPointSimulationsDeployBytecode
})
}),
chain
})

const receipt = await client.getTransactionReceipt({
hash: deployHash
// if flag is set, use utility wallet to deploy the simulations contract
if (args.deploySimulationsContract) {
args.entrypointSimulationContract = await deploySimulationsContract({
args,
publicClient
})

const simulationsContract = receipt.contractAddress

if (simulationsContract === null) {
throw new Error("Failed to deploy simulationsContract")
}

parsedArgs["entrypoint-simulation-contract"] = simulationsContract
}

const gasPriceManager = new GasPriceManager(
chain,
client,
parsedArgs["legacy-transactions"],
logger.child(
{ module: "gas_price_manager" },
{
level:
parsedArgs["public-client-log-level"] ||
parsedArgs["log-level"]
}
),
parsedArgs["gas-price-bump"],
parsedArgs["gas-price-expiry"],
parsedArgs["gas-price-refresh-interval"],
parsedArgs["chain-type"]
)
const config = createConfig({ ...args, logger, publicClient, walletClient })

const gasPriceManager = new GasPriceManager(config)

await gasPriceManager.init()

Expand All @@ -184,70 +124,32 @@ export async function bundlerHandler(args: IOptionsInput): Promise<void> {
})
const metrics = createMetrics(registry)

await preFlightChecks(client, parsedArgs)
await preFlightChecks(config)

const walletClient = createWalletClient({
transport: customTransport(
parsedArgs["send-transaction-rpc-url"] ?? args["rpc-url"],
{
logger: logger.child(
{ module: "wallet_client" },
{
level:
parsedArgs["wallet-client-log-level"] ||
parsedArgs["log-level"]
}
)
}
),
chain
})

const senderManager = new SenderManager(
parsedArgs["executor-private-keys"],
parsedArgs["utility-private-key"],
logger.child(
{ module: "executor" },
{
level:
parsedArgs["executor-log-level"] || parsedArgs["log-level"]
}
),
const senderManager = new SenderManager({
config,
metrics,
parsedArgs["legacy-transactions"],
gasPriceManager,
parsedArgs["max-executors"]
)
gasPriceManager
})

const utilityWalletAddress = parsedArgs["utility-private-key"]?.address
const utilityWalletAddress = config.utilityPrivateKey?.address

if (utilityWalletAddress && parsedArgs["utility-wallet-monitor"]) {
const utilityWalletMonitor = new UtilityWalletMonitor(
client,
parsedArgs["utility-wallet-monitor-interval"],
utilityWalletAddress,
if (utilityWalletAddress && config.utilityWalletMonitor) {
const utilityWalletMonitor = new UtilityWalletMonitor({
config,
metrics,
logger.child(
{ module: "utility_wallet_monitor" },
{
level: parsedArgs["log-level"]
}
)
)
utilityWalletAddress
})

await utilityWalletMonitor.start()
}

metrics.executorWalletsMinBalance.set(
Number.parseFloat(formatEther(parsedArgs["min-executor-balance"] || 0n))
Number.parseFloat(formatEther(config.minExecutorBalance || 0n))
)

await setupServer({
client,
walletClient,
parsedArgs,
logger,
rootLogger,
config,
registry,
metrics,
senderManager,
Expand Down
Loading

0 comments on commit 6f9eb33

Please sign in to comment.