From da3107fad2fbd7b4fb2edb6374b7d377ba61bac5 Mon Sep 17 00:00:00 2001 From: Eduardo Date: Thu, 11 Apr 2024 12:52:41 -0500 Subject: [PATCH 1/6] update: split deploy --- packages/snfoundry/scripts_js/deploy.js | 117 +---------------- .../snfoundry/scripts_js/deploy_contract.js | 121 ++++++++++++++++++ 2 files changed, 122 insertions(+), 116 deletions(-) create mode 100644 packages/snfoundry/scripts_js/deploy_contract.js diff --git a/packages/snfoundry/scripts_js/deploy.js b/packages/snfoundry/scripts_js/deploy.js index 2cee6253..2c4a12db 100644 --- a/packages/snfoundry/scripts_js/deploy.js +++ b/packages/snfoundry/scripts_js/deploy.js @@ -7,122 +7,7 @@ const { TransactionStatus } = require("starknet"); const { hash } = require("starknet"); const { CallData } = require("starknet-dev"); - -const networkName = argv.network; - -const { provider, deployer } = networks[networkName]; -const deployContract = async ( - constructorArgs, - contractName, - exportContractName -) => { - const compiledContractCasm = JSON.parse( - fs - .readFileSync( - path.resolve( - __dirname, - `../contracts/target/dev/contracts_${contractName}.compiled_contract_class.json` - ) - ) - .toString("ascii") - ); - - const compiledContractSierra = JSON.parse( - fs - .readFileSync( - path.resolve( - __dirname, - `../contracts/target/dev/contracts_${contractName}.contract_class.json` - ) - ) - .toString("ascii") - ); - - let classHash; - let existingClass; - let contractAddress; - - const precomputedClassHash = hash.computeSierraContractClassHash( - compiledContractSierra - ); - const contractCalldata = new CallData(compiledContractSierra.abi); - const constructorCalldata = constructorArgs - ? contractCalldata.compile("constructor", constructorArgs) - : []; - console.log("Deploying Contract ", contractName); - - let totalFee = 0n; - - try { - const { suggestedMaxFee: estimatedFeeDeclare } = - await deployer.estimateDeclareFee( - { - contract: compiledContractSierra, - casm: compiledContractCasm, - }, - {} - ); - totalFee = estimatedFeeDeclare * 2n; - } catch (e) { - const { suggestedMaxFee: estimatedFeeDeploy } = - await deployer.estimateDeployFee({ - classHash: precomputedClassHash, - constructorCalldata, - }); - totalFee = estimatedFeeDeploy * 2n; - } - - try { - const tryDeclareAndDeploy = await deployer.declareAndDeploy( - { - contract: compiledContractSierra, - casm: compiledContractCasm, - constructorCalldata, - }, - { - maxFee: totalFee * 20n, // this optional max fee serves when error AccountValidation Failed or small fee on public networks , try 5n , 10n, 20n, 50n, 100n - } - ); - const debug = await provider.waitForTransaction( - tryDeclareAndDeploy.deploy.transaction_hash, - { - successStates: [TransactionStatus.ACCEPTED_ON_L2], - // retryInterval: 10000, // we can retry in 10 seconds - } - ); - classHash = tryDeclareAndDeploy.declare.class_hash; - existingClass = await provider.getClassByHash(classHash); - contractAddress = tryDeclareAndDeploy.deploy.address; - contractAddress = "0x" + contractAddress.slice(2).padStart(64, "0"); - } catch (e) { - console.log("Error", e); - } - console.log("Deployed contract ", contractName, " at: ", contractAddress); - const chainIdPath = path.resolve( - __dirname, - `../deployments/${networkName}.json` - ); - let deployments = {}; - if (fs.existsSync(chainIdPath)) { - deployments = JSON.parse(fs.readFileSync(chainIdPath).toString()); - } - - let finalContractName = exportContractName || contractName; - - deployments[finalContractName] = { - classHash: classHash, - address: contractAddress, - contract: contractName, - }; - - fs.writeFileSync(chainIdPath, JSON.stringify(deployments, null, 2)); - - return { - classHash: classHash, - abi: JSON.stringify(existingClass.abi), - address: contractAddress, - }; -}; +const deployContract = require("./deploy_contract"); const deployScript = async () => { const { diff --git a/packages/snfoundry/scripts_js/deploy_contract.js b/packages/snfoundry/scripts_js/deploy_contract.js new file mode 100644 index 00000000..b6ec06e2 --- /dev/null +++ b/packages/snfoundry/scripts_js/deploy_contract.js @@ -0,0 +1,121 @@ +const fs = require("fs"); +const path = require("path"); +const networks = require("./helpers/networks"); +const {hash, CallData, TransactionStatus} = require("starknet"); +const networkName = argv.network; + +const {provider, deployer} = networks[networkName]; +const deployContract = async ( + constructorArgs, + contractName, + exportContractName +) => { + const compiledContractCasm = JSON.parse( + fs + .readFileSync( + path.resolve( + __dirname, + `../contracts/target/dev/contracts_${contractName}.compiled_contract_class.json` + ) + ) + .toString("ascii") + ); + + const compiledContractSierra = JSON.parse( + fs + .readFileSync( + path.resolve( + __dirname, + `../contracts/target/dev/contracts_${contractName}.contract_class.json` + ) + ) + .toString("ascii") + ); + + let classHash; + let existingClass; + let contractAddress; + + const precomputedClassHash = hash.computeSierraContractClassHash( + compiledContractSierra + ); + const contractCalldata = new CallData(compiledContractSierra.abi); + const constructorCalldata = constructorArgs + ? contractCalldata.compile("constructor", constructorArgs) + : []; + console.log("Deploying Contract ", contractName); + + let totalFee = 0n; + + try { + const {suggestedMaxFee: estimatedFeeDeclare} = + await deployer.estimateDeclareFee( + { + contract: compiledContractSierra, + casm: compiledContractCasm, + }, + {} + ); + totalFee = estimatedFeeDeclare * 2n; + } catch (e) { + const {suggestedMaxFee: estimatedFeeDeploy} = + await deployer.estimateDeployFee({ + classHash: precomputedClassHash, + constructorCalldata, + }); + totalFee = estimatedFeeDeploy * 2n; + } + + try { + const tryDeclareAndDeploy = await deployer.declareAndDeploy( + { + contract: compiledContractSierra, + casm: compiledContractCasm, + constructorCalldata, + }, + { + maxFee: totalFee * 20n, // this optional max fee serves when error AccountValidation Failed or small fee on public networks , try 5n , 10n, 20n, 50n, 100n + } + ); + const debug = await provider.waitForTransaction( + tryDeclareAndDeploy.deploy.transaction_hash, + { + successStates: [TransactionStatus.ACCEPTED_ON_L2], + // retryInterval: 10000, // we can retry in 10 seconds + } + ); + classHash = tryDeclareAndDeploy.declare.class_hash; + existingClass = await provider.getClassByHash(classHash); + contractAddress = tryDeclareAndDeploy.deploy.address; + contractAddress = "0x" + contractAddress.slice(2).padStart(64, "0"); + } catch (e) { + console.log("Error", e); + } + console.log("Deployed contract ", contractName, " at: ", contractAddress); + const chainIdPath = path.resolve( + __dirname, + `../deployments/${networkName}.json` + ); + let deployments = {}; + if (fs.existsSync(chainIdPath)) { + deployments = JSON.parse(fs.readFileSync(chainIdPath).toString()); + } + + let finalContractName = exportContractName || contractName; + + deployments[finalContractName] = { + classHash: classHash, + address: contractAddress, + contract: contractName, + }; + + fs.writeFileSync(chainIdPath, JSON.stringify(deployments, null, 2)); + + return { + classHash: classHash, + abi: JSON.stringify(existingClass.abi), + address: contractAddress, + }; +}; + +export default deployContract \ No newline at end of file From c3ff555834e51dae3a1a613ae40104a9b5339fac Mon Sep 17 00:00:00 2001 From: Eduardo Date: Mon, 15 Apr 2024 12:33:09 -0500 Subject: [PATCH 2/6] fix: provider --- .../ScaffoldStarkAppWithProviders.tsx | 15 +- .../nextjs/contracts/deployedContracts.ts | 532 +++++++++++++++++- packages/nextjs/services/web3/provider.ts | 19 + 3 files changed, 551 insertions(+), 15 deletions(-) create mode 100644 packages/nextjs/services/web3/provider.ts diff --git a/packages/nextjs/components/ScaffoldStarkAppWithProviders.tsx b/packages/nextjs/components/ScaffoldStarkAppWithProviders.tsx index 4cee39ec..fa821d08 100644 --- a/packages/nextjs/components/ScaffoldStarkAppWithProviders.tsx +++ b/packages/nextjs/components/ScaffoldStarkAppWithProviders.tsx @@ -6,20 +6,17 @@ import { useTheme } from "next-themes"; import { Toaster } from "react-hot-toast"; import { StarknetConfig, - publicProvider, argent, braavos, useInjectedConnectors, starkscan, - jsonRpcProvider, - starknetChainId, } from "@starknet-react/core"; import { Header } from "~~/components/Header"; import { Footer } from "~~/components/Footer"; import { ProgressBar } from "~~/components/scaffold-stark/ProgressBar"; import { appChains } from "~~/services/web3/connectors"; import { BurnerConnector } from "~~/services/web3/stark-burner/BurnerConnector"; -import scaffoldConfig from "~~/scaffold.config"; +import provider from "~~/services/web3/provider"; const ScaffoldStarkApp = ({ children }: { children: React.ReactNode }) => { return ( @@ -42,16 +39,6 @@ export const ScaffoldStarkAppWithProviders = ({ const isDarkMode = resolvedTheme === "dark"; const [mounted, setMounted] = useState(false); - const provider = - scaffoldConfig.rpcProviderUrl == "" - ? publicProvider() - : jsonRpcProvider({ - rpc: () => ({ - nodeUrl: scaffoldConfig.rpcProviderUrl, - chainId: starknetChainId(scaffoldConfig.targetNetworks[0].id), - }), - }); - useEffect(() => { setMounted(true); }, []); diff --git a/packages/nextjs/contracts/deployedContracts.ts b/packages/nextjs/contracts/deployedContracts.ts index 25751cee..5052ea1d 100644 --- a/packages/nextjs/contracts/deployedContracts.ts +++ b/packages/nextjs/contracts/deployedContracts.ts @@ -3,6 +3,536 @@ * You should not edit it manually or your changes might be overwritten. */ -const deployedContracts = {} as const; +const deployedContracts = { + devnet: { + Challenge0: { + address: + "0x029de5578255560287ebdad126340555672f25ff9799e2e61e6c861fa2035cec", + abi: [ + { + type: "impl", + name: "WrappedIERC721MetadataImpl", + interface_name: + "openzeppelin::token::erc721::interface::IERC721Metadata", + }, + { + type: "struct", + name: "core::byte_array::ByteArray", + members: [ + { + name: "data", + type: "core::array::Array::", + }, + { + name: "pending_word", + type: "core::felt252", + }, + { + name: "pending_word_len", + type: "core::integer::u32", + }, + ], + }, + { + type: "struct", + name: "core::integer::u256", + members: [ + { + name: "low", + type: "core::integer::u128", + }, + { + name: "high", + type: "core::integer::u128", + }, + ], + }, + { + type: "interface", + name: "openzeppelin::token::erc721::interface::IERC721Metadata", + items: [ + { + type: "function", + name: "name", + inputs: [], + outputs: [ + { + type: "core::byte_array::ByteArray", + }, + ], + state_mutability: "view", + }, + { + type: "function", + name: "symbol", + inputs: [], + outputs: [ + { + type: "core::byte_array::ByteArray", + }, + ], + state_mutability: "view", + }, + { + type: "function", + name: "token_uri", + inputs: [ + { + name: "token_id", + type: "core::integer::u256", + }, + ], + outputs: [ + { + type: "core::byte_array::ByteArray", + }, + ], + state_mutability: "view", + }, + ], + }, + { + type: "impl", + name: "Challenge0Impl", + interface_name: "contracts::challenge0::IChallenge0", + }, + { + type: "interface", + name: "contracts::challenge0::IChallenge0", + items: [ + { + type: "function", + name: "mint_item", + inputs: [ + { + name: "recipient", + type: "core::starknet::contract_address::ContractAddress", + }, + { + name: "uri", + type: "core::byte_array::ByteArray", + }, + ], + outputs: [ + { + type: "core::integer::u256", + }, + ], + state_mutability: "external", + }, + { + type: "function", + name: "token_id_counter", + inputs: [], + outputs: [ + { + type: "core::integer::u256", + }, + ], + state_mutability: "view", + }, + ], + }, + { + type: "impl", + name: "ERC721Impl", + interface_name: "openzeppelin::token::erc721::interface::IERC721", + }, + { + type: "struct", + name: "core::array::Span::", + members: [ + { + name: "snapshot", + type: "@core::array::Array::", + }, + ], + }, + { + type: "enum", + name: "core::bool", + variants: [ + { + name: "False", + type: "()", + }, + { + name: "True", + type: "()", + }, + ], + }, + { + type: "interface", + name: "openzeppelin::token::erc721::interface::IERC721", + items: [ + { + type: "function", + name: "balance_of", + inputs: [ + { + name: "account", + type: "core::starknet::contract_address::ContractAddress", + }, + ], + outputs: [ + { + type: "core::integer::u256", + }, + ], + state_mutability: "view", + }, + { + type: "function", + name: "owner_of", + inputs: [ + { + name: "token_id", + type: "core::integer::u256", + }, + ], + outputs: [ + { + type: "core::starknet::contract_address::ContractAddress", + }, + ], + state_mutability: "view", + }, + { + type: "function", + name: "safe_transfer_from", + inputs: [ + { + name: "from", + type: "core::starknet::contract_address::ContractAddress", + }, + { + name: "to", + type: "core::starknet::contract_address::ContractAddress", + }, + { + name: "token_id", + type: "core::integer::u256", + }, + { + name: "data", + type: "core::array::Span::", + }, + ], + outputs: [], + state_mutability: "external", + }, + { + type: "function", + name: "transfer_from", + inputs: [ + { + name: "from", + type: "core::starknet::contract_address::ContractAddress", + }, + { + name: "to", + type: "core::starknet::contract_address::ContractAddress", + }, + { + name: "token_id", + type: "core::integer::u256", + }, + ], + outputs: [], + state_mutability: "external", + }, + { + type: "function", + name: "approve", + inputs: [ + { + name: "to", + type: "core::starknet::contract_address::ContractAddress", + }, + { + name: "token_id", + type: "core::integer::u256", + }, + ], + outputs: [], + state_mutability: "external", + }, + { + type: "function", + name: "set_approval_for_all", + inputs: [ + { + name: "operator", + type: "core::starknet::contract_address::ContractAddress", + }, + { + name: "approved", + type: "core::bool", + }, + ], + outputs: [], + state_mutability: "external", + }, + { + type: "function", + name: "get_approved", + inputs: [ + { + name: "token_id", + type: "core::integer::u256", + }, + ], + outputs: [ + { + type: "core::starknet::contract_address::ContractAddress", + }, + ], + state_mutability: "view", + }, + { + type: "function", + name: "is_approved_for_all", + inputs: [ + { + name: "owner", + type: "core::starknet::contract_address::ContractAddress", + }, + { + name: "operator", + type: "core::starknet::contract_address::ContractAddress", + }, + ], + outputs: [ + { + type: "core::bool", + }, + ], + state_mutability: "view", + }, + ], + }, + { + type: "impl", + name: "OwnableImpl", + interface_name: "openzeppelin::access::ownable::interface::IOwnable", + }, + { + type: "interface", + name: "openzeppelin::access::ownable::interface::IOwnable", + items: [ + { + type: "function", + name: "owner", + inputs: [], + outputs: [ + { + type: "core::starknet::contract_address::ContractAddress", + }, + ], + state_mutability: "view", + }, + { + type: "function", + name: "transfer_ownership", + inputs: [ + { + name: "new_owner", + type: "core::starknet::contract_address::ContractAddress", + }, + ], + outputs: [], + state_mutability: "external", + }, + { + type: "function", + name: "renounce_ownership", + inputs: [], + outputs: [], + state_mutability: "external", + }, + ], + }, + { + type: "constructor", + name: "constructor", + inputs: [ + { + name: "owner", + type: "core::starknet::contract_address::ContractAddress", + }, + ], + }, + { + type: "event", + name: "openzeppelin::token::erc721::erc721::ERC721Component::Transfer", + kind: "struct", + members: [ + { + name: "from", + type: "core::starknet::contract_address::ContractAddress", + kind: "key", + }, + { + name: "to", + type: "core::starknet::contract_address::ContractAddress", + kind: "key", + }, + { + name: "token_id", + type: "core::integer::u256", + kind: "key", + }, + ], + }, + { + type: "event", + name: "openzeppelin::token::erc721::erc721::ERC721Component::Approval", + kind: "struct", + members: [ + { + name: "owner", + type: "core::starknet::contract_address::ContractAddress", + kind: "key", + }, + { + name: "approved", + type: "core::starknet::contract_address::ContractAddress", + kind: "key", + }, + { + name: "token_id", + type: "core::integer::u256", + kind: "key", + }, + ], + }, + { + type: "event", + name: "openzeppelin::token::erc721::erc721::ERC721Component::ApprovalForAll", + kind: "struct", + members: [ + { + name: "owner", + type: "core::starknet::contract_address::ContractAddress", + kind: "key", + }, + { + name: "operator", + type: "core::starknet::contract_address::ContractAddress", + kind: "key", + }, + { + name: "approved", + type: "core::bool", + kind: "data", + }, + ], + }, + { + type: "event", + name: "openzeppelin::token::erc721::erc721::ERC721Component::Event", + kind: "enum", + variants: [ + { + name: "Transfer", + type: "openzeppelin::token::erc721::erc721::ERC721Component::Transfer", + kind: "nested", + }, + { + name: "Approval", + type: "openzeppelin::token::erc721::erc721::ERC721Component::Approval", + kind: "nested", + }, + { + name: "ApprovalForAll", + type: "openzeppelin::token::erc721::erc721::ERC721Component::ApprovalForAll", + kind: "nested", + }, + ], + }, + { + type: "event", + name: "openzeppelin::introspection::src5::SRC5Component::Event", + kind: "enum", + variants: [], + }, + { + type: "event", + name: "openzeppelin::access::ownable::ownable::OwnableComponent::OwnershipTransferred", + kind: "struct", + members: [ + { + name: "previous_owner", + type: "core::starknet::contract_address::ContractAddress", + kind: "key", + }, + { + name: "new_owner", + type: "core::starknet::contract_address::ContractAddress", + kind: "key", + }, + ], + }, + { + type: "event", + name: "openzeppelin::access::ownable::ownable::OwnableComponent::OwnershipTransferStarted", + kind: "struct", + members: [ + { + name: "previous_owner", + type: "core::starknet::contract_address::ContractAddress", + kind: "key", + }, + { + name: "new_owner", + type: "core::starknet::contract_address::ContractAddress", + kind: "key", + }, + ], + }, + { + type: "event", + name: "openzeppelin::access::ownable::ownable::OwnableComponent::Event", + kind: "enum", + variants: [ + { + name: "OwnershipTransferred", + type: "openzeppelin::access::ownable::ownable::OwnableComponent::OwnershipTransferred", + kind: "nested", + }, + { + name: "OwnershipTransferStarted", + type: "openzeppelin::access::ownable::ownable::OwnableComponent::OwnershipTransferStarted", + kind: "nested", + }, + ], + }, + { + type: "event", + name: "contracts::challenge0::Challenge0::Event", + kind: "enum", + variants: [ + { + name: "ERC721Event", + type: "openzeppelin::token::erc721::erc721::ERC721Component::Event", + kind: "flat", + }, + { + name: "SRC5Event", + type: "openzeppelin::introspection::src5::SRC5Component::Event", + kind: "flat", + }, + { + name: "OwnableEvent", + type: "openzeppelin::access::ownable::ownable::OwnableComponent::Event", + kind: "flat", + }, + ], + }, + ], + }, + }, +} as const; export default deployedContracts; diff --git a/packages/nextjs/services/web3/provider.ts b/packages/nextjs/services/web3/provider.ts new file mode 100644 index 00000000..0c6f95b7 --- /dev/null +++ b/packages/nextjs/services/web3/provider.ts @@ -0,0 +1,19 @@ +import scaffoldConfig from "~~/scaffold.config"; +import {jsonRpcProvider, publicProvider, starknetChainId} from "@starknet-react/core"; +import * as chains from "@starknet-react/chains"; + +const containsDevnet = (networks: readonly chains.Chain[]) => { + return networks.filter(it => it.id == chains.devnet.id).length > 0 +} + +const provider = + scaffoldConfig.rpcProviderUrl == "" || containsDevnet(scaffoldConfig.targetNetworks) + ? publicProvider() + : jsonRpcProvider({ + rpc: () => ({ + nodeUrl: scaffoldConfig.rpcProviderUrl, + chainId: starknetChainId(scaffoldConfig.targetNetworks[0].id), + }), + }); + +export default provider; \ No newline at end of file From 02b8c739d79c8cb89a793fcbbd5014b4cc246559 Mon Sep 17 00:00:00 2001 From: Eduardo Date: Mon, 15 Apr 2024 12:39:52 -0500 Subject: [PATCH 3/6] fix: format --- packages/nextjs/services/web3/provider.ts | 25 ++++++++++++++--------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/packages/nextjs/services/web3/provider.ts b/packages/nextjs/services/web3/provider.ts index 0c6f95b7..e155024a 100644 --- a/packages/nextjs/services/web3/provider.ts +++ b/packages/nextjs/services/web3/provider.ts @@ -1,19 +1,24 @@ import scaffoldConfig from "~~/scaffold.config"; -import {jsonRpcProvider, publicProvider, starknetChainId} from "@starknet-react/core"; +import { + jsonRpcProvider, + publicProvider, + starknetChainId, +} from "@starknet-react/core"; import * as chains from "@starknet-react/chains"; const containsDevnet = (networks: readonly chains.Chain[]) => { - return networks.filter(it => it.id == chains.devnet.id).length > 0 -} + return networks.filter((it) => it.id == chains.devnet.id).length > 0; +}; const provider = - scaffoldConfig.rpcProviderUrl == "" || containsDevnet(scaffoldConfig.targetNetworks) + scaffoldConfig.rpcProviderUrl == "" || + containsDevnet(scaffoldConfig.targetNetworks) ? publicProvider() : jsonRpcProvider({ - rpc: () => ({ - nodeUrl: scaffoldConfig.rpcProviderUrl, - chainId: starknetChainId(scaffoldConfig.targetNetworks[0].id), - }), - }); + rpc: () => ({ + nodeUrl: scaffoldConfig.rpcProviderUrl, + chainId: starknetChainId(scaffoldConfig.targetNetworks[0].id), + }), + }); -export default provider; \ No newline at end of file +export default provider; From eb2de3a3fccc67933941f82f7c0610e7aabd821f Mon Sep 17 00:00:00 2001 From: Eduardo Date: Mon, 15 Apr 2024 15:03:52 -0500 Subject: [PATCH 4/6] feat: fetch eth price --- packages/nextjs/components/Footer.tsx | 19 +++++---- .../ScaffoldStarkAppWithProviders.tsx | 3 ++ .../components/scaffold-stark/Balance.tsx | 7 +++- .../scaffold-stark/useNativeCurrencyPrice.ts | 39 +++++++++++++++++++ packages/nextjs/scaffold.config.ts | 4 ++ .../scaffold-stark/fetchPriceFromCoingecko.ts | 27 +++++++++++++ packages/nextjs/utils/scaffold-stark/index.ts | 1 + .../nextjs/utils/scaffold-stark/networks.ts | 1 + 8 files changed, 92 insertions(+), 9 deletions(-) create mode 100644 packages/nextjs/hooks/scaffold-stark/useNativeCurrencyPrice.ts create mode 100644 packages/nextjs/utils/scaffold-stark/fetchPriceFromCoingecko.ts diff --git a/packages/nextjs/components/Footer.tsx b/packages/nextjs/components/Footer.tsx index 66feda99..b8eab224 100644 --- a/packages/nextjs/components/Footer.tsx +++ b/packages/nextjs/components/Footer.tsx @@ -8,6 +8,9 @@ import { import { HeartIcon } from "@heroicons/react/24/outline"; import { SwitchTheme } from "~~/components/SwitchTheme"; import { BuidlGuidlLogo } from "~~/components/assets/BuidlGuidlLogo"; +import { useTargetNetwork } from "~~/hooks/scaffold-stark/useTargetNetwork"; +import { useGlobalState } from "~~/services/store/store"; +import { devnet } from "@starknet-react/chains"; // import { Faucet } from "~~/components/scaffold-eth"; // import { useTargetNetwork } from "~~/hooks/scaffold-eth/useTargetNetwork"; // import { useGlobalState } from "~~/services/store/store"; @@ -16,18 +19,18 @@ import { BuidlGuidlLogo } from "~~/components/assets/BuidlGuidlLogo"; * Site footer */ export const Footer = () => { - // const nativeCurrencyPrice = useGlobalState( - // (state) => state.nativeCurrencyPrice - // ); - // const { targetNetwork } = useTargetNetwork(); - const isLocalNetwork = false; + const nativeCurrencyPrice = useGlobalState( + (state) => state.nativeCurrencyPrice, + ); + const { targetNetwork } = useTargetNetwork(); + const isLocalNetwork = targetNetwork.id === devnet.id; return (
- {/* {nativeCurrencyPrice > 0 && ( + {nativeCurrencyPrice > 0 && (
@@ -37,7 +40,7 @@ export const Footer = () => { )} {isLocalNetwork && ( <> - + {/**/} { Block Explorer - )} */} + )}
{ + useNativeCurrencyPrice(); + return ( <>
diff --git a/packages/nextjs/components/scaffold-stark/Balance.tsx b/packages/nextjs/components/scaffold-stark/Balance.tsx index f5fa9eef..cde2f5f4 100644 --- a/packages/nextjs/components/scaffold-stark/Balance.tsx +++ b/packages/nextjs/components/scaffold-stark/Balance.tsx @@ -70,7 +70,12 @@ export const Balance = ({ address, className = "", usdMode }: BalanceProps) => { {displayUsdMode ? ( <> $ - {(formattedBalance * price).toFixed(2)} + + {(formattedBalance * price).toLocaleString("en-US", { + minimumFractionDigits: 2, + maximumFractionDigits: 2, + })} + ) : ( <> diff --git a/packages/nextjs/hooks/scaffold-stark/useNativeCurrencyPrice.ts b/packages/nextjs/hooks/scaffold-stark/useNativeCurrencyPrice.ts new file mode 100644 index 00000000..b117ba96 --- /dev/null +++ b/packages/nextjs/hooks/scaffold-stark/useNativeCurrencyPrice.ts @@ -0,0 +1,39 @@ +import { useEffect } from "react"; +import { useTargetNetwork } from "./useTargetNetwork"; +import { useInterval } from "usehooks-ts"; +import scaffoldConfig from "~~/scaffold.config"; +import { fetchPriceFromCoingecko } from "~~/utils/scaffold-stark"; +import { useGlobalState } from "~~/services/store/store"; + +/** + * Get the price of Native Currency based on Native Token/DAI trading pair from Uniswap SDK + */ +export const useNativeCurrencyPrice = () => { + const { targetNetwork } = useTargetNetwork(); + const nativeCurrencyPrice = useGlobalState( + (state) => state.nativeCurrencyPrice, + ); + const setNativeCurrencyPrice = useGlobalState( + (state) => state.setNativeCurrencyPrice, + ); + // Get the price of ETH from Coingecko on mount + useEffect(() => { + (async () => { + if (nativeCurrencyPrice == 0) { + const price = await fetchPriceFromCoingecko(targetNetwork); + setNativeCurrencyPrice(price); + } + })(); + }, [targetNetwork]); + + // Get the price of ETH from Coingecko at a given interval + useInterval( + async () => { + const price = await fetchPriceFromCoingecko(targetNetwork); + setNativeCurrencyPrice(price); + }, + scaffoldConfig.pollingInterval ? 4000 : scaffoldConfig.pollingInterval, + ); + + //return nativeCurrencyPrice; +}; diff --git a/packages/nextjs/scaffold.config.ts b/packages/nextjs/scaffold.config.ts index 9d010910..3daf09e4 100644 --- a/packages/nextjs/scaffold.config.ts +++ b/packages/nextjs/scaffold.config.ts @@ -2,6 +2,7 @@ import * as chains from "@starknet-react/chains"; export type ScaffoldConfig = { targetNetworks: readonly chains.Chain[]; + pollingInterval?: number | null; onlyLocalBurnerWallet: boolean; rpcProviderUrl: string; walletAutoConnect: boolean; @@ -12,6 +13,9 @@ const scaffoldConfig = { // Only show the Burner Wallet when running on devnet onlyLocalBurnerWallet: false, rpcProviderUrl: process.env.NEXT_PUBLIC_PROVIDER_URL || "", + // The interval at which your front-end polls the RPC servers for new data + // it has no effect if you only target the local network (default is 4000) + pollingInterval: null, /** * Auto connect: * 1. If the user was connected into a wallet before, on page reload reconnect automatically diff --git a/packages/nextjs/utils/scaffold-stark/fetchPriceFromCoingecko.ts b/packages/nextjs/utils/scaffold-stark/fetchPriceFromCoingecko.ts new file mode 100644 index 00000000..a0e42af7 --- /dev/null +++ b/packages/nextjs/utils/scaffold-stark/fetchPriceFromCoingecko.ts @@ -0,0 +1,27 @@ +import { ChainWithAttributes } from "~~/utils/scaffold-stark"; + +export const fetchPriceFromCoingecko = async ( + targetNetwork: ChainWithAttributes, +): Promise => { + if ( + targetNetwork.nativeCurrency.symbol !== "ETH" && + targetNetwork.nativeCurrency.symbol !== "SEP" && + !targetNetwork.nativeCurrencyTokenAddress + ) { + return 0; + } + + try { + const response = await fetch( + "https://api.coingecko.com/api/v3/simple/price?ids=ethereum&vs_currencies=usd", + ); + const data = await response.json(); + return data.ethereum.usd; + } catch (error) { + console.error( + `useNativeCurrencyPrice - Error fetching ${targetNetwork.nativeCurrency.symbol} price from Coingecko: `, + error, + ); + return 0; + } +}; diff --git a/packages/nextjs/utils/scaffold-stark/index.ts b/packages/nextjs/utils/scaffold-stark/index.ts index eaa4e9b4..1a102ac0 100644 --- a/packages/nextjs/utils/scaffold-stark/index.ts +++ b/packages/nextjs/utils/scaffold-stark/index.ts @@ -1,2 +1,3 @@ export * from "./networks"; export * from "./notification"; +export * from "./fetchPriceFromCoingecko"; diff --git a/packages/nextjs/utils/scaffold-stark/networks.ts b/packages/nextjs/utils/scaffold-stark/networks.ts index 2e5b71c6..4e44e005 100644 --- a/packages/nextjs/utils/scaffold-stark/networks.ts +++ b/packages/nextjs/utils/scaffold-stark/networks.ts @@ -4,6 +4,7 @@ import scaffoldConfig from "~~/scaffold.config"; type ChainAttributes = { // color | [lightThemeColor, darkThemeColor] color: string | [string, string]; + nativeCurrencyTokenAddress?: string; }; export type ChainWithAttributes = chains.Chain & Partial; From 889e4d8a166c88f798533c828f5cbeb3cafc630c Mon Sep 17 00:00:00 2001 From: CarlosR Date: Tue, 16 Apr 2024 10:51:34 +0800 Subject: [PATCH 5/6] feat: deployment workflow --- .github/workflows/deploy.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .github/workflows/deploy.yml diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 00000000..82c37397 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,27 @@ +name: Build and Deploy to Droplet + +on: + push: + branches: + - main + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - name: Build and deploy app on server + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.DROPLET_IP }} + username: ${{ secrets.DROPLET_USER }} + key: ${{ secrets.SSH_PRIVATE_KEY }} + script: | + cd /var/www/speedrunstark + git pull origin main + pm2 stop speedrunstark + yarn install + cd packages/nextjs + yarn build + pm2 restart speedrunstark + pm2 save \ No newline at end of file From 21637406b38f769655364828dd77f76280fa0918 Mon Sep 17 00:00:00 2001 From: jrcarlos2000 Date: Tue, 16 Apr 2024 14:34:00 +0800 Subject: [PATCH 6/6] fix deploy scripts --- packages/snfoundry/scripts_js/deploy.js | 13 ++----------- packages/snfoundry/scripts_js/deploy_contract.js | 15 ++++++++++----- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/packages/snfoundry/scripts_js/deploy.js b/packages/snfoundry/scripts_js/deploy.js index b0b1beb8..384be09f 100644 --- a/packages/snfoundry/scripts_js/deploy.js +++ b/packages/snfoundry/scripts_js/deploy.js @@ -1,13 +1,4 @@ -const fs = require("fs"); -const path = require("path"); -const networks = require("./helpers/networks"); -const argv = require("yargs/yargs")(process.argv.slice(2)).argv; - -const { TransactionStatus } = require("starknet"); -const { hash } = require("starknet"); - -const { CallData } = require("starknet-dev"); -const deployContract = require("./deploy_contract"); +const { deployContract } = require("./deploy_contract"); const deployScript = async () => { // const { @@ -27,7 +18,7 @@ const deployScript = async () => { owner: "0x4b3f4ba8c00a02b66142a4b1dd41a4dfab4f92650922a3280977b0f03c75ee1", }, // last account in devnet accounts - "Challenge0", + "Challenge0" ); // await deployContract( diff --git a/packages/snfoundry/scripts_js/deploy_contract.js b/packages/snfoundry/scripts_js/deploy_contract.js index b6ec06e2..691c50e3 100644 --- a/packages/snfoundry/scripts_js/deploy_contract.js +++ b/packages/snfoundry/scripts_js/deploy_contract.js @@ -1,10 +1,13 @@ const fs = require("fs"); const path = require("path"); const networks = require("./helpers/networks"); -const {hash, CallData, TransactionStatus} = require("starknet"); +const argv = require("yargs/yargs")(process.argv.slice(2)).argv; +const { hash, TransactionStatus } = require("starknet"); +const { CallData } = require("starknet-dev"); + const networkName = argv.network; -const {provider, deployer} = networks[networkName]; +const { provider, deployer } = networks[networkName]; const deployContract = async ( constructorArgs, contractName, @@ -48,7 +51,7 @@ const deployContract = async ( let totalFee = 0n; try { - const {suggestedMaxFee: estimatedFeeDeclare} = + const { suggestedMaxFee: estimatedFeeDeclare } = await deployer.estimateDeclareFee( { contract: compiledContractSierra, @@ -58,7 +61,7 @@ const deployContract = async ( ); totalFee = estimatedFeeDeclare * 2n; } catch (e) { - const {suggestedMaxFee: estimatedFeeDeploy} = + const { suggestedMaxFee: estimatedFeeDeploy } = await deployer.estimateDeployFee({ classHash: precomputedClassHash, constructorCalldata, @@ -118,4 +121,6 @@ const deployContract = async ( }; }; -export default deployContract \ No newline at end of file +module.exports = { + deployContract, +};