diff --git a/package.json b/package.json index 4321fdce..2fa98d54 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "scripts": { "chain": "yarn workspace @ss-2/snfoundry chain", "deploy": "yarn workspace @ss-2/snfoundry deploy", - "deploy:reset": "yarn workspace @ss-2/snfoundry deploy:reset", + "deploy:no-reset": "yarn workspace @ss-2/snfoundry deploy --no-reset", "test": "yarn workspace @ss-2/snfoundry test", "compile": "yarn workspace @ss-2/snfoundry compile", "start": "yarn workspace @ss-2/nextjs dev", diff --git a/packages/nextjs/hooks/scaffold-stark/useScaffoldMultiWriteContract.ts b/packages/nextjs/hooks/scaffold-stark/useScaffoldMultiWriteContract.ts index 16728c86..a119737e 100644 --- a/packages/nextjs/hooks/scaffold-stark/useScaffoldMultiWriteContract.ts +++ b/packages/nextjs/hooks/scaffold-stark/useScaffoldMultiWriteContract.ts @@ -11,7 +11,7 @@ import { UseScaffoldWriteConfig, } from "~~/utils/scaffold-stark/contract"; import { useSendTransaction, useNetwork, Abi } from "@starknet-react/core"; -import { InvocationsDetails } from "starknet"; +import { Contract as StarknetJsContract, InvocationsDetails } from "starknet"; import { notification } from "~~/utils/scaffold-stark"; import { useMemo } from "react"; import { useTransactor } from "./useTransactor"; @@ -34,45 +34,53 @@ export const useScaffoldMultiWriteContract = < const { chain } = useNetwork(); const sendTxnWrapper = useTransactor(); - const parsedCalls = useMemo(() => { - if (calls) { - return calls.map((call) => { - const functionName = call.functionName; - const contractName = call.contractName; - const unParsedArgs = call.args as any[]; - const contract = contracts?.[targetNetwork.network]?.[ - contractName as ContractName - ] as Contract; + // TODO: commented out in case we need it again + // const parsedCalls = useMemo(() => { + // if (calls) { + // return calls.map((call) => { + // const functionName = call.functionName; + // const contractName = call.contractName; + // const unParsedArgs = call.args as any[]; + // const contract = contracts?.[targetNetwork.network]?.[ + // contractName as ContractName + // ] as Contract; - const abiFunction = getFunctionsByStateMutability( - contract?.abi || [], - "external", - ).find((fn) => fn.name === functionName); + // // TODO: see if we still need this + // // const abiFunction = getFunctionsByStateMutability( + // // contract?.abi || [], + // // "external", + // // ).find((fn) => fn.name === functionName); - return { - contractAddress: contract?.address, - entrypoint: functionName, - calldata: - abiFunction && unParsedArgs && contract - ? parseFunctionParams({ - abiFunction, - isRead: false, - inputs: unParsedArgs as any[], - isReadArgsParsing: false, - abi: contract.abi, - }).flat() - : [], - }; - }); - } else { - return []; - } - }, [calls]); + // // we convert to starknetjs contract instance here since deployed data may be undefined if contract is not deployed + // const contractInstance = new StarknetJsContract( + // contract.abi, + // contract.address, + // ); + + // return { + // ...contractInstance.populate(functionName, unParsedArgs as any[]), + + // // TODO: see if we still need this + // // calldata: + // // abiFunction && unParsedArgs && contract + // // ? parseFunctionParams({ + // // abiFunction, + // // isRead: false, + // // inputs: unParsedArgs as any[], + // // isReadArgsParsing: false, + // // abi: contract.abi, + // // }).flat() + // // : [], + // }; + // }); + // } else { + // return []; + // } + // }, [calls, targetNetwork.network]); // TODO add custom options - const sendTransactionInstance = useSendTransaction({ - calls: parsedCalls, - }); + + const sendTransactionInstance = useSendTransaction({}); const sendContractWriteTx = async () => { if (!chain?.id) { @@ -86,8 +94,37 @@ export const useScaffoldMultiWriteContract = < if (sendTransactionInstance.sendAsync) { try { + // we just parse calldata here so that it will only parse on demand. + // use IIFE pattern + const parsedCalls = (() => { + if (calls) { + return calls.map((call) => { + const functionName = call.functionName; + const contractName = call.contractName; + const unParsedArgs = call.args as any[]; + const contract = contracts?.[targetNetwork.network]?.[ + contractName as ContractName + ] as Contract; + // we convert to starknetjs contract instance here since deployed data may be undefined if contract is not deployed + const contractInstance = new StarknetJsContract( + contract.abi, + contract.address, + ); + + return contractInstance.populate( + functionName, + unParsedArgs as any[], + ); + }); + } else { + return []; + } + })(); + // setIsMining(true); - return await sendTxnWrapper(() => sendTransactionInstance.sendAsync()); + return await sendTxnWrapper(() => + sendTransactionInstance.sendAsync(parsedCalls), + ); } catch (e: any) { throw e; } finally { diff --git a/packages/nextjs/hooks/scaffold-stark/useScaffoldReadContract.ts b/packages/nextjs/hooks/scaffold-stark/useScaffoldReadContract.ts index 511b2c94..fae3d663 100644 --- a/packages/nextjs/hooks/scaffold-stark/useScaffoldReadContract.ts +++ b/packages/nextjs/hooks/scaffold-stark/useScaffoldReadContract.ts @@ -29,7 +29,7 @@ export const useScaffoldReadContract = < address: deployedContract?.address, abi: deployedContract?.abi, watch: true, - args, + args: args || [], enabled: args && (!Array.isArray(args) || !args.some((arg) => arg === undefined)), blockIdentifier: "pending" as BlockNumber, diff --git a/packages/nextjs/hooks/scaffold-stark/useScaffoldWriteContract.ts b/packages/nextjs/hooks/scaffold-stark/useScaffoldWriteContract.ts index 1c082912..7632c9e8 100644 --- a/packages/nextjs/hooks/scaffold-stark/useScaffoldWriteContract.ts +++ b/packages/nextjs/hooks/scaffold-stark/useScaffoldWriteContract.ts @@ -1,4 +1,4 @@ -import { useEffect, useMemo } from "react"; +import { useCallback, useEffect, useMemo } from "react"; import { useTargetNetwork } from "./useTargetNetwork"; import { useDeployedContractInfo, @@ -12,8 +12,14 @@ import { parseFunctionParams, UseScaffoldWriteConfig, } from "~~/utils/scaffold-stark/contract"; -import { useSendTransaction, useNetwork, Abi } from "@starknet-react/core"; +import { + useSendTransaction, + useNetwork, + Abi, + useContract, +} from "@starknet-react/core"; import { notification } from "~~/utils/scaffold-stark"; +import { Contract as StarknetJsContract } from "starknet"; type UpdatedArgs = Parameters< ReturnType["sendAsync"] @@ -45,90 +51,97 @@ export const useScaffoldWriteContract = < [deployedContractData?.abi, functionName], ); - const parsedParams = useMemo(() => { - if (args && abiFunction && deployedContractData) { - const parsed = parseFunctionParams({ - abiFunction, - abi: deployedContractData.abi, - inputs: args as any[], - isRead: false, - isReadArgsParsing: false, - }).flat(Infinity); - return parsed; - } - return []; - }, [args, abiFunction, deployedContractData]); + // TODO: see if we need this bit later + // const parsedParams = useMemo(() => { + // if (args && abiFunction && deployedContractData) { + // const parsed = parseFunctionParams({ + // abiFunction, + // abi: deployedContractData.abi, + // inputs: args as any[], + // isRead: false, + // isReadArgsParsing: true, + // }).flat(Infinity); + // return parsed; + // } + // return []; + // }, [args, abiFunction, deployedContractData]); - const sendTransactionInstance = useSendTransaction({ - calls: deployedContractData - ? [ - { - contractAddress: deployedContractData?.address, - entrypoint: functionName, - calldata: parsedParams, - }, - ] - : [], - }); + // leave blank for now since default args will be called by the trigger function anyway + const sendTransactionInstance = useSendTransaction({}); - const sendContractWriteTx = async (params?: { - args?: UseScaffoldWriteConfig["args"]; - }) => { - // if no args supplied, use the one supplied from hook - let newArgs = params?.args; - if (!newArgs) { - newArgs = args; - } + const sendContractWriteTx = useCallback( + async (params?: { + args?: UseScaffoldWriteConfig["args"]; + }) => { + // if no args supplied, use the one supplied from hook + let newArgs = params?.args; + if (Object.keys(newArgs || {}).length <= 0) { + newArgs = args; + } - if (!deployedContractData) { - console.error( - "Target Contract is not deployed, did you forget to run `yarn deploy`?", + if (!deployedContractData) { + console.error( + "Target Contract is not deployed, did you forget to run `yarn deploy`?", + ); + return; + } + if (!chain?.id) { + console.error("Please connect your wallet"); + return; + } + if (chain?.id !== targetNetwork.id) { + console.error("You are on the wrong network"); + return; + } + + // TODO: see if we need this back, keeping this here + // let newParsedParams = + // newArgs && abiFunction && deployedContractData + // ? parseFunctionParams({ + // abiFunction, + // abi: deployedContractData.abi, + // inputs: newArgs as any[], + // isRead: false, + // isReadArgsParsing: false, + // }) + // : parsedParams; + + // we convert to starknetjs contract instance here since deployed data may be undefined if contract is not deployed + const contractInstance = new StarknetJsContract( + deployedContractData.abi, + deployedContractData.address, ); - return; - } - if (!chain?.id) { - console.error("Please connect your wallet"); - return; - } - if (chain?.id !== targetNetwork.id) { - console.error("You are on the wrong network"); - return; - } - let newParsedParams = - newArgs && abiFunction && deployedContractData - ? parseFunctionParams({ - abiFunction, - abi: deployedContractData.abi, - inputs: args as any[], - isRead: false, - isReadArgsParsing: false, - }).flat(Infinity) - : parsedParams; - const newCalls = [ - { - contractAddress: deployedContractData.address, - entrypoint: functionName, - calldata: newParsedParams, - }, - ]; + const newCalls = deployedContractData + ? [contractInstance.populate(functionName, newArgs as any[])] + : []; - if (sendTransactionInstance.sendAsync) { - try { - // setIsMining(true); - return await sendTxnWrapper(() => - sendTransactionInstance.sendAsync(newCalls as any[]), - ); - } catch (e: any) { - throw e; - } finally { - // setIsMining(false); + if (sendTransactionInstance.sendAsync) { + try { + // setIsMining(true); + return await sendTxnWrapper(() => + sendTransactionInstance.sendAsync(newCalls as any[]), + ); + } catch (e: any) { + throw e; + } finally { + // setIsMining(false); + } + } else { + notification.error("Contract writer error. Try again."); + return; } - } else { - notification.error("Contract writer error. Try again."); - return; - } - }; + }, + [ + args, + chain?.id, + deployedContractData, + functionName, + sendTransactionInstance, + sendTxnWrapper, + targetNetwork.id, + ], + ); return { ...sendTransactionInstance, diff --git a/packages/nextjs/package.json b/packages/nextjs/package.json index 1ceae600..c1ecdfc8 100644 --- a/packages/nextjs/package.json +++ b/packages/nextjs/package.json @@ -16,8 +16,8 @@ }, "dependencies": { "@heroicons/react": "^2.1.3", - "@next/font": "^14.2.1", "@radix-ui/react-icons": "1.3.0", + "@next/font": "^14.2.1", "@radix-ui/themes": "2.0.3", "@starknet-io/types-js": "^0.7.7", "@starknet-react/chains": "^3.0.0", diff --git a/packages/nextjs/utils/scaffold-stark/contract.ts b/packages/nextjs/utils/scaffold-stark/contract.ts index 6a8fb479..3052ec88 100644 --- a/packages/nextjs/utils/scaffold-stark/contract.ts +++ b/packages/nextjs/utils/scaffold-stark/contract.ts @@ -458,10 +458,7 @@ const decodeParamsWithType = (paramType: string, param: any): unknown => { : `Err(${parseParamWithType(error, result.unwrap(), isRead)})`; }, param); } else if (isCairoContractAddress(paramType)) { - return tryParsingParamReturnObject( - getChecksumAddress, - `0x${param.toString(16)}`, - ); + return tryParsingParamReturnObject(validateAndParseAddress, param); } else if (isCairoU256(paramType)) { return tryParsingParamReturnObject(uint256.uint256ToBN, param); } else if (isCairoByteArray(paramType)) { @@ -783,13 +780,11 @@ export function parseFunctionParams({ args: inputs, }); - console.debug({ formattedInputs }); - formattedInputs.forEach((inputItem) => { const { type: inputType, value: inputValue } = inputItem; parsedInputs.push( - parseParamWithType(inputType, inputValue, isRead, !!isReadArgsParsing), + deepParseValues(inputValue, isRead, inputType, !!isReadArgsParsing), ); }); @@ -841,7 +836,10 @@ function formatInputForParsing({ _formatInput(structValue, argIndex, variants as AbiParameter[]), ]; }); - return { type: structName, value: { variant: Object.fromEntries } }; + return { + type: structName, + value: { variant: Object.fromEntries(formattedEntries) }, + }; } const { members } = structDef as AbiStruct; diff --git a/packages/snfoundry/package.json b/packages/snfoundry/package.json index 888509fa..84ebb295 100644 --- a/packages/snfoundry/package.json +++ b/packages/snfoundry/package.json @@ -4,7 +4,7 @@ "scripts": { "chain": "starknet-devnet --seed 0 --account-class cairo1", "deploy": "ts-node scripts-ts/helpers/deploy-wrapper.ts", - "deploy:reset": "ts-node scripts-ts/helpers/deploy-wrapper.ts --reset", + "deploy:no-reset": "yarn workspace @ss-2/snfoundry deploy --no-reset", "test": "cd contracts && snforge test", "test-eslint": "node eslint-contract-name/eslint-plugin-contract-names.test.js", "compile": "cd contracts && scarb build", diff --git a/packages/snfoundry/scripts-ts/deploy-contract.ts b/packages/snfoundry/scripts-ts/deploy-contract.ts index 8448ce41..c5ab2417 100644 --- a/packages/snfoundry/scripts-ts/deploy-contract.ts +++ b/packages/snfoundry/scripts-ts/deploy-contract.ts @@ -32,10 +32,11 @@ const argv = yargs(process.argv.slice(2)) demandOption: true, }) .option("reset", { - alias: "r", + alias: "nr", type: "boolean", - description: "Reset deployments", - default: false, + description: + "(--no-reset) Do not reset deployments (keep existing deployments)", + default: true, }) .option("fee", { type: "string", @@ -295,11 +296,9 @@ const exportDeployments = () => { `../deployments/${networkName}_latest.json` ); - let finalDeployments = resetDeployments - ? deployments - : { ...loadExistingDeployments(), ...deployments }; + const resetDeployments: boolean = argv.reset; - if (fs.existsSync(networkPath) && !resetDeployments) { + if (!resetDeployments && fs.existsSync(networkPath)) { const currentTimestamp = new Date().getTime(); fs.renameSync( networkPath, @@ -307,7 +306,11 @@ const exportDeployments = () => { ); } - fs.writeFileSync(networkPath, JSON.stringify(finalDeployments, null, 2)); + if (resetDeployments && fs.existsSync(networkPath)) { + fs.unlinkSync(networkPath); + } + + fs.writeFileSync(networkPath, JSON.stringify(deployments, null, 2)); }; export { diff --git a/packages/snfoundry/scripts-ts/helpers/deploy-wrapper.ts b/packages/snfoundry/scripts-ts/helpers/deploy-wrapper.ts index 7584c5c0..217844d8 100644 --- a/packages/snfoundry/scripts-ts/helpers/deploy-wrapper.ts +++ b/packages/snfoundry/scripts-ts/helpers/deploy-wrapper.ts @@ -13,25 +13,30 @@ interface CommandLineOptions { const argv = yargs(process.argv.slice(2)) .options({ network: { type: "string" }, - reset: { type: "boolean", default: false }, fee: { type: "string", choices: ["eth", "strk"], default: "eth" }, + reset: { + type: "boolean", + description: "Do not reset deployments (keep existing deployments)", + default: true, + }, }) .parseSync() as CommandLineOptions; // Set the NETWORK environment variable based on the --network argument process.env.NETWORK = argv.network || "devnet"; process.env.FEE_TOKEN = argv.fee || "eth"; -// Set the RESET environment variable based on the --reset flag +process.env.NO_RESET = !argv.reset ? "true" : "false"; -// Execute the deploy script -execSync( - "cd contracts && scarb build && ts-node ../scripts-ts/deploy.ts" + - " --network " + - process.env.NETWORK + - " --fee " + - process.env.FEE_TOKEN + - (argv.reset ? " --reset" : "") + - " && ts-node ../scripts-ts/helpers/parse-deployments.ts" + - " && cd ..", - { stdio: "inherit" } -); +// Execute the deploy script without the reset option +try { + execSync( + `cd contracts && scarb build && ts-node ../scripts-ts/deploy.ts` + + ` --network ${process.env.NETWORK}` + + ` --fee ${process.env.FEE_TOKEN}` + + ` --no-reset ${process.env.NO_RESET}` + + ` && ts-node ../scripts-ts/helpers/parse-deployments.ts && cd ..`, + { stdio: "inherit" } + ); +} catch (error) { + console.error("Error during deployment:", error); +} diff --git a/yarn.lock b/yarn.lock index bf580036..be9666fb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -716,15 +716,6 @@ __metadata: languageName: node linkType: hard -"@next/font@npm:^14.2.1": - version: 14.2.14 - resolution: "@next/font@npm:14.2.14" - peerDependencies: - next: "*" - checksum: 67626fcf39d90f65cc69a734ddfb04ad7af69cc3ba33ba7b4cdb749a7dd5a5cbfc09f64041a15d0dac2a53dfe756769d8b356246a954c752e4cd888e4f821ec8 - languageName: node - linkType: hard - "@next/swc-darwin-arm64@npm:14.1.3": version: 14.1.3 resolution: "@next/swc-darwin-arm64@npm:14.1.3" @@ -2231,7 +2222,6 @@ __metadata: resolution: "@ss-2/nextjs@workspace:packages/nextjs" dependencies: "@heroicons/react": ^2.1.3 - "@next/font": ^14.2.1 "@radix-ui/react-icons": 1.3.0 "@radix-ui/themes": 2.0.3 "@starknet-io/types-js": ^0.7.7