Skip to content

Commit

Permalink
Update and Sync ch-0 with last version Scaffold Stark (#165)
Browse files Browse the repository at this point in the history
Co-authored-by: metalboyrick <[email protected]>
  • Loading branch information
Nadai2010 and metalboyrick authored Dec 10, 2024
1 parent 1f70bd0 commit 51a4201
Show file tree
Hide file tree
Showing 42 changed files with 3,111 additions and 1,860 deletions.
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
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ To ensure the proper functioning of scaffold-stark, your local `Scarb` version m
scarb --version
```

If your local Scarb version is not `2.8.3`, you need to install it.
If your local Scarb version is not `2.8.5`, you need to install it.

- Install Scarb `2.8.3` via `asdf` ([instructions](https://docs.swmansion.com/scarb/download.html#install-via-asdf)).
- Install Scarb `2.8.5` via `asdf` ([instructions](https://docs.swmansion.com/scarb/download.html#install-via-asdf)).

### Starknet Foundry version

Expand All @@ -57,16 +57,16 @@ To ensure the proper functioning of the tests on scaffold-stark, your Starknet F
snforge --version
```

If your Starknet Foundry version is not `0.31.0`, you need to install it.
If your Starknet Foundry version is not `0.33.0`, you need to install it.

- Install Starknet Foundry `0.31.0` via `asdf` ([instructions](https://foundry-rs.github.io/starknet-foundry/getting-started/installation.html#installation-via-asdf)).
- Install Starknet Foundry `0.33.0` via `asdf` ([instructions](https://foundry-rs.github.io/starknet-foundry/getting-started/installation.html#installation-via-asdf)).

### 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

0 comments on commit 51a4201

Please sign in to comment.