Skip to content

Commit

Permalink
fix replacement logic flow
Browse files Browse the repository at this point in the history
  • Loading branch information
mouseless0x committed Dec 10, 2024
1 parent 52395dd commit 8a1b83d
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 76 deletions.
168 changes: 93 additions & 75 deletions src/executor/executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,7 @@ export class Executor {
newRequest.gas = maxBigInt(newRequest.gas, gasLimit)

// update calldata to include only ops that pass simulation
let txParam
if (transactionInfo.transactionType === "default") {
const isUserOpVersion06 = opsWithHashes.reduce(
(acc, op) => {
Expand All @@ -351,39 +352,29 @@ export class Executor {
)
)

newRequest.data = isUserOpVersion06
? encodeFunctionData({
abi: EntryPointV06Abi,
functionName: "handleOps",
args: [
opsToBundle.map(
(opInfo) =>
opInfo.mempoolUserOperation as UserOperationV06
),
transactionInfo.executor.address
]
})
: encodeFunctionData({
abi: EntryPointV07Abi,
functionName: "handleOps",
args: [
opsToBundle.map((opInfo) =>
toPackedUserOperation(
opInfo.mempoolUserOperation as UserOperationV07
)
),
transactionInfo.executor.address
]
})
const userOps = opsToBundle.map((op) =>
isUserOpVersion06
? op.mempoolUserOperation
: toPackedUserOperation(
op.mempoolUserOperation as UserOperationV07
)
) as PackedUserOperation[]

txParam = {
type: "default",
isUserOpVersion06,
ops: userOps,
entryPoint: transactionInfo.entryPoint
}
} else if (transactionInfo.transactionType === "compressed") {
const compressedOps = opsToBundle.map(
(opInfo) =>
opInfo.mempoolUserOperation as CompressedUserOperation
)
newRequest.data = createCompressedCalldata(
compressedOps,
this.getCompressionHandler().perOpInflatorId
)
({ mempoolUserOperation }) => mempoolUserOperation
) as CompressedUserOperation[]

txParam = {
type: "compressed",
compressedOps: compressedOps
}
}

try {
Expand All @@ -402,25 +393,30 @@ export class Executor {
"replacing transaction"
)

const txHash = await this.config.walletClient.sendTransaction(
this.config.legacyTransactions
? {
...newRequest,
gasPrice: newRequest.maxFeePerGas,
maxFeePerGas: undefined,
maxPriorityFeePerGas: undefined,
type: "legacy",
accessList: undefined
}
: newRequest
)
const txHash = await this.sendHandleOpsTransaction({
txParam,
opts
})

opsToBundle.map((opToBundle) => {
const op = deriveUserOperation(opToBundle.mempoolUserOperation)
//const txHash = await this.config.walletClient.sendTransaction(
// this.config.legacyTransactions
// ? {
// ...newRequest,
// gasPrice: newRequest.maxFeePerGas,
// maxFeePerGas: undefined,
// maxPriorityFeePerGas: undefined,
// type: "legacy",
// accessList: undefined
// }
// : newRequest
//)

opsToBundle.map(({ entryPoint, mempoolUserOperation }) => {
const op = deriveUserOperation(mempoolUserOperation)
const chainId = this.config.publicClient.chain?.id
const opHash = getUserOperationHash(
op,
opToBundle.entryPoint,
entryPoint,
chainId as number
)

Expand Down Expand Up @@ -489,6 +485,7 @@ export class Executor {

childLogger.warn({ error: e }, "error replacing transaction")
this.markWalletProcessed(transactionInfo.executor)

return { status: "failed" }
}
}
Expand Down Expand Up @@ -525,10 +522,19 @@ export class Executor {
await Promise.all(promises)
}

async sendHandleOpsTransaction(
userOps: PackedUserOperation[],
isUserOpVersion06: boolean,
entryPoint: Address,
async sendHandleOpsTransaction({
txParam,
opts
}: {
txParam:
| {
type: "default"
ops: PackedUserOperation[]
isUserOpVersion06: boolean
entryPoint: Address
}
| { type: "compressed"; compressedOps: CompressedUserOperation[] }

opts:
| {
gasPrice: bigint
Expand All @@ -546,17 +552,31 @@ export class Executor {
gas: bigint
nonce: number
}
) {
}) {
let data: Hex
let to: Address

if (txParam.type === "default") {
const { isUserOpVersion06, ops, entryPoint } = txParam
data = encodeFunctionData({
abi: isUserOpVersion06 ? EntryPointV06Abi : EntryPointV07Abi,
functionName: "handleOps",
args: [ops, opts.account.address]
})
to = entryPoint
} else {
const { compressedOps } = txParam
const compressionHandler = this.getCompressionHandler()
data = createCompressedCalldata(
compressedOps,
compressionHandler.perOpInflatorId
)
to = compressionHandler.bundleBulkerAddress
}

const request =
await this.config.walletClient.prepareTransactionRequest({
to: entryPoint,
data: encodeFunctionData({
abi: isUserOpVersion06
? EntryPointV06Abi
: EntryPointV07Abi,
functionName: "handleOps",
args: [userOps, opts.account.address]
}),
data,
...opts
})

Expand Down Expand Up @@ -881,12 +901,15 @@ export class Executor {
)
) as PackedUserOperation[]

transactionHash = await this.sendHandleOpsTransaction(
userOps,
isUserOpVersion06,
entryPoint,
transactionHash = await this.sendHandleOpsTransaction({
txParam: {
type: "default",
ops: userOps,
isUserOpVersion06,
entryPoint
},
opts
)
})

opsWithHashToBundle.map(({ userOperationHash }) => {
this.eventManager.emitSubmitted(
Expand Down Expand Up @@ -1156,17 +1179,12 @@ export class Executor {
}
)

// need to use sendTransaction to target BundleBulker's fallback
transactionHash = await this.config.walletClient.sendTransaction({
account: wallet,
to: compressionHandler.bundleBulkerAddress,
data: createCompressedCalldata(
compressedOpsToBundle,
compressionHandler.perOpInflatorId
),
gas: gasLimit,
nonce: nonce,
...gasOptions
transactionHash = await this.sendHandleOpsTransaction({
txParam: {
type: "compressed",
compressedOps: compressedOpsToBundle
},
opts: { ...gasOptions, gas: gasLimit, account: wallet, nonce }
})

opsToBundle.map(({ userOperationHash }) => {
Expand Down
24 changes: 24 additions & 0 deletions src/executor/executorManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -823,15 +823,37 @@ export class ExecutorManager {
reason: string
): Promise<void> {
let replaceResult: ReplaceTransactionResult | undefined = undefined

try {
replaceResult = await this.executor.replaceTransaction(txInfo)
} finally {
this.metrics.replacedTransactions
.labels({ reason, status: replaceResult?.status || "failed" })
.inc()
}

if (replaceResult.status === "failed") {
txInfo.userOperationInfos.map((opInfo) => {
const userOperation = deriveUserOperation(
opInfo.mempoolUserOperation
)

this.eventManager.emitDropped(
opInfo.userOperationHash,
"Failed to replace transaction"
)

this.logger.warn(
{
userOperation: JSON.stringify(userOperation, (_k, v) =>
typeof v === "bigint" ? v.toString() : v
),
userOpHash: opInfo.userOperationHash,
reason
},
"user operation rejected"
)

this.mempool.removeSubmitted(opInfo.userOperationHash)
})

Expand All @@ -842,6 +864,7 @@ export class ExecutorManager {

return
}

if (replaceResult.status === "potentially_already_included") {
this.logger.info(
{ oldTxHash: txInfo.transactionHash, reason },
Expand Down Expand Up @@ -872,6 +895,7 @@ export class ExecutorManager {
.map((ni) => ni.userOperationHash)
.includes(info.userOperationHash)
)

const matchingOps = txInfo.userOperationInfos.filter((info) =>
newTxInfo.userOperationInfos
.map((ni) => ni.userOperationHash)
Expand Down
1 change: 0 additions & 1 deletion src/types/mempool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ export type TransactionInfo = {
transactionRequest: {
account: Account
to: Address
data: Hex
gas: bigint
chain: Chain
maxFeePerGas: bigint
Expand Down

0 comments on commit 8a1b83d

Please sign in to comment.