Skip to content

Commit

Permalink
add call args playground validation
Browse files Browse the repository at this point in the history
  • Loading branch information
ukorvl committed Feb 27, 2025
1 parent 4000d87 commit d8cbc7f
Show file tree
Hide file tree
Showing 15 changed files with 586 additions and 113 deletions.
10 changes: 1 addition & 9 deletions explorer_frontend/src/features/account-connector/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ createSmartAccountFx.use(async ({ privateKey, rpcUrl }) => {
{
smartAccountAddress: smartAccount.address,
faucetAddress: tokenFaucetAddress,
amount: 10,
amount: 10n,
},
client,
);
Expand Down Expand Up @@ -236,14 +236,6 @@ initializePrivateKey();

initilizeSmartAccount();

sample({
clock: sendMethodFx.doneData,
target: fetchBalanceFx,
source: $smartAccount,
filter: (smartAccount) => smartAccount !== null,
fn: (smartAccount) => smartAccount as SmartAccountV1,
});

$activeComponent.on(setActiveComponent, (_, payload) => payload);

persistSessionStorage({
Expand Down
2 changes: 1 addition & 1 deletion explorer_frontend/src/features/code/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import dayjs from "dayjs";
import { combine, sample } from "effector";
import { persist } from "effector-storage/local";
import { fetchSolidityCompiler } from "../../services/compiler";
import type { App } from "../../types";
import { playgroundRoute, playgroundWithHashRoute } from "../routing/routes/playgroundRoute";
import { getRuntimeConfigOrThrow } from "../runtime-config";
import {
Expand All @@ -25,6 +24,7 @@ import {
setCodeSnippetFx,
updateRecentProjects,
} from "./model";
import type { App } from "./types";

$code.on(changeCode, (_, x) => x);

Expand Down
2 changes: 1 addition & 1 deletion explorer_frontend/src/features/code/model.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createDomain } from "effector";
import { fetchCodeSnippet, setCodeSnippet } from "../../api/code";
import type { App } from "../../types";
import type { App } from "./types";

export const codeDomain = createDomain("code");

Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
import { expandProperty } from "inline-style-expand-shorthand";
import type { FC } from "react";
import { useStyletron } from "styletron-react";
import type { App } from "../../../../types";
import type { App } from "../../../code/types";
import { choseApp } from "../../models/base";
import { RemoveAppButton } from "../RemoveAppButton";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ import {
setValueInput,
toggleActiveKey,
} from "../../models/base.ts";
import { $callParamsValidationErrors } from "../../models/callParamsValidation.ts";
import type { CallParams } from "../../types.ts";
import { getResultDisplay } from "../../utils.tsx";
import { MethodInput } from "./MethodInput";
import { RemoveTokenButton } from "./RemoveTokenButton.tsx";
import { Result } from "./Result";
Expand All @@ -38,11 +41,18 @@ export type MethodProps = {
result?: unknown;
loading?: boolean;
txHash?: string;
params?: Record<string, unknown>;
params?: CallParams[string];
paramsHandler: (params: {
functionName: string;
paramName: string;
value: unknown;
value:
| string
| boolean
| {
type: string;
value: string;
}[];
type: string;
}) => void;
};

Expand Down Expand Up @@ -85,7 +95,11 @@ export const Method = ({
params,
}: MethodProps) => {
const [css] = useStyletron();
const [tokenBalance, valueInputs] = useUnit([$balanceToken, $valueInputs]);
const [tokenBalance, valueInputs, errors] = useUnit([
$balanceToken,
$valueInputs,
$callParamsValidationErrors,
]);
const availableTokens = [
{ token: "NIL" },
...Object.keys(tokenBalance ?? {}).map((token) => ({
Expand All @@ -96,6 +110,9 @@ export const Method = ({
const methodType = getMethodType(func);
const markerColor = getMarkerColor(methodType);
const handler = methodType === "Read" ? callMethod : sendMethod;
const functionName = func.name;
const functionValues = valueInputs.find((v) => v.functionName === functionName)?.values;
const methodErrors = errors[functionName] ?? {};

return (
<div
Expand Down Expand Up @@ -164,11 +181,13 @@ export const Method = ({
justifyContent: "center",
})}
>
{valueInputs.map((valueInput, index) => {
const usedTokens = valueInputs.map((v) => v.token);
{functionValues?.map((valueInput, index) => {
const usedTokens = functionValues.map((v) => v.token);

const availableInputTokens = availableTokens.filter(
(c) => !usedTokens.includes(c.token) || c.token === valueInput.token,
);

return (
// biome-ignore lint/correctness/useJsxKeyInIterable: can be the same for now
<div
Expand All @@ -187,19 +206,30 @@ export const Method = ({
disabled={loading}
tokens={availableInputTokens}
onChange={({ amount, token }) => {
setValueInput({ index, amount, token });
setValueInput({ index, amount, token, functionName });
}}
value={valueInput}
/>
<RemoveTokenButton index={index} kind={BUTTON_KIND.secondary} />
<RemoveTokenButton
index={index}
kind={BUTTON_KIND.secondary}
functionName={functionName}
/>
</div>
);
})}
<Button
onClick={() => {
addValueInput(availableTokens.map((c) => c.token));
addValueInput({
availableTokens: availableTokens.map((c) => c.token),
functionName,
});
}}
disabled={valueInputs.map((v) => v.token).length >= availableTokens.length}
disabled={
functionValues
? functionValues.map((v) => v.token).length >= availableTokens.length
: false
}
kind={BUTTON_KIND.tertiary}
overrides={{
Root: {
Expand All @@ -216,6 +246,7 @@ export const Method = ({
)}
{func.inputs.map((input, index) => {
const key = input.name || `${index}`;

return (
<MethodInput
key={key}
Expand All @@ -224,6 +255,7 @@ export const Method = ({
params={params}
paramName={key}
input={input}
error={methodErrors[key]}
/>
);
})}
Expand Down Expand Up @@ -261,7 +293,7 @@ export const Method = ({
wordBreak: "break-all",
})}
>
{String(result)}
{getResultDisplay(result)}
</ParagraphMedium>
</Result>
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,54 @@
import { FormControl, Input, LabelMedium } from "@nilfoundation/ui-kit";
import type { AbiInternalType, AbiParameter } from "abitype";
import { COLORS, FormControl, Input, LabelMedium } from "@nilfoundation/ui-kit";
import type { AbiParameter } from "abitype";
import type { FormControlOverrides } from "baseui/form-control";
import type { InputOverrides } from "baseui/input";
import type { FC } from "react";
import { useStyletron } from "styletron-react";
import type { CallParams } from "../../types";
import { isAbiParameterTuple } from "../../utils";

type MethodInputProps = {
input: AbiParameter;
methodName: string;
paramName: string;
params?: Record<string, unknown>;
paramsHandler: (params: { functionName: string; paramName: string; value: unknown }) => void;
params?: CallParams[string];
paramsHandler: (params: {
functionName: string;
paramName: string;
value:
| string
| boolean
| {
type: string;
value: string;
}[];
type: string;
}) => void;
error?: string | null | Record<string, string | null>;
};

const isAbiParameterTuple = (
input: AbiParameter,
): input is {
type: "tuple" | `tuple[${string}]`;
name?: string | undefined;
internalType?: AbiInternalType | undefined;
components: readonly AbiParameter[];
} => {
return input.type === "tuple";
const formControlOverries: FormControlOverrides = {
Caption: {
style: ({ $error }) => ({
marginTop: "8px",
...($error ? { color: COLORS.red200 } : {}),
}),
},
};

const inputOverrides: InputOverrides = {
Root: {
style: ({ $error }) => ({
...($error
? { boxShadow: `0px 0px 0px 2px ${COLORS.gray900}, 0px 0px 0px 4px ${COLORS.red200}` }
: {}),
}),
},
Input: {
style: ({ $error }) => ({
...($error ? { color: COLORS.red200 } : {}),
}),
},
};

const MethodInput: FC<MethodInputProps> = ({
Expand All @@ -28,6 +57,7 @@ const MethodInput: FC<MethodInputProps> = ({
paramsHandler,
methodName,
paramName,
error,
}: MethodInputProps) => {
const { type, name } = input;
const [css] = useStyletron();
Expand All @@ -46,21 +76,42 @@ const MethodInput: FC<MethodInputProps> = ({
})}
>
{input.components.map(({ name = "", type }, i) => {
const componentValue = params ? (params[paramName] as AbiParameter) : "";
const inputValue = componentValue ? componentValue.name : "";
const inputValue = params?.[paramName]
? (params[paramName].value as {
type: string;
value: string;
}[])
: [];
const componentValue = inputValue[i] ?? { type, value: "" };
const errs = error as Record<string, string | null> | null;
const err = errs ? errs[i.toString()] : null;

console.log("ERR", error, err);

return (
// biome-ignore lint/suspicious/noArrayIndexKey: <explanation>
<div key={i}>
<FormControl label={name} caption={type}>
<FormControl
label={name}
caption={type}
overrides={formControlOverries}
error={err}
>
<Input
value={inputValue}
value={componentValue.value}
onChange={(e) => {
const value = e.target.value;
const mergedValue = { ...componentValue, [name]: value };
paramsHandler({ functionName: methodName, paramName, value: mergedValue });
const mergedValue = [...inputValue];
mergedValue[i] = { type, value };
paramsHandler({
functionName: methodName,
paramName,
value: mergedValue,
type: input.type,
});
}}
placeholder={type === "address" ? "0x..." : ""}
overrides={inputOverrides}
/>
</FormControl>
</div>
Expand All @@ -69,15 +120,24 @@ const MethodInput: FC<MethodInputProps> = ({
</div>
</>
) : (
<FormControl label={name} caption={type}>
<Input
value={params?.[paramName] ? String(params[paramName]) : ""}
onChange={(e) => {
const value = e.target.value;
paramsHandler({ functionName: methodName, paramName, value });
}}
/>
</FormControl>
<>
<FormControl
label={name}
caption={type}
error={error as string | null}
overrides={formControlOverries}
>
<Input
value={params?.[paramName] ? String(params[paramName].value) : ""}
onChange={(e) => {
const value = e.target.value;
paramsHandler({ functionName: methodName, paramName, value, type: input.type });
}}
placeholder={type === "address" ? "0x..." : ""}
overrides={inputOverrides}
/>
</FormControl>
</>
)}
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import { DeleteIcon } from "../DeleteIcon.tsx";
type RemoveTokenButtonProps = {
index: number;
kind?: BUTTON_KIND;
functionName: string;
};

export const RemoveTokenButton: FC<RemoveTokenButtonProps> = ({
index,
kind = BUTTON_KIND.text,
functionName,
}) => {
return (
<StatefulTooltip content="Remove token" showArrow={false} placement="bottom" popoverMargin={6}>
Expand All @@ -20,7 +22,7 @@ export const RemoveTokenButton: FC<RemoveTokenButtonProps> = ({
kind={kind}
onClick={(e) => {
e.stopPropagation();
removeValueInput(index);
removeValueInput({ functionName, index });
}}
overrides={{
Root: {
Expand Down
Loading

0 comments on commit d8cbc7f

Please sign in to comment.