Skip to content

Commit

Permalink
add value, calls always an array
Browse files Browse the repository at this point in the history
  • Loading branch information
karooolis committed Oct 27, 2024
1 parent 8597f4d commit fa4c130
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -82,23 +82,21 @@ export function TransactionTableRow({ row }: { row: Row<ObservedTransaction> })
<div className="flex items-start gap-x-4">
<h3 className="w-[45px] flex-shrink-0 text-2xs font-bold uppercase">Inputs</h3>

{(Array.isArray(data.calls) && data.calls.length > 0) || data.calls ? (
{data.calls.length > 0 ? (
<div className="flex w-full flex-col gap-y-4">
{(Array.isArray(data.calls) ? data.calls : [data.calls]).map((call, idx) => {
return (
<div key={idx} className="min-w-0 flex-grow border border-white/20 p-2 pt-1">
<span className="text-xs">{call.functionName}:</span>
{call.args?.map((arg, idx) => (
<div key={idx} className="flex">
<span className="flex-shrink-0 text-xs text-white/60">arg {idx + 1}:</span>
<span className="ml-2 break-all text-xs">
{typeof arg === "object" && arg !== null ? JSON.stringify(arg, null, 2) : String(arg)}
</span>
</div>
))}
</div>
);
})}
{data.calls.map((call, idx) => (
<div key={idx} className="min-w-0 flex-grow border border-white/20 p-2 pt-1">
<span className="text-xs">{call.functionName}:</span>
{call.args?.map((arg, argIdx) => (
<div key={argIdx} className="flex">
<span className="flex-shrink-0 text-xs text-white/60">arg {argIdx + 1}:</span>
<span className="ml-2 break-all text-xs">
{typeof arg === "object" && arg !== null ? JSON.stringify(arg, null, 2) : String(arg)}
</span>
</div>
))}
</div>
))}
</div>
) : (
<p className="text-2xs uppercase text-white/60">No inputs</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export const columns = [
return (
<div className="flex items-center">
<div className="flex gap-2">
{(Array.isArray(calls) ? calls : [calls]).map(({ functionName }, idx) => (
{calls.map(({ functionName }, idx) => (
<Badge variant="secondary" key={idx}>
{functionName}
</Badge>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { useChain } from "../../../../hooks/useChain";
import { useWorldAbiQuery } from "../../../../queries/useWorldAbiQuery";
import { store as worldStore } from "../store";
import { userOperationEventAbi } from "./abis";
import { getCalls } from "./helpers";
import { getDecodedUserOperationCalls } from "./helpers";

export function TransactionsWatcher() {
const { id: chainId } = useChain();
Expand Down Expand Up @@ -58,13 +58,19 @@ export function TransactionsWatcher() {
});

const { functionName: decodedFunctionName, args: decodedArgs } = decodedSmartAccountCall;
const calls = getCalls(decodedFunctionName, decodedArgs, transaction);
const calls = getDecodedUserOperationCalls({
functionName: decodedFunctionName,
decodedArgs,
transaction,
}).filter(({ to }) => to && getAddress(to) === getAddress(worldAddress)); // TODO: filter earlier
if (calls.length === 0) return;

const logs = parseEventLogs({
abi: [...abi, userOperationEventAbi],
logs: receipt.logs,
});

console.log("calls", calls);
console.log("RECEIPT", receipt);

setTransaction({
hash,
Expand All @@ -76,11 +82,11 @@ export function TransactionsWatcher() {
receipt,
logs,
value: transaction.value,
status: receipt.status, // TODO: correct status check
status: receipt.status,
error: undefined, // TODO: transactionError as BaseError,
});
},
[abi, setTransaction],
[abi, setTransaction, worldAddress],
);

const handleUserOperations = useCallback(
Expand All @@ -94,14 +100,12 @@ export function TransactionsWatcher() {
data: transaction.input,
});

// decodedEntryPointCall.args[0] is an array of UserOperation<"0.7">
// decodedEntryPointCall.args[1] is `beneficiary`
const userOperations = decodedEntryPointCall.args[0] as never as UserOperation<"0.7">[];
for (const userOperation of userOperations) {
handleUserOperation({ hash, writeId, timestamp, receipt, transaction, userOperation });
}
},
[abi, observerWrites, handleUserOperation, wagmiConfig],
[abi, handleUserOperation, wagmiConfig],
);

const handleAuthenticTransaction = useCallback(
Expand All @@ -116,7 +120,7 @@ export function TransactionsWatcher() {
timestamp: bigint;
transaction: Transaction;
}) => {
if (!abi) return;
if (!abi || !transaction.to) return;

let functionName: string | undefined;
let args: readonly unknown[] | undefined;
Expand All @@ -138,11 +142,13 @@ export function TransactionsWatcher() {
timestamp,
transaction,
status: "pending",
calls: {
to: transaction.to,
functionName,
args,
},
calls: [
{
to: transaction.to,
functionName,
args,
},
],
value: transaction.value,
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,41 @@
import { Address, Hex, Transaction, decodeFunctionData } from "viem";
import { DecodedUserOperationCall } from "../../../../../../observer/messages";
import { doomWorldAbi } from "./abis";

export function getCalls(decodedFunctionName: string, decodedArgs: readonly unknown[], transaction: Transaction) {
if (decodedFunctionName === "execute") {
export function getDecodedUserOperationCalls({
functionName,
decodedArgs,
transaction,
}: {
functionName: string;
decodedArgs: readonly unknown[];
transaction: Transaction;
}) {
if (functionName === "execute") {
const target = decodedArgs[0] as Address;
// const value = decodedArgs[1]; // TODO: handle value
const value = decodedArgs[1] as bigint;
const data = decodedArgs[2] as Hex;

return getCall(target, data, transaction);
} else if (decodedFunctionName === "executeBatch") {
return (decodedArgs[0] as { target: Address; data: Hex }[]).map((worldFunction) =>
getCall(worldFunction.target, worldFunction.data, transaction),
return [getDecodedUserOperationCall({ target, data, transaction, value })];
} else if (functionName === "executeBatch") {
return (decodedArgs[0] as { target: Address; data: Hex; value: bigint }[]).map(({ target, data, value }) =>
getDecodedUserOperationCall({ target, data, transaction, value }),
);
}
return [];
}

function getCall(target: Address, data: Hex, transaction: Transaction) {
function getDecodedUserOperationCall({
target,
data,
transaction,
value,
}: {
target: Address;
data: Hex;
transaction: Transaction;
value: bigint;
}): DecodedUserOperationCall {
let functionName: string | undefined;
let args: readonly unknown[] | undefined;
try {
Expand All @@ -31,5 +50,6 @@ function getCall(target: Address, data: Hex, transaction: Transaction) {
to: target,
functionName,
args,
value,
};
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Address, BaseError, Hex, Log, Transaction, TransactionReceipt } from "viem";
import { useStore } from "zustand";
import { useMemo } from "react";
import { Message, UserOperationCall } from "../../../../../../observer/messages";
import { DecodedUserOperationCall, Message } from "../../../../../../observer/messages";
import { type Write, store as observerStore } from "../../../../../../observer/store";
import { store as worldStore } from "../store";

Expand All @@ -11,7 +11,7 @@ export type ObservedTransaction = {
from?: Address;
timestamp?: bigint;
transaction?: Transaction;
calls: UserOperationCall | UserOperationCall[];
calls: DecodedUserOperationCall[];
value?: bigint;
receipt?: TransactionReceipt;
status: "pending" | "success" | "reverted" | "rejected" | "unknown";
Expand Down
33 changes: 15 additions & 18 deletions packages/explorer/src/observer/decorator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ import { Account, Chain, Client, Hex, Transport, WalletActions } from "viem";
import { BundlerActions, sendUserOperation, waitForUserOperationReceipt } from "viem/account-abstraction";
import { waitForTransactionReceipt, writeContract } from "viem/actions";
import { getAction } from "viem/utils";
import { isDefined } from "@latticexyz/common/utils";
import { createBridge } from "./bridge";
import { ReceiptSummary } from "./common";
import { UserOperationCall } from "./messages";
import { DecodedUserOperationCall } from "./messages";

export type WaitForTransaction = (hash: Hex) => Promise<ReceiptSummary>;

Expand All @@ -31,22 +30,20 @@ export function observer({ explorerUrl = "http://localhost:13690", waitForTransa
const writeId = `${client.uid}-${++writeCounter}`;
const write = getAction(client, sendUserOperation, "sendUserOperation")(args);

let calls: UserOperationCall[] = [];
let calls: DecodedUserOperationCall[] = [];
if ("calls" in args && args.calls) {
calls = args.calls
.map((call) => {
// TODO: make this nicer
if (call && typeof call === "object" && "functionName" in call && "args" in call && "to" in call) {
return {
to: call.to,
functionName: call.functionName,
args: call.args,
} as UserOperationCall;
}

return undefined;
})
.filter(isDefined);
calls = args.calls.map((call) => {
return {
// @ts-expect-error TODO: fix
to: call.to,
// @ts-expect-error TODO: fix
functionName: call.functionName,
// @ts-expect-error TODO: fix
args: call.args,
// @ts-expect-error TODO: fix
value: call.value,
};
});
}

emit("write", {
Expand Down Expand Up @@ -87,9 +84,9 @@ export function observer({ explorerUrl = "http://localhost:13690", waitForTransa
to: args.address,
functionName: args.functionName,
args: (args.args ?? []) as never,
value: args.value,
},
],
value: args.value, // TODO: how to handle value?
});
Promise.allSettled([write]).then(([result]) => {
emit("write:result", { ...result, writeId });
Expand Down
9 changes: 5 additions & 4 deletions packages/explorer/src/observer/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ import { UserOperationReceipt } from "viem/account-abstraction";
import { ReceiptSummary } from "./common";

// TODO: fix type, move elsewhere
export type UserOperationCall = {
to: Address | null;
export type DecodedUserOperationCall = {
to?: Address;
functionName: string;
args: unknown;
args: unknown[];
value?: bigint;
};

export type Messages = {
Expand All @@ -18,7 +19,7 @@ export type Messages = {
write: {
writeId: string;
from: Address;
calls: UserOperationCall[];
calls: DecodedUserOperationCall[];
value?: bigint;
};
"write:result": PromiseSettledResult<Hash> & { writeId: string };
Expand Down
5 changes: 2 additions & 3 deletions packages/explorer/src/observer/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Address, Hash } from "viem";
import { createStore } from "zustand/vanilla";
import { relayChannelName } from "./common";
import { debug } from "./debug";
import { Message, MessageType, UserOperationCall } from "./messages";
import { DecodedUserOperationCall, Message, MessageType } from "./messages";

export type Write = {
writeId: string;
Expand All @@ -13,8 +13,7 @@ export type Write = {
userOpHash?: Hash;
from: Address;
time: number;
calls: UserOperationCall | UserOperationCall[];
value?: bigint;
calls: DecodedUserOperationCall[];
events: Message<Exclude<MessageType, "ping">>[];
error?: Error;
};
Expand Down

0 comments on commit fa4c130

Please sign in to comment.