diff --git a/change/@starknet-react-core-2cb32fda-224a-4b36-86e2-acffaa17d520.json b/change/@starknet-react-core-2cb32fda-224a-4b36-86e2-acffaa17d520.json new file mode 100644 index 00000000..6bda5e15 --- /dev/null +++ b/change/@starknet-react-core-2cb32fda-224a-4b36-86e2-acffaa17d520.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "Add provider option to select default chain when no wallet is connected", + "packageName": "@starknet-react/core", + "email": "francesco@ceccon.me", + "dependentChangeType": "patch" +} diff --git a/docs/components/demo/change-default-network.tsx b/docs/components/demo/change-default-network.tsx new file mode 100644 index 00000000..adbc6b4e --- /dev/null +++ b/docs/components/demo/change-default-network.tsx @@ -0,0 +1,70 @@ +import { type Chain, mainnet, sepolia } from "@starknet-react/chains"; +import { publicProvider, useAccount, useNetwork } from "@starknet-react/core"; +import { useState } from "react"; +import { Button } from "../ui/button"; +import { DemoContainer } from "../starknet"; + +export function ChangeDefaultNetwork() { + const [defaultChain, setDefaultChain] = useState(sepolia); + const chains = [mainnet, sepolia]; + const provider = publicProvider(); + + return ( + + + + ); +} + +function ChangeNetworkInner({ + defaultChain, + setDefaultChain, +}: { + defaultChain: Chain; + setDefaultChain: (chain: Chain) => void; +}) { + const { chain } = useNetwork(); + const chains = [sepolia, mainnet]; + const { isConnected } = useAccount(); + + return ( +
+
+

Current Chain:

+
{chain.name}
+
+ +
+

Default Chain:

+
{defaultChain.name}
+
+ +
+

Change Default Chain:

+
+ {chains.map((chain) => ( + + ))} +
+
+ +
+

Behavior Explanation:

+
+          {isConnected
+            ? "Connected: Changing default chain won't affect current chain"
+            : "Not Connected: Changing default chain will update current chain"}
+        
+
+
+ ); +} diff --git a/docs/components/demo/index.ts b/docs/components/demo/index.ts index 0a4f8542..b0038ef3 100644 --- a/docs/components/demo/index.ts +++ b/docs/components/demo/index.ts @@ -13,6 +13,7 @@ import { StarkProfile } from "./stark-profile"; import { StarknetKit } from "./starknetkit"; import { SwitchChain } from "./switch-chain"; import { WalletPermission } from "./wallet-permission"; +import { ChangeDefaultNetwork } from "./change-default-network"; export default { Account, @@ -30,4 +31,5 @@ export default { DeclareContract, NonceForAddress, StarknetKit, + ChangeDefaultNetwork, }; diff --git a/docs/components/starknet/index.tsx b/docs/components/starknet/index.tsx index 5019053a..214f47b3 100644 --- a/docs/components/starknet/index.tsx +++ b/docs/components/starknet/index.tsx @@ -2,14 +2,16 @@ import { WalletBar } from "./bar"; import { StarknetProvider } from "./provider"; export function DemoContainer({ + defaultChainId, hasWallet, children, }: { + defaultChainId?: bigint; hasWallet?: boolean; children: React.ReactNode; }) { return ( - +
{hasWallet ? : null}
{children}
diff --git a/docs/components/starknet/provider.tsx b/docs/components/starknet/provider.tsx index 2972958a..b1e057a6 100644 --- a/docs/components/starknet/provider.tsx +++ b/docs/components/starknet/provider.tsx @@ -9,10 +9,12 @@ import { } from "@starknet-react/core"; export function StarknetProvider({ + defaultChainId, children, explorer, }: { children: React.ReactNode; + defaultChainId?: bigint; explorer?: ExplorerFactory; }) { const chains = [sepolia, mainnet]; @@ -32,6 +34,7 @@ export function StarknetProvider({ provider={provider} connectors={connectors} explorer={explorer} + defaultChainId={defaultChainId} > {children} diff --git a/docs/pages/demo/change-default-network.mdx b/docs/pages/demo/change-default-network.mdx new file mode 100644 index 00000000..657046da --- /dev/null +++ b/docs/pages/demo/change-default-network.mdx @@ -0,0 +1,5 @@ +import Demo from "../../components/demo"; + +# Change Default Network (Todo) + + diff --git a/docs/pages/demo/index.mdx b/docs/pages/demo/index.mdx index 3742a1d2..33febeb1 100644 --- a/docs/pages/demo/index.mdx +++ b/docs/pages/demo/index.mdx @@ -20,6 +20,8 @@ You can find the source code for these demos [on GitHub](https://github.com/apib **[Sign Typed Data](/demo/sign-typed-data)**: Shows how to request users to sign a piece of data. +**[Change Default Network](/demo/change-default-network)**: Shows how to change the default network. + ## New APIs **[Request wallet permissions](/demo/wallet-permission)**: Shows how to request wallet permissions. diff --git a/docs/pages/docs/starknet-config.mdx b/docs/pages/docs/starknet-config.mdx new file mode 100644 index 00000000..5d5eabea --- /dev/null +++ b/docs/pages/docs/starknet-config.mdx @@ -0,0 +1,65 @@ +# StarknetConfig + +The React Context provider for Starknet. + +## Usage + +```tsx twoslash +"use client"; +import React from "react"; + +import { mainnet } from "@starknet-react/chains"; +import { StarknetConfig, publicProvider } from "@starknet-react/core"; + +function App() { + return ( + + {/* your app here */} + + ); +} +``` + +## Arguments + +### chains + +- Type: `Chain[]` + +List of supported chains. + +### provider + +- Type: `ChainProviderFactory` + +The JSON-RPC provider you want to use. See [the RPC providers page](/docs/providers) for more information. + +### connectors + +- Type: `Connector[]` + +List of wallet connectors you want to use. See [the wallets page](/docs/wallets) for more information. + +### explorer + +- Type: `ExplorerFactory` + +Explorer factory to use. See [the explorers page](/docs/explorers) for more information. + +### autoConnect + +- Type: `boolean | undefined` + +Whether to automatically connect to the first available wallet. + +### queryClient + +- Type: `QueryClient` + +React Query client to use. + +### defaultChainId + +- Type: `bigint | undefined` + +Default chain to use when no wallet is connected. This chain must be included in the `chains` array. diff --git a/docs/sidebar.ts b/docs/sidebar.ts index d20fd04a..21c2ae52 100644 --- a/docs/sidebar.ts +++ b/docs/sidebar.ts @@ -13,6 +13,10 @@ export const sidebar = { text: "Upgrading to V3", link: "/docs/upgrading-to-v3", }, + { + text: "StarknetConfig", + link: "/docs/starknet-config", + }, { text: "Wallets", link: "/docs/wallets", diff --git a/packages/core/src/context/starknet.tsx b/packages/core/src/context/starknet.tsx index efbae3ef..3792585e 100644 --- a/packages/core/src/context/starknet.tsx +++ b/packages/core/src/context/starknet.tsx @@ -102,6 +102,7 @@ interface UseStarknetManagerProps { explorer?: ExplorerFactory; connectors?: Connector[]; autoConnect?: boolean; + defaultChainId?: bigint; } function useStarknetManager({ @@ -110,17 +111,20 @@ function useStarknetManager({ explorer, connectors = [], autoConnect = false, + defaultChainId, }: UseStarknetManagerProps): StarknetState & { account?: AccountInterface; address?: Address; } { - const initialChain = chains[0]; - if (initialChain === undefined) { + const defaultChain = defaultChainId + ? (chains.find((c) => c.id === defaultChainId) ?? chains[0]) + : chains[0]; + if (defaultChain === undefined) { throw new Error("Must provide at least one chain."); } - const { chain: defaultChain, provider: defaultProvider } = providerForChain( - initialChain, + const { chain: _, provider: defaultProvider } = providerForChain( + defaultChain, provider, ); @@ -174,6 +178,16 @@ function useStarknetManager({ [updateChainAndProvider, state.currentProvider], ); + useEffect(() => { + if (!connectorRef.current) { + // Only update currentChain if no wallet is connected + setState((state) => ({ + ...state, + currentChain: defaultChain, + currentProvider: providerForChain(defaultChain, provider).provider, + })); + } + }, [defaultChain, provider]); const connect = useCallback( async ({ connector }: { connector?: Connector }) => { if (!connector) { @@ -311,6 +325,8 @@ export interface StarknetProviderProps { queryClient?: QueryClient; /** Application. */ children?: React.ReactNode; + /** Default chain to use when wallet is not connected */ + defaultChainId?: bigint; } /** Root Starknet context provider. */ @@ -321,6 +337,7 @@ export function StarknetProvider({ explorer, autoConnect, queryClient, + defaultChainId, children, }: StarknetProviderProps): JSX.Element { const { account, address, ...state } = useStarknetManager({ @@ -329,6 +346,7 @@ export function StarknetProvider({ explorer, connectors, autoConnect, + defaultChainId, }); return (