Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
rouzwelt committed Dec 10, 2024
1 parent 22ad8db commit c99dfc6
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 23 deletions.
5 changes: 5 additions & 0 deletions src/abis.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { parseAbi } from "viem";

/**
* Minimal ABI for ERC20 contract only including Transfer event
*/
Expand Down Expand Up @@ -45,6 +47,7 @@ export const orderbookAbi = [
"function multicall(bytes[] calldata data) external returns (bytes[] memory results)",
`function takeOrders2(${TakeOrdersConfigV3} memory config) external returns (uint256 totalInput, uint256 totalOutput)`,
`function clear2(${OrderV3} memory aliceOrder, ${OrderV3} memory bobOrder, ${ClearConfig} calldata clearConfig, ${SignedContextV1}[] memory aliceSignedContext, ${SignedContextV1}[] memory bobSignedContext) external`,
`event TakeOrderV2(address sender, ${TakeOrderConfigV3} config, uint256 input, uint256 output)`,
] as const;

/**
Expand Down Expand Up @@ -89,3 +92,5 @@ export const DefaultArbEvaluable = {
store: "0x" + "0".repeat(40),
bytecode: "0x",
} as const;

export const TakeOrderV2EventAbi = parseAbi([orderbookAbi[13]]);
98 changes: 75 additions & 23 deletions src/error.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
import { BigNumber } from "ethers";
import { isDeepStrictEqual } from "util";
import { RawTx, ViemClient } from "./types";
import { TakeOrderV2EventAbi } from "./abis";
// @ts-ignore
import { abi as obAbi } from "../test/abis/OrderBook.json";
// @ts-ignore
Expand All @@ -17,6 +19,7 @@ import {
FeeCapTooLowError,
decodeErrorResult,
TransactionReceipt,
decodeFunctionData,
ExecutionRevertedError,
InsufficientFundsError,
TransactionNotFoundError,
Expand Down Expand Up @@ -80,35 +83,33 @@ export function errorSnapshot(
receipt: TransactionReceipt;
rawtx: RawTx;
signerBalance: BigNumber;
frontrun?: string;
},
): string {
const message = [header];
if (err instanceof BaseError) {
if (err.shortMessage) message.push("Reason: " + err.shortMessage);
if (err.name) message.push("Error: " + err.name);
if (err.details) {
message.push("Details: " + err.details);
if (
message.some(
(v) => v.includes("unknown reason") || v.includes("execution reverted"),
)
) {
const { raw, decoded } = parseRevertError(err);
if (decoded) {
message.push("Error Name: " + decoded.name);
if (decoded.args.length) {
message.push("Error Args: " + JSON.stringify(decoded.args));
}
} else if (raw.data) {
message.push("Error Raw Data: " + raw.data);
} else if (data) {
const gasErr = checkGasIssue(data.receipt, data.rawtx, data.signerBalance);
if (gasErr) {
message.push("Gas Error: " + gasErr);
}
} else {
message.push("Comment: Found no additional info");
if (err.details) message.push("Details: " + err.details);
if (message.some((v) => v.includes("unknown reason") || v.includes("execution reverted"))) {
const { raw, decoded } = parseRevertError(err);
if (decoded) {
message.push("Error Name: " + decoded.name);
if (decoded.args.length) {
message.push("Error Args: " + JSON.stringify(decoded.args));
}
} else if (raw.data) {
message.push("Error Raw Data: " + raw.data);
} else if (data) {
const gasErr = checkGasIssue(data.receipt, data.rawtx, data.signerBalance);
if (gasErr) {
message.push("Gas Error: " + gasErr);
}
} else {
message.push("Comment: Found no additional info");
}
if (data?.frontrun) {
message.push("Actual Cause: " + data.frontrun);
}
}
} else if (err instanceof Error) {
Expand Down Expand Up @@ -177,6 +178,7 @@ export async function handleRevert(
receipt: TransactionReceipt,
rawtx: RawTx,
signerBalance: BigNumber,
orderbook: `0x${string}`,
): Promise<{
err: any;
nodeError: boolean;
Expand Down Expand Up @@ -207,10 +209,16 @@ export async function handleRevert(
" and simulation failed to find the revert reason, please try to simulate the tx manualy for more details";
return { err: msg, nodeError: false, snapshot: msg };
} catch (err: any) {
let frontrun: string | undefined = await hasFrontrun(viemClient, rawtx, receipt, orderbook);
if (frontrun) {
frontrun = `current transaction with hash ${
receipt.transactionHash
} has been actually frontrun by transaction with hash ${frontrun}`;
}
return {
err,
nodeError: containsNodeError(err),
snapshot: errorSnapshot(header, err, { receipt, rawtx, signerBalance }),
snapshot: errorSnapshot(header, err, { receipt, rawtx, signerBalance, frontrun }),
rawRevertError: parseRevertError(err),
};
}
Expand Down Expand Up @@ -304,3 +312,47 @@ export function checkGasIssue(receipt: TransactionReceipt, rawtx: RawTx, signerB
}
return undefined;
}

/**
* Checks if the given transaction has been frontrun by another transaction.
* This is done by checking previouse transaction on the same block that emitted
* the target event with the same TakeOrderConfigV3 struct.
*/
export async function hasFrontrun(
viemClient: ViemClient,
rawtx: RawTx,
receipt: TransactionReceipt,
orderbook: `0x${string}`,
) {
try {
const orderConfig = (() => {
try {
const result = decodeFunctionData({
abi: arbRp4Abi,
data: rawtx.data,
}) as any;
return result?.args?.[1]?.orders?.[0];
} catch {
return undefined;
}
})();
if (orderConfig) {
const logs = await viemClient.getLogs({
event: TakeOrderV2EventAbi[0],
address: orderbook,
blockHash: receipt.blockHash,
});
const otherLogs = logs.filter(
(v) =>
receipt.transactionIndex > v.transactionIndex &&
v.transactionHash.toLowerCase() !== receipt.transactionHash.toLowerCase(),
);
if (otherLogs.length) {
for (const log of otherLogs) {
if (isDeepStrictEqual(log.args.config, orderConfig)) return log.transactionHash;
}
}
}
} catch {}
return undefined;
}
2 changes: 2 additions & 0 deletions src/tx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ export async function handleReceipt(
receipt,
rawtx,
signerBalance,
orderbook.address as `0x${string}`,
);
if (result.snapshot.includes("simulation failed to find the revert reason")) {
// wait at least 90s before simulating the revert tx
Expand All @@ -299,6 +300,7 @@ export async function handleReceipt(
receipt,
rawtx,
signerBalance,
orderbook.address as `0x${string}`,
);
} else {
return result;
Expand Down

0 comments on commit c99dfc6

Please sign in to comment.