Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sync Speedrun with last version Scaffold Stark #163

Merged
merged 7 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 0 additions & 13 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,17 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

DESIRED_COMMIT="46e0ec032956f0e7cbe0330f32b6b31eff824087"

cd packages/snfoundry/local-devnet

LAST_COMMIT=$(git log -1 --format="%H")

if [ "$LAST_COMMIT" != "$DESIRED_COMMIT" ]; then
echo "FAIL: Last local-devnet commit ($LAST_COMMIT) is not the desired ($DESIRED_COMMIT)."
exit 1
fi

cd -

npm run format:check
6 changes: 3 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# Contributing to Scaffold-Stark

Thank you for your interest in contributing to Scaffold-Stark! Your support enhances this StarkNet-focused framework that bridges smart contract integration with web applications.
Thank you for your interest in contributing to Scaffold-Stark! Your support enhances this Starknet-focused framework that bridges smart contract integration with web applications.

## About the Project

**Scaffold-Stark** provides a full DApp development template, offering seamless integration of StarkNet smart contracts with web applications. **SpeedrunStark.com** offers interactive challenges that serve to practice your Cairo and StarkNet skills, learn how to use the provided hooks, and launch your applications swiftly with potential rewards.
**Scaffold-Stark** provides a full DApp development template, offering seamless integration of Starket smart contracts with web applications. **SpeedrunStark.com** offers interactive challenges that serve to practice your Cairo and Starknet skills, learn how to use the provided hooks, and launch your applications swiftly with potential rewards.

## Project Vision

Our goal is to simplify the DApp development and learning process, enabling developers to launch applications efficiently while understanding the intricacies of StarkNet.
Our goal is to simplify the DApp development and learning process, enabling developers to launch applications efficiently while understanding the intricacies of Starknet.

## How to Get Involved

Expand Down
31 changes: 31 additions & 0 deletions packages/nextjs/app/api/price/[symbol]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
export async function GET(
_: Request,
{ params: { symbol } }: { params: { symbol: string } },
) {
let apiUrl = "";
if (symbol === "ETH") {
apiUrl =
"https://api.coingecko.com/api/v3/simple/price?ids=ethereum&vs_currencies=usd";
} else if (symbol === "STRK") {
apiUrl =
"https://api.coingecko.com/api/v3/simple/price?ids=starknet&vs_currencies=usd";
} else {
return Response.json({
ethereum: { usd: 0 },
starknet: { usd: 0 },
});
}
try {
const response = await fetch(apiUrl);
if (!response.ok) {
throw new Error(`coingecko response status: ${response.status}`);
}
const json = await response.json();
return Response.json(json);
} catch (e) {
return Response.json({
ethereum: { usd: 0 },
starknet: { usd: 0 },
});
}
}
31 changes: 15 additions & 16 deletions packages/nextjs/app/debug/_components/contract/Array.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ import { replacer } from "~~/utils/scaffold-stark/common";
import { ContractInput } from "./ContractInput";
import { Abi } from "abi-wan-kanabi";
import { parseGenericType } from "~~/utils/scaffold-stark";
import { FormErrorMessageState } from "./utilsDisplay";

type ArrayProps = {
abi: Abi;
abiParameter: AbiParameter;
parentForm: Record<string, any> | undefined;
setParentForm: (form: Record<string, any>) => void;
parentStateObjectKey: string;
setFormErrorMessage: Dispatch<SetStateAction<string | null>>;
setFormErrorMessage: Dispatch<SetStateAction<FormErrorMessageState>>;
};

export const ArrayInput = ({
Expand Down Expand Up @@ -67,23 +68,21 @@ export const ArrayInput = ({
| Record<string, any>
| ((arg: Record<string, any>) => void),
) => {
let nextInputObject: Record<string, any> = nextInputRecipe;
// if we find a function (a.k.a setState recipe), we run it to generate the next state based on recpe, else just use the object passed in
const nextInputObject: Record<string, any> =
typeof nextInputRecipe === "function"
? nextInputRecipe(parentForm!)
: nextInputRecipe;

// set state recipe function, handle
if (typeof nextInputRecipe === "function") {
nextInputObject = nextInputRecipe(parentForm!);
}

const currentInputArray = { ...inputArr };

// we do some nasty workaround
currentInputArray[index] =
nextInputObject?.[`input_${index}`] || null;

setInputArr(currentInputArray);
setInputArr((currentInputArray: any) => {
return {
...currentInputArray,
[index]: nextInputObject?.[index] || null,
};
});
}}
form={inputArr[index]}
stateObjectKey={`input_${index}`}
form={inputArr}
stateObjectKey={index}
paramType={
{
name: `${abiParameter.name}[${index}]`,
Expand Down
21 changes: 18 additions & 3 deletions packages/nextjs/app/debug/_components/contract/ContractInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,17 @@
import { Dispatch, SetStateAction } from "react";
import { InputBase, IntegerInput } from "~~/components/scaffold-stark";
import { AbiParameter } from "~~/utils/scaffold-stark/contract";
import { displayType } from "./utilsDisplay";
import {
addError,
clearError,
displayType,
FormErrorMessageState,
} from "./utilsDisplay";
import {
isCairoArray,
isCairoBigInt,
isCairoInt,
isCairoTuple,
isCairoType,
isCairoU256,
} from "~~/utils/scaffold-stark";
Expand All @@ -21,7 +27,7 @@ type ContractInputProps = {
form: Record<string, any> | undefined;
stateObjectKey: string;
paramType: AbiParameter;
setFormErrorMessage: Dispatch<SetStateAction<string | null>>;
setFormErrorMessage: Dispatch<SetStateAction<FormErrorMessageState>>;
};

export const ContractInput = ({
Expand Down Expand Up @@ -58,6 +64,11 @@ export const ContractInput = ({
setFormErrorMessage={setFormErrorMessage}
/>
);
}

// we prio tuples here to avoid wrong input
else if (isCairoTuple(paramType.type)) {
return <InputBase {...inputProps} />;
} else if (
isCairoInt(paramType.type) ||
isCairoBigInt(paramType.type) ||
Expand All @@ -68,7 +79,11 @@ export const ContractInput = ({
{...inputProps}
variant={paramType.type}
onError={(errMessage: string | null) =>
setFormErrorMessage(errMessage)
setFormErrorMessage((prev) => {
if (!!errMessage)
return addError(prev, "intError" + stateObjectKey, errMessage);
return clearError(prev, "intError" + stateObjectKey);
})
}
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { Abi } from "abi-wan-kanabi";
import { Address } from "@starknet-react/chains";
import { useReadContract } from "@starknet-react/core";
import { BlockNumber } from "starknet";
import { displayTxResult } from "./utilsDisplay";
import { decodeContractResponse } from "./utilsDisplay";
import { useTheme } from "next-themes";

type DisplayVariableProps = {
Expand Down Expand Up @@ -85,7 +85,13 @@ export const DisplayVariable = ({
showAnimation ? "bg-warning rounded-sm animate-pulse-fast" : ""
}`}
>
{displayTxResult(result, false, abiFunction?.outputs)}
{decodeContractResponse({
resp: result,
abi,
functionOutputs: abiFunction?.outputs,
asText: true,
showAsString: true,
})}
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@ import { useState, useRef, useEffect } from "react";
import { Abi } from "abi-wan-kanabi";
import { Address } from "@starknet-react/chains";
import {
displayTxResult,
getFunctionInputKey,
getInitialFormState,
getParsedContractFunctionArgs,
getArgsAsStringInputFromForm,
transformAbiFunction,
FormErrorMessageState,
isError,
getTopErrorMessage,
decodeContractResponse,
} from "~~/app/debug/_components/contract";
import { AbiFunction } from "~~/utils/scaffold-stark/contract";
import { BlockNumber } from "starknet";
import { useReadContract } from "@starknet-react/core";
import { useContract, useReadContract } from "@starknet-react/core";
import { ContractInput } from "./ContractInput";

type ReadOnlyFunctionFormProps = {
Expand All @@ -30,15 +33,21 @@ export const ReadOnlyFunctionForm = ({
getInitialFormState(abiFunction),
);
const [inputValue, setInputValue] = useState<any | undefined>(undefined);
const [formErrorMessage, setFormErrorMessage] = useState<string | null>(null);
const [formErrorMessage, setFormErrorMessage] =
useState<FormErrorMessageState>({});
const lastForm = useRef(form);

const { contract: contractInstance } = useContract({
abi,
address: contractAddress,
});

const { isFetching, data, refetch, error } = useReadContract({
address: contractAddress,
functionName: abiFunction.name,
abi: [...abi],
args: inputValue || [],
enabled: !!inputValue,
enabled: !!inputValue && !!contractInstance,
blockIdentifier: "pending" as BlockNumber,
});

Expand Down Expand Up @@ -66,8 +75,7 @@ export const ReadOnlyFunctionForm = ({
});

const handleRead = () => {
const newInputValue = getParsedContractFunctionArgs(form, false, true);

const newInputValue = getArgsAsStringInputFromForm(form);
if (JSON.stringify(form) !== JSON.stringify(lastForm.current)) {
setInputValue(newInputValue);
lastForm.current = form;
Expand All @@ -87,23 +95,28 @@ export const ReadOnlyFunctionForm = ({
<div className="bg-input text-sm px-4 py-1.5 break-words">
<p className="font-bold m-0 mb-1">Result:</p>
<pre className="whitespace-pre-wrap break-words">
{displayTxResult(data, false, abiFunction?.outputs)}
{decodeContractResponse({
resp: data,
abi,
functionOutputs: abiFunction?.outputs,
asText: true,
})}
</pre>
</div>
)}
</div>

<div
className={`flex ${
formErrorMessage &&
isError(formErrorMessage) &&
"tooltip before:content-[attr(data-tip)] before:right-[-10px] before:left-auto before:transform-none"
}`}
data-tip={`${formErrorMessage}`}
data-tip={`${getTopErrorMessage(formErrorMessage)}`}
>
<button
className="btn bg-gradient-dark btn-sm shadow-none border-none text-white"
onClick={handleRead}
disabled={(inputValue && isFetching) || !!formErrorMessage}
disabled={(inputValue && isFetching) || isError(formErrorMessage)}
>
{inputValue && isFetching && (
<span className="loading loading-spinner loading-xs"></span>
Expand Down
9 changes: 6 additions & 3 deletions packages/nextjs/app/debug/_components/contract/Struct.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ import { AbiEnum, AbiStruct } from "~~/utils/scaffold-stark/contract";
import { replacer } from "~~/utils/scaffold-stark/common";
import { ContractInput } from "./ContractInput";
import { Abi } from "abi-wan-kanabi";
import { addError, clearError, FormErrorMessageState } from "./utilsDisplay";

type StructProps = {
abi?: Abi;
parentForm: Record<string, any> | undefined;
setParentForm: (form: Record<string, any>) => void;
parentStateObjectKey: string;
abiMember?: AbiStruct | AbiEnum;
setFormErrorMessage: Dispatch<SetStateAction<string | null>>;
setFormErrorMessage: Dispatch<SetStateAction<FormErrorMessageState>>;
};

export const Struct = ({
Expand Down Expand Up @@ -51,9 +52,11 @@ export const Struct = ({

// check for enum validity
if (values.filter((item) => (item || "").length > 0).length > 1) {
setFormErrorMessage("Enums can only have one defined value");
setFormErrorMessage((prev) =>
addError(prev, "enumError", "Enums can only have one active value"),
);
} else {
setFormErrorMessage(null);
setFormErrorMessage((prev) => clearError(prev, "enumError"));
}
}

Expand Down
20 changes: 17 additions & 3 deletions packages/nextjs/app/debug/_components/contract/TxReceipt.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
CheckCircleIcon,
DocumentDuplicateIcon,
} from "@heroicons/react/24/outline";
import { displayTxResult } from "~~/app/debug/_components/contract";
import { decodeContractResponse } from "~~/app/debug/_components/contract";

export const TxReceipt = (
txResult:
Expand All @@ -28,7 +28,14 @@ export const TxReceipt = (
/>
) : (
<CopyToClipboard
text={displayTxResult(txResult, false) as string}
text={
decodeContractResponse({
resp: txResult,
abi: [],
functionOutputs: [],
asText: true,
}) as string
}
onCopy={() => {
setTxResultCopied(true);
setTimeout(() => {
Expand All @@ -49,7 +56,14 @@ export const TxReceipt = (
<strong>Transaction Receipt</strong>
</div>
<div className="collapse-content overflow-auto bg-transparent rounded-t-none rounded-3xl">
<pre className="text-xs pt-4">{displayTxResult(txResult, false)}</pre>
<pre className="text-xs pt-4">
{decodeContractResponse({
resp: txResult,
abi: [],
functionOutputs: [],
asText: true,
})}
</pre>
</div>
</div>
</div>
Expand Down
Loading
Loading