Skip to content

Feat/custom fork id #438

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions src/components/current/CustomConnectButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import { PowerIcon } from '@heroicons/react/24/outline';
import { ConnectButton } from '@rainbow-me/rainbowkit';
import { formatEther } from 'ethers/lib/utils.js';
import { abbreviateHash, cleanValue } from '@/utils';
import Avatar from '../shared/Avatar';
import useBalance from '../cactiComponents/hooks/useBalance';
import useEnsName from '../cactiComponents/hooks/useEnsName';
import { buttonStyle } from './layout/sidebar/NewChatButton';
import Avatar from '../shared/Avatar';
import SkeletonWrap from '../shared/SkeletonWrap';
import { buttonStyle } from './layout/sidebar/NewChatButton';

const CustomConnectButton = () => {
const { data: balance } = useBalance();
Expand Down Expand Up @@ -64,7 +64,11 @@ const CustomConnectButton = () => {
if (chain.unsupported) {
return (
<button onClick={openChainModal} type="button">
<div className="text-xs text-red-500">Wrong network</div>
<div
className={`flex items-center justify-center text-xs text-red-500/70 ${buttonStyle}`}
>
Wrong Network
</div>
</button>
);
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/current/layout/header/HeaderContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const HeaderContainer = ({
const { pathname } = useRouter();
return (
<div
className={`sticky top-0 z-40 flex gap-x-4 p-4 pt-6 text-white/70 sm:gap-x-6 ${
className={`sticky top-0 z-40 flex gap-x-4 p-4 pt-6 text-white/70 sm:gap-x-6 items-center ${
pathname !== '/' ? 'bg-gray-secondary' : ''
}`}
>
Expand Down
2 changes: 1 addition & 1 deletion src/components/current/layout/sidebar/AccountStatus.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ReadyState } from 'react-use-websocket';
import { useChatContext } from '@/contexts/ChatContext';
import { ReadyState } from 'react-use-websocket';
import ConnectionStatus from './ConnectionStatus';

const AccountStatus = () => {
Expand Down
29 changes: 29 additions & 0 deletions src/components/current/layout/sidebar/ForkStatus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import SettingsContext from '@/contexts/SettingsContext';
import { ExclamationTriangleIcon } from '@heroicons/react/24/outline';
import { useContext } from 'react';

const ForkStatus = () => {
const { settings } = useContext(SettingsContext);
const { isForkedEnv } = settings;

return (
<>
{isForkedEnv ? (
<div>
<div className={`flex flex-col justify-between text-xs text-orange-500`}>
<div />
<div className="flex gap-2 items-center">
<span className='w-3 h-3' > <ExclamationTriangleIcon /> </span>
<span>Test Environemnt</span>
</div>
</div>
</div>
) : null}
</>


);
};


export default ForkStatus;
4 changes: 3 additions & 1 deletion src/components/current/layout/sidebar/SideBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import ChatList from '../../ChatList';
import AccountStatus from './AccountStatus';
import MoreItems from './MoreItems';
import NewChatButton from './NewChatButton';
import ForkStatus from './ForkStatus';

const Sidebar = ({
isOpen,
Expand All @@ -31,8 +32,9 @@ const Sidebar = ({
<div className="relative flex w-full flex-col self-end">
<div className="p-2">
<MoreItems />
<div className="p-2">
<div className="p-2 space-y-2">
<AccountStatus />
<ForkStatus />
</div>
</div>
</div>
Expand Down
24 changes: 11 additions & 13 deletions src/components/devTools/CurrentForkInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ import {
DocumentDuplicateIcon,
} from '@heroicons/react/24/outline';
import copy from 'copy-to-clipboard';
import { useNetwork } from 'wagmi';
import SettingsContext from '@/contexts/SettingsContext';
import { Button } from '../shared/Button';

export const CurrentForkInfo = () => {
const {
settings: { isForkedEnv, forkEnvUrl },
settings: { isForkedEnv, forkEnvUrl, forkId },
} = useContext(SettingsContext);
const [tenderlyUrl, setTenderlyUrl] = useState<string>(forkEnvUrl);
const [copied, setCopied] = useState<boolean>(false);
Expand Down Expand Up @@ -39,22 +40,20 @@ export const CurrentForkInfo = () => {
window.open(tenderlyUrl, '_blank', 'noopener,noreferrer');
};

const { chain } = useNetwork();

return (
<div>
<div className="border">
<div
className={`p-2 text-left text-xs ${
isForkedEnv ? 'bg-green-300' : 'bg-red-300'
} bg-red-300`}
>
{isForkedEnv ? 'Current forked environment' : 'Default fork'}
isForkedEnv ? <div className="border rounded-lg">
<div className={`bg-green-300 p-2 text-left text-xs`}>
<div> Chain Id: {chain?.id} </div>
<div> Mocking Chain Id: {chain!.id.toString().slice(6)} </div>
</div>
<div className="overflow-x-scroll p-4 font-mono text-xs">{forkEnvUrl}</div>
<div className="p-4 font-mono text-xs">{forkId}</div>
<div className="flex gap-2 p-2 text-xs ">
<Button onClick={copyUrl} disabled={copied}>
<div className="flex gap-2 text-[0.75em]">
<div className="w-4">{copied ? <CheckCircleIcon /> : <DocumentDuplicateIcon />} </div>
Copy url
Copy URL
</div>
</Button>
<Button onClick={goToTenderly} disabled={!forkEnvUrl}>
Expand All @@ -66,7 +65,6 @@ export const CurrentForkInfo = () => {
</div>
</Button>
</div>
</div>
</div>
</div> : null
);
};
4 changes: 2 additions & 2 deletions src/components/devTools/DevToolsModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import { Fragment } from 'react';
import { Dialog, Transition } from '@headlessui/react';
import { ChevronDownIcon, XMarkIcon } from '@heroicons/react/24/outline';
import { DebugPanel } from '@/components/devTools/DebugPanel';
import { ResetButton } from './ResetButton';
import { ChangeForkId } from './ChangeForkId';
import { CurrentForkInfo } from './CurrentForkInfo';
import { DebugMessageToggle } from './DebugMessageToggle';
import { ExperimentalUiToggle } from './ExperimentalUiToggle';
import ForkButton from './ForkButton';
import { MintButton } from './MintButton';
import { ResetButton } from './ResetButton';
import { SessionInfo } from './SessionInfo';

interface Props {
Expand Down Expand Up @@ -91,7 +91,7 @@ export const DevToolsModal = ({ openState, handleClose }: Props) => {
<ForkButton />
<CurrentForkInfo />
<MintButton />
<ChangeForkId />
{/* <ChangeForkId /> */}
</div>
</div>

Expand Down
2 changes: 1 addition & 1 deletion src/components/devTools/ForkButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const ForkButton = () => {
const { isForkedEnv } = settings;

const setIsFork = (val: boolean) => {
changeSetting(Setting.FORKED_ENV, val);
changeSetting(Setting.IS_FORKED_ENV, val);
};

return (
Expand Down
22 changes: 9 additions & 13 deletions src/components/devTools/MintButton.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
import { useEffect, useState } from 'react';
import { useContext, useState } from 'react';
import { JsonRpcProvider } from '@ethersproject/providers';
import { ethers } from 'ethers';
import { useAccount, useNetwork, useProvider } from 'wagmi';
import { useAccount, useProvider } from 'wagmi';
import { Button } from '../shared/Button';
import useBalance from '../cactiComponents/hooks/useBalance';
import SettingsContext from '@/contexts/SettingsContext';

export const MintButton = () => {
const { address } = useAccount();
const [isLoading, setLoading] = useState(false);
const [isVisible, setVisible] = useState(false);
const { chain } = useNetwork();
const { refetch } = useBalance();
const provider = useProvider() as JsonRpcProvider;

useEffect(() => {
if (!address || chain?.id != 1) setVisible(false);
setVisible(true);
}, [address, chain?.id]);
const {
settings: { isForkedEnv },
} = useContext(SettingsContext);

const mint = async () => {
const params = [
Expand All @@ -28,15 +25,14 @@ export const MintButton = () => {
await refetch();
setLoading(false);
};
return !isVisible ? (
<></>
) : (
return (
isForkedEnv ?
<Button
onClick={mint}
disabled={isLoading}
className="flex w-full text-xs disabled:bg-gray-400"
>
Mint 10 ETH
</Button>
</Button> : <></>
);
};
29 changes: 11 additions & 18 deletions src/contexts/ConnectionWrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { ReactNode, useContext } from 'react';
import { useContext } from 'react';
import Jazzicon, { jsNumberForAddress } from 'react-jazzicon';
import { useQueryClient } from 'react-query';
import { AppProps } from 'next/app';
import {
AvatarComponent,
RainbowKitProvider,
Expand All @@ -11,45 +9,40 @@ import {
} from '@rainbow-me/rainbowkit';
import axios from 'axios';
import { Chain, WagmiConfig, configureChains, createClient, useEnsAvatar } from 'wagmi';
import { goerli, zkSyncTestnet } from 'wagmi/chains';
import { jsonRpcProvider } from 'wagmi/providers/jsonRpc';
import { goerli, mainnet, zkSyncTestnet } from 'wagmi/chains';
import { publicProvider } from 'wagmi/providers/public';
import useCachedState from '@/hooks/useCachedState';
import { getBackendApiUrl } from '@/utils/backend';
import { GetSiweMessageOptions, RainbowKitSiweNextAuthProvider } from '@/utils/rainbowSIWEmod';
import SettingsContext from './SettingsContext';

const ConnectionWrapper = ({ children, useSiwe = true }: any) => {
const queryClient = useQueryClient();
const { settings } = useContext(SettingsContext);
const { experimentalUi, isForkedEnv, forkEnvUrl } = settings;

/* Use a fork url cached in the browser localStorage, else use the .env value */
const [forkUrl] = useCachedState(
const [cachedForkUrl] = useCachedState(
'forkUrl',
`https://rpc.tenderly.co/fork/${process.env.NEXT_PUBLIC_TENDERLY_FORK_ID}`
);
console.log('🦄 ~ file: ConnectionWrapper.tsx:29 ~ ConnectionWrapper ~ forkUrl:', forkUrl);

const {
settings: { experimentalUi },
} = useContext(SettingsContext);

const mainnetFork = {
id: 1,
name: 'Mainnet Fork',
network: 'mainnet',
id: 1277971, // chainid is made up of 127797 with the natural id of the fork (eg mainnet = 1): 1277971
name: 'Cacti Mainnet Fork',
network: 'mainnet_fork',
nativeCurrency: {
decimals: 18,
name: 'Ether',
symbol: 'ETH',
},
rpcUrls: {
public: { http: [forkUrl] },
default: { http: [forkUrl] },
public: { http: [forkEnvUrl] },
default: { http: [forkEnvUrl] },
},
} as Chain;

const { chains, provider } = configureChains(
[mainnetFork, goerli, zkSyncTestnet],
[isForkedEnv ? mainnetFork : mainnet], // here we select one, so the other is never an option in a forked Env
[publicProvider()]
);

Expand Down
8 changes: 2 additions & 6 deletions src/contexts/SettingsContext.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import {
Dispatch,
ReactNode,
createContext,
useContext,
useEffect,
useReducer,
useState,
} from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import { toast } from 'react-toastify';
Expand All @@ -20,7 +17,7 @@ export enum Setting {

FORCE_TRANSACTIONS = 'forceTransactions',

FORKED_ENV = 'isForkedEnv',
IS_FORKED_ENV = 'isForkedEnv',
FORK_ENV_URL = 'forkEnvUrl',

EXPERIMENTAL_UI = 'experimentalUi',
Expand Down Expand Up @@ -75,7 +72,6 @@ const initState: ISettings = {

/* UI test */
experimentalUi: true,

developerTools: false,

/** Development settings **/
Expand Down Expand Up @@ -121,7 +117,7 @@ export const SettingsProvider = ({ children }: { children: ReactNode }) => {
/* Set universal Shortcut keys for the some settings */
useHotkeys('alt+f', () => {
const currentSetting = settings.isForkedEnv;
changeSetting(Setting.FORKED_ENV, !currentSetting);
changeSetting(Setting.IS_FORKED_ENV, !currentSetting);
toast(
`${
!currentSetting
Expand Down
20 changes: 17 additions & 3 deletions src/hooks/useChainId.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,26 @@
// use the appropriate chain id depending on the network and if using a fork
import { useMemo } from 'react';
import { useContext, useMemo } from 'react';
import { useNetwork } from 'wagmi';
import SettingsContext from '@/contexts/SettingsContext';

const DEFAULT_CHAIN_ID = 1;

const useChainId = () => {
const useChainId = (returnForkId?: boolean) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const useChainId = (returnForkId?: boolean) => {
const useChainId = (returnForkId = false) => {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does returnForkId mean?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UseChainId will return the ID of the forked network ( eg. 1 if we forked mainnet). However, that might not be the id returned by getNetwork().id .... there will likely be a need to have access to both. (For example, some deployed contracts might reference the id 1 , when the id returned by the network will be different ) .

const { chain } = useNetwork();
return useMemo(() => (chain ? chain.id : DEFAULT_CHAIN_ID), [chain]);
const {
settings: { isForkedEnv },
} = useContext(SettingsContext);

return useMemo(() => {
/* if required, we use the *base* chain id for the forked env
because most contracts will require the chain id to match
eg. chainID 1 etc even though we are using a forked env with custom id
*/
if (isForkedEnv && !returnForkId) {
return chain ? +chain.id.toString().slice(6) : DEFAULT_CHAIN_ID;
}
return chain ? chain.id : DEFAULT_CHAIN_ID;
}, [chain]);
};

export default useChainId;
11 changes: 7 additions & 4 deletions src/hooks/useForkTools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@ const useForkTools = (id?: string): ForkTools => {
const { settings } = useContext(SettingsContext);
const { isForkedEnv, forkId } = settings;

const forkUrl = id
? `https://rpc.tenderly.co/fork/${id}`
: `https://rpc.tenderly.co/fork/${forkId}`;
const forkUrl = `https://rpc.tenderly.co/fork/${ id ?? forkId }`

/* parameters from wagmi */
const { address: account } = useAccount();
Expand All @@ -40,7 +38,12 @@ const useForkTools = (id?: string): ForkTools => {
const currentBlockNumber = await provider.getBlockNumber();
const resp = await axios.post(
forkAPI,
{ network_id: 1, block_number: currentBlockNumber },
{ network_id: 1,
block_number: currentBlockNumber,
chain_config: {
chain_id: 1277971
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we or should we make the fork chain id an env variable?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could do so, I think better would be to simply append 127797.. to the current netwrok_id in this case.

}
},
{
headers: {
'X-Access-Key': process.env.NEXT_PUBLIC_TENDERLY_ACCESS_KEY as string,
Expand Down