Skip to content

Commit

Permalink
Decoding calldata on the form
Browse files Browse the repository at this point in the history
  • Loading branch information
brickpop committed Jul 30, 2024
1 parent 4d2d9cd commit 770c4e7
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 8 deletions.
77 changes: 69 additions & 8 deletions components/input/calldata-form.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
import { type RawAction } from "@/utils/types";
import { type FC, useEffect, useState } from "react";
import { InputText, InputNumber, TextArea } from "@aragon/ods";
import { type Address, parseEther, isHex } from "viem";
import { InputText, InputNumber, TextArea, AlertInline } from "@aragon/ods";
import {
type Address,
parseEther,
isHex,
decodeFunctionData,
Hex,
toFunctionSelector,
AbiFunction,
toFunctionSignature,
} from "viem";
import { isAddress } from "@/utils/evm";
import { If } from "../if";
import { If, Then } from "../if";
import { PUB_CHAIN } from "@/constants";
import { useIsContract } from "@/hooks/useIsContract";
import { PleaseWaitSpinner } from "../please-wait";
import { useAbi } from "@/hooks/useAbi";
import { CallFunctionSignatureField, CallParamField } from "../proposalActions/callParamField";

interface ICalldataFormProps {
onChange: (actions: RawAction) => any;
Expand All @@ -19,6 +30,7 @@ export const CalldataForm: FC<ICalldataFormProps> = ({ onChange, onSubmit }) =>
const [calldata, setCalldata] = useState<string>("");
const [value, setValue] = useState<string>("");
const { isContract, isLoading, error: isContractError } = useIsContract(to);
const { abi, isLoading: isLoadingAbi } = useAbi((to || "") as Address);

useEffect(() => {
if (!isAddress(to)) return;
Expand All @@ -31,6 +43,24 @@ export const CalldataForm: FC<ICalldataFormProps> = ({ onChange, onSubmit }) =>
setTo(event?.target?.value as Address);
};

let decodedParams: ReturnType<typeof decodeFunctionData> | null = null;
let matchingAbiFunction: AbiFunction | null = null;
try {
decodedParams = decodeFunctionData({
abi: abi,
data: calldata as Hex,
});

for (const item of abi) {
const selector = toFunctionSelector(item);
if (calldata.startsWith(selector)) {
matchingAbiFunction = item;
}
}
} catch (_) {
//
}

return (
<div className="my-6">
<div className="mb-3 pb-3">
Expand Down Expand Up @@ -65,11 +95,7 @@ export const CalldataForm: FC<ICalldataFormProps> = ({ onChange, onSubmit }) =>
label="Calldata"
placeholder="0x..."
value={calldata}
alert={
!calldata || (isHex(calldata) && calldata.trim().length % 2 === 0)
? undefined
: { message: "The given calldata is not valid", variant: "critical" }
}
alert={resolveCalldataAlert(calldata, abi, decodedParams)}
onChange={(e) => setCalldata(e.target.value)}
/>
</div>
Expand All @@ -82,7 +108,42 @@ export const CalldataForm: FC<ICalldataFormProps> = ({ onChange, onSubmit }) =>
onKeyDown={(e) => (e.key === "Enter" ? onSubmit?.() : null)}
/>
</div>
{/* Try to decode */}
<If condition={!!calldata}>
<If condition={!!decodedParams}>
<div className="flex flex-row items-center justify-between border-b border-neutral-200 py-4">
<p className="text-md font-semibold text-neutral-800">Decoded parameters</p>
</div>

<div className="mt-4 flex flex-col gap-y-4">
<CallFunctionSignatureField functionAbi={matchingAbiFunction} />
{decodedParams?.args?.map((arg, i) => (
<div className="flex" key={i}>
<CallParamField value={arg as any} idx={i} functionAbi={matchingAbiFunction} />
</div>
))}
</div>
</If>
</If>
</If>
</div>
);
};

function resolveCalldataAlert(
calldata: string,
abi: AbiFunction[] | null,
decodedParams: {
args: readonly unknown[];
functionName: string;
} | null
): { message: string; variant: "critical" | "warning" } | undefined {
if (!calldata) return undefined;
else if (!isHex(calldata) || calldata.trim().length % 2 !== 0) {
return { message: "The given calldata is not a valid hex string", variant: "critical" };
} else if (!abi?.length) return undefined;
else if (!decodedParams) {
return { message: "The given calldata cannot be decoded using the available ABI", variant: "warning" };
}
return undefined;
}
10 changes: 10 additions & 0 deletions pages/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,16 @@ body {
font-family: "Public Sans";
}

body,
span,
p,
ul,
ol,
div {
/* Custom */
font-family: "Public Sans";
}

h1,
h2,
h3,
Expand Down

0 comments on commit 770c4e7

Please sign in to comment.