Skip to content

Commit

Permalink
feat: support parsing erc-4337 transactions
Browse files Browse the repository at this point in the history
  • Loading branch information
hzhu committed Aug 19, 2024
1 parent 16e4b79 commit 373d143
Show file tree
Hide file tree
Showing 4 changed files with 399 additions and 56 deletions.
13 changes: 6 additions & 7 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { SupportedChainId } from "./types";

export const SETTLER_ABI = [
export const SETTLER_META_TXN_ABI = [
{
inputs: [
{
Expand All @@ -27,13 +27,10 @@ export const SETTLER_ABI = [
stateMutability: "nonpayable",
type: "function",
},
];
] as const;

export const FUNCTION_SELECTORS = { EXECUTE_META_TXN: "0xfd3ad6d4" };

export const NATIVE_TOKEN_ADDRESS =
"0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";

export const NATIVE_SYMBOL_BY_CHAIN_ID: { [key in SupportedChainId]: string } =
{
1: "ETH", // Ethereum
Expand All @@ -45,6 +42,8 @@ export const NATIVE_SYMBOL_BY_CHAIN_ID: { [key in SupportedChainId]: string } =
43114: "AVAX", // Avalanche
};

export const MULTICALL3_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976CA11";
export const NATIVE_TOKEN_ADDRESS = `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`;

export const MULTICALL3_ADDRESS = `0xcA11bde05977b3631167028862bE2a173976CA11`;

export const NATIVE_ETH_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
export const ERC_4337_ENTRY_POINT = `0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789`;
60 changes: 42 additions & 18 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,30 @@ import {
decodeFunctionData,
} from "viem";
import {
SETTLER_ABI,
MULTICALL3_ADDRESS,
FUNCTION_SELECTORS,
ERC_4337_ENTRY_POINT,
NATIVE_TOKEN_ADDRESS,
SETTLER_META_TXN_ABI,
NATIVE_SYMBOL_BY_CHAIN_ID,
} from "./constants";
import {
transferLogs,
isChainIdSupported,
extractNativeTransfer,
calculateNativeTransfer,
parseSmartContractWalletTx,
} from "./utils";
import type { Hash, Chain, Address, Transport, PublicClient } from "viem";
import type { TraceTransactionSchema } from "./types";

export async function parseSwap({
publicClient,
transactionHash: hash,
smartContractWallet,
}: {
publicClient: PublicClient<Transport, Chain>;
transactionHash: Address;
smartContractWallet?: Address;
}) {
const chainId = await publicClient.getChainId();

Expand All @@ -48,7 +52,11 @@ export async function parseSwap({

const { from: taker, value, to } = transaction;

const nativeTransferAmount = extractNativeTransfer(trace, taker);
const isToERC4337 = to === ERC_4337_ENTRY_POINT.toLowerCase();

const nativeAmountToTaker = calculateNativeTransfer(trace, {
recipient: taker,
});

const transactionReceipt = await publicClient.getTransactionReceipt({ hash });

Expand All @@ -59,20 +67,35 @@ export async function parseSwap({
transactionReceipt,
});

if (isToERC4337) {
if (!smartContractWallet) {
throw new Error(
"This is an ERC-4337 transaction. You must provide a smart contract wallet address to 0x-parser."
);
}

return parseSmartContractWalletTx({
logs,
trace,
chainId,
smartContractWallet,
});
}

const fromTaker = logs.filter(
(log) => log.from.toLowerCase() === taker.toLowerCase()
);

let input = fromTaker.length ? fromTaker[0] : logs[0];

let output =
nativeTransferAmount === "0"
nativeAmountToTaker === "0"
? logs.find((log) => {
return log.to.toLowerCase() === taker.toLowerCase();
})
: {
symbol: NATIVE_SYMBOL_BY_CHAIN_ID[chainId],
amount: nativeTransferAmount,
amount: nativeAmountToTaker,
address: NATIVE_TOKEN_ADDRESS,
};

Expand All @@ -82,41 +105,42 @@ export async function parseSwap({
data: transaction.input,
});

const { args: settlerArgs } = decodeFunctionData<any[]>({
abi: SETTLER_ABI,
const { args: settlerArgs } = decodeFunctionData({
abi: SETTLER_META_TXN_ABI,
data: multicallArgs[0][1].callData,
});

const takerForGaslessApprovalSwap =
settlerArgs[0].recipient.toLowerCase() as Address;

const nativeTransferAmount = extractNativeTransfer(
trace,
takerForGaslessApprovalSwap
);
const nativeAmountToTaker = calculateNativeTransfer(trace, {
recipient: takerForGaslessApprovalSwap,
});

if (nativeTransferAmount === "0") {
if (nativeAmountToTaker === "0") {
output = output = logs[logs.length - 1];
} else {
output = {
symbol: NATIVE_SYMBOL_BY_CHAIN_ID[chainId],
amount: nativeTransferAmount,
amount: nativeAmountToTaker,
address: NATIVE_TOKEN_ADDRESS,
};
}
}

if (transaction.input.startsWith(FUNCTION_SELECTORS.EXECUTE_META_TXN)) {
const { args } = decodeFunctionData<any[]>({
abi: SETTLER_ABI,
const { args } = decodeFunctionData({
abi: SETTLER_META_TXN_ABI,
data: transaction.input,
});

const { 3: msgSender } = args;

const nativeTransferAmount = extractNativeTransfer(trace, msgSender);
const nativeAmountToTaker = calculateNativeTransfer(trace, {
recipient: msgSender,
});

if (nativeTransferAmount === "0") {
if (nativeAmountToTaker === "0") {
output = logs[logs.length - 1];
const takerReceived = logs.filter(
(log) => log.to.toLowerCase() === msgSender.toLowerCase()
Expand All @@ -138,7 +162,7 @@ export async function parseSwap({
} else {
output = {
symbol: NATIVE_SYMBOL_BY_CHAIN_ID[chainId],
amount: nativeTransferAmount,
amount: nativeAmountToTaker,
address: NATIVE_TOKEN_ADDRESS,
};
}
Expand Down
Loading

0 comments on commit 373d143

Please sign in to comment.