Skip to content

Commit

Permalink
Change provider to a factory
Browse files Browse the repository at this point in the history
  • Loading branch information
IvanLudvig authored Nov 7, 2023
1 parent f6c7425 commit 8ba9a3a
Show file tree
Hide file tree
Showing 17 changed files with 92 additions and 171 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,11 @@ import {

function App() {
const chains = [goerli];
const providers = [publicProvider()];
const provider = publicProvider();
const connectors = [braavos(), argent()];

return (
<StarknetConfig chains={chains} providers={providers} connectors={connectors}>
<StarknetConfig chains={chains} provider={provider} connectors={connectors}>
<YourApp />
</StarknetConfig>
)
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/context/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from "react";

import { StarknetProvider, StarknetProviderProps } from "./starknet";

export { starknetChainId } from "./starknet";
export { AccountProvider as OverrideAccount } from "./account";

export type StarknetConfigProps = StarknetProviderProps;
Expand Down
39 changes: 15 additions & 24 deletions packages/core/src/context/starknet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,14 @@ interface StarknetManagerState {

interface UseStarknetManagerProps {
chains: Chain[];
providers: ChainProviderFactory[];
provider: ChainProviderFactory;
connectors?: Connector[];
autoConnect?: boolean;
}

function useStarknetManager({
chains,
providers,
provider,
connectors = [],
autoConnect = false,
}: UseStarknetManagerProps): StarknetState & { account?: AccountInterface } {
Expand All @@ -104,7 +104,7 @@ function useStarknetManager({

const { chain: defaultChain, provider: defaultProvider } = providerForChain(
initialChain,
providers,
provider,
);

// The currently connected connector needs to be accessible from the
Expand All @@ -121,14 +121,14 @@ function useStarknetManager({
if (!chainId) return;
for (const chain of chains) {
if (chain.id === chainId) {
const { chain: newChain, provider } = providerForChain(
const { chain: newChain, provider: newProvider } = providerForChain(
chain,
providers,
provider,
);
setState((state) => ({
...state,
currentChain: newChain,
currentProvider: provider,
currentProvider: newProvider,
}));
return;
}
Expand Down Expand Up @@ -283,8 +283,8 @@ function useStarknetManager({
export interface StarknetProviderProps {
/** Chains supported by the app. */
chains: Chain[];
/** Providers supported by the app. */
providers: ChainProviderFactory[];
/** Provider to use. */
provider: ChainProviderFactory;
/** List of connectors to use. */
connectors?: Connector[];
/** Connect the first available connector on page load. */
Expand All @@ -298,15 +298,15 @@ export interface StarknetProviderProps {
/** Root Starknet context provider. */
export function StarknetProvider({
chains,
providers,
provider,
connectors,
autoConnect,
queryClient,
children,
}: StarknetProviderProps): JSX.Element {
const { account, ...state } = useStarknetManager({
chains,
providers,
provider,
connectors,
autoConnect,
});
Expand All @@ -322,26 +322,17 @@ export function StarknetProvider({

function providerForChain(
chain: Chain,
providers: ChainProviderFactory[],
factory: ChainProviderFactory,
): { chain: Chain; provider: ProviderInterface } {
for (const factory of providers) {
const provider = factory(chain);
if (provider) {
const { chain, rpcUrls } = provider;
const nodeUrl = rpcUrls.http[0];
if (!nodeUrl) {
continue;
}
const chainId = starknetChainId(chain.id);
const rpc = new RpcProvider({ nodeUrl, chainId });
return { chain, provider: rpc };
}
const provider = factory(chain);
if (provider) {
return { chain, provider };
}

throw new Error(`No provider found for chain ${chain.name}`);
}

function starknetChainId(
export function starknetChainId(
chainId: bigint,
): constants.StarknetChainId | undefined {
switch (chainId) {
Expand Down
25 changes: 10 additions & 15 deletions packages/core/src/providers/alchemy.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ChainProviderFactory, setDefaultRpcUrl } from "./factory";
import { jsonRpcProvider } from "./jsonrpc";

/** Arguments for `alchemyProvider`. */
export type AlchemyProviderArgs = {
Expand All @@ -7,18 +7,13 @@ export type AlchemyProviderArgs = {
};

/** Configure the Alchemy provider using the provided API key. */
export function alchemyProvider({
apiKey,
}: AlchemyProviderArgs): ChainProviderFactory {
return function (chain) {
const baseHttpUrl = chain.rpcUrls["alchemy"]?.http[0];
if (!baseHttpUrl) return null;
const httpUrl = `${baseHttpUrl}/${apiKey}`;
return {
chain: setDefaultRpcUrl(chain, httpUrl),
rpcUrls: {
http: [httpUrl],
},
};
};
export function alchemyProvider({ apiKey }: AlchemyProviderArgs) {
return jsonRpcProvider({
rpc: chain => {
const baseHttpUrl = chain.rpcUrls["alchemy"]?.http[0];
if (!baseHttpUrl) return null;
const nodeUrl = `${baseHttpUrl}/${apiKey}`;
return { nodeUrl };
}
});
}
19 changes: 3 additions & 16 deletions packages/core/src/providers/factory.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,4 @@
import { Chain, RpcUrls } from "@starknet-react/chains";
import { Chain } from "@starknet-react/chains";
import { ProviderInterface } from "starknet";

export type ChainProviderFactory = (chain: Chain) => {
chain: Chain;
rpcUrls: RpcUrls;
} | null;

/** Returns a new chain with the default RPC URL set. */
export function setDefaultRpcUrl(chain: Chain, url: string): Chain {
return {
...chain,
rpcUrls: {
...chain.rpcUrls,
default: { http: [url] },
},
};
}
export type ChainProviderFactory<T extends ProviderInterface = ProviderInterface> = (chain: Chain) => T | null;
25 changes: 10 additions & 15 deletions packages/core/src/providers/infura.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ChainProviderFactory, setDefaultRpcUrl } from "./factory";
import { jsonRpcProvider } from "./jsonrpc";

/** Arguments for `infuraProvider`. */
export type InfuraProviderArgs = {
Expand All @@ -7,18 +7,13 @@ export type InfuraProviderArgs = {
};

/** Configure the Infura provider using the provided API key. */
export function infuraProvider({
apiKey,
}: InfuraProviderArgs): ChainProviderFactory {
return function (chain) {
const baseHttpUrl = chain.rpcUrls["infura"]?.http[0];
if (!baseHttpUrl) return null;
const httpUrl = `${baseHttpUrl}/${apiKey}`;
return {
chain: setDefaultRpcUrl(chain, httpUrl),
rpcUrls: {
http: [httpUrl],
},
};
};
export function infuraProvider({ apiKey }: InfuraProviderArgs) {
return jsonRpcProvider({
rpc: chain => {
const baseHttpUrl = chain.rpcUrls["infura"]?.http[0];
if (!baseHttpUrl) return null;
const nodeUrl = `${baseHttpUrl}/${apiKey}`;
return { nodeUrl };
}
});
}
12 changes: 3 additions & 9 deletions packages/core/src/providers/jsonrpc.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,12 @@ import { jsonRpcProvider } from "./jsonrpc";

function rpc(chain: Chain) {
return {
http: `https://${chain.network}.example.com`,
nodeUrl: `https://${chain.network}.example.com`,
};
}

describe("publicProvider", () => {
describe("jsonRpcProvider", () => {
it("returns a public rpc endpoint", () => {
expect(jsonRpcProvider({ rpc })(mainnet)?.rpcUrls).toMatchInlineSnapshot(`
{
"http": [
"https://mainnet.example.com",
],
}
`);
expect(jsonRpcProvider({ rpc })(mainnet)?.nodeUrl).toMatchInlineSnapshot('"https://mainnet.example.com"');
});
});
20 changes: 10 additions & 10 deletions packages/core/src/providers/jsonrpc.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import { Chain } from "@starknet-react/chains";
import { RpcProvider, RpcProviderOptions } from "starknet";

import { ChainProviderFactory, setDefaultRpcUrl } from "./factory";
import { starknetChainId } from "~/context";
import { ChainProviderFactory } from "./factory";

/** Arguments for `jsonRpcProvider`. */
export type JsonRpcProviderArgs = {
rpc: (chain: Chain) => { http: string } | null;
rpc: (chain: Chain) => RpcProviderOptions | null;
};

/** Configure the JSON-RPC provider using the provided function. */
export function jsonRpcProvider({
rpc,
}: JsonRpcProviderArgs): ChainProviderFactory {
}: JsonRpcProviderArgs): ChainProviderFactory<RpcProvider> {
return function (chain) {
const config = rpc(chain);
if (!config || config.http === "") return null;
return {
chain: setDefaultRpcUrl(chain, config.http),
rpcUrls: {
http: [config.http],
},
};
if (!config) return null;
const chainId = starknetChainId(chain.id);

const provider = new RpcProvider({ ...config, chainId });
return provider;
};
}
25 changes: 10 additions & 15 deletions packages/core/src/providers/lava.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ChainProviderFactory, setDefaultRpcUrl } from "./factory";
import { jsonRpcProvider } from "./jsonrpc";

/** Arguments for `lavaProvider`. */
export type LavaProviderArgs = {
Expand All @@ -7,18 +7,13 @@ export type LavaProviderArgs = {
};

/** Configure the Lava provider using the provided API key. */
export function lavalProvider({
apiKey,
}: LavaProviderArgs): ChainProviderFactory {
return function (chain) {
const baseHttpUrl = chain.rpcUrls["lava"]?.http[0];
if (!baseHttpUrl) return null;
const httpUrl = `${baseHttpUrl}/${apiKey}`;
return {
chain: setDefaultRpcUrl(chain, httpUrl),
rpcUrls: {
http: [httpUrl],
},
};
};
export function lavalProvider({ apiKey }: LavaProviderArgs) {
return jsonRpcProvider({
rpc: chain => {
const baseHttpUrl = chain.rpcUrls["lava"]?.http[0];
if (!baseHttpUrl) return null;
const nodeUrl = `${baseHttpUrl}/${apiKey}`;
return { nodeUrl };
}
});
}
33 changes: 2 additions & 31 deletions packages/core/src/providers/public.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,10 @@ import { publicProvider } from "./public";

describe("publicProvider", () => {
it("returns a public rpc endpoint", () => {
expect(publicProvider()(devnet)?.rpcUrls).toMatchInlineSnapshot(`
{
"http": [
"http://localhost:5050/rpc",
],
}
`);
expect(publicProvider()(devnet)?.nodeUrl).toMatchInlineSnapshot('"http://localhost:5050/rpc"');
});

it("returns the chain", () => {
expect(publicProvider()(devnet)?.chain).toMatchInlineSnapshot(`
{
"id": 1536727068981429685321n,
"name": "Starknet Devnet",
"nativeCurrency": {
"address": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
"decimals": 18,
"name": "Ether",
"symbol": "ETH",
},
"network": "devnet",
"rpcUrls": {
"default": {
"http": [],
},
"public": {
"http": [
"http://localhost:5050/rpc",
],
},
},
"testnet": true,
}
`);
expect(publicProvider()(devnet)?.getChainId()).resolves.toMatch('0x534e5f474f45524c49');
});
});
18 changes: 9 additions & 9 deletions packages/core/src/providers/public.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { ChainProviderFactory } from "./factory";
import { jsonRpcProvider } from "./jsonrpc";

/** Configure the provider to use the public RPC endpoint. */
export function publicProvider(): ChainProviderFactory {
return function (chain) {
if (!chain.rpcUrls.public.http[0]) return null;
return {
chain,
rpcUrls: chain.rpcUrls.public,
};
};
export function publicProvider() {
return jsonRpcProvider({
rpc: chain => {
const nodeUrl = chain.rpcUrls.public.http[0];
if (!nodeUrl) return null;
return { nodeUrl };
}
});
}
4 changes: 2 additions & 2 deletions packages/core/test/react.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { defaultConnector } from "./devnet";

function StarknetConfig({ children }: { children: React.ReactNode }) {
const chains = [devnet, mainnet];
const providers = [publicProvider()];
const provider = publicProvider();
const connectors = [defaultConnector];

const queryClient = new QueryClient({
Expand All @@ -34,7 +34,7 @@ function StarknetConfig({ children }: { children: React.ReactNode }) {
return (
<OgStarknetConfig
chains={chains}
providers={providers}
provider={provider}
connectors={connectors}
queryClient={queryClient}
>
Expand Down
Loading

0 comments on commit 8ba9a3a

Please sign in to comment.