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 all 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
4 changes: 2 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ jobs:
uses: actions/checkout@master

- name: Install scarb
run: curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh | sh -s -- -v 2.8.2
run: curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh | sh -s -- -v 2.8.5

- name: Install snfoundryup
run: curl -L https://raw.githubusercontent.com/foundry-rs/starknet-foundry/master/scripts/install.sh | sh

- name: Install snforge
run: snfoundryup -v 0.30.0
run: snfoundryup -v 0.33.0

- name: Run snforge tests
run: snforge test
Expand Down
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
4 changes: 2 additions & 2 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
scarb 2.8.3
starknet-foundry 0.31.0
scarb 2.8.5
starknet-foundry 0.33.0
starknet-devnet 0.2.0
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
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ If your local starknet-devnet version is not `0.2.0`, you need to install it.
### Compatible versions

- Starknet-devnet - v0.2.0
- Scarb - v2.8.3
- Snforge - v0.31.0
- Cairo - v2.8.2
- Scarb - v2.8.5
- Snforge - v0.33.0
- Cairo - v2.8.5
- RPC - v0.7.1

Make sure you have the compatible versions otherwise refer to [Scaffold-Stark Requirements](https://github.com/Scaffold-Stark/scaffold-stark-2?.tab=readme-ov-file#requirements)
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 },
});
}
}
34 changes: 18 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,16 @@ 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>>;
isDisabled?: boolean;
};

export const ArrayInput = ({
Expand All @@ -26,6 +28,7 @@ export const ArrayInput = ({
parentStateObjectKey,
abiParameter,
setFormErrorMessage,
isDisabled,
}: ArrayProps) => {
// array in object representation
const [inputArr, setInputArr] = useState<any>({});
Expand Down Expand Up @@ -62,28 +65,27 @@ export const ArrayInput = ({
<ContractInput
abi={abi}
key={index}
isDisabled={isDisabled}
setForm={(
nextInputRecipe:
| 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
36 changes: 31 additions & 5 deletions packages/nextjs/app/debug/_components/contract/ContractInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,19 @@
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,
isCairoOption,
isCairoResult,
isCairoTuple,
isCairoType,
isCairoU256,
} from "~~/utils/scaffold-stark";
Expand All @@ -21,7 +29,8 @@ type ContractInputProps = {
form: Record<string, any> | undefined;
stateObjectKey: string;
paramType: AbiParameter;
setFormErrorMessage: Dispatch<SetStateAction<string | null>>;
setFormErrorMessage: Dispatch<SetStateAction<FormErrorMessageState>>;
isDisabled?: boolean;
};

export const ContractInput = ({
Expand All @@ -31,6 +40,7 @@ export const ContractInput = ({
stateObjectKey,
paramType,
setFormErrorMessage,
isDisabled,
}: ContractInputProps) => {
const inputProps = {
name: stateObjectKey,
Expand All @@ -56,8 +66,14 @@ export const ContractInput = ({
parentForm={form}
setParentForm={setForm}
setFormErrorMessage={setFormErrorMessage}
isDisabled={isDisabled}
/>
);
}

// we prio tuples here to avoid wrong input
else if (isCairoTuple(paramType.type)) {
return <InputBase {...inputProps} disabled={isDisabled} />;
} else if (
isCairoInt(paramType.type) ||
isCairoBigInt(paramType.type) ||
Expand All @@ -67,13 +83,22 @@ export const ContractInput = ({
<IntegerInput
{...inputProps}
variant={paramType.type}
disabled={isDisabled}
onError={(errMessage: string | null) =>
setFormErrorMessage(errMessage)
setFormErrorMessage((prev) => {
if (!!errMessage)
return addError(prev, "intError" + stateObjectKey, errMessage);
return clearError(prev, "intError" + stateObjectKey);
})
}
/>
);
} else if (isCairoType(paramType.type)) {
return <InputBase {...inputProps} />;
} else if (
isCairoType(paramType.type) &&
!isCairoResult(paramType.type) &&
!isCairoOption(paramType.type)
) {
return <InputBase {...inputProps} disabled={isDisabled} />;
} else {
return (
<Struct
Expand All @@ -87,6 +112,7 @@ export const ContractInput = ({
// @ts-ignore
(member) => member.name === paramType.type,
)}
isDisabled={isDisabled}
/>
);
}
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: false,
})}
</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
Loading
Loading