π Eth-hooks Overview
Commonly used Ethereum hooks to supercharge your web3 dev!
Used by π scaffold-eth-typescript, π scaffold-eth
, eth-components and many other web3 projects!
Created by π° BuidlGuidl.eth
Author
@shravansunder
Documentation
Features
See this video summary on v4 features!
EthersAppContext
A context that allows you to access the current ethers.js context and information such as provider, signer, account. This allows your user to easily log into web3 account using web3modal. You can setup up overrides and multiple providers.
ContractAppContext
Gives you a contractContextFactory
that allows you to easily setup typed contracts, load typed contracts, create connectors, and access them with hooks anywhere in your app.
Caching & optional updates
Caches the network RPC calls so that unecessary requests to the network is prevented. You can setup an update interval from every block, every (n) blocks, polling, onMount, onWindow focus and other react-query update options.
API Documentation
Check out the documentation at the eth-hooks page!
Hooks!
Ethers App Context
- useBlockNumberContext
- useEthersContext
Network
- useBalance
- useBlockNumber
- useContractExistsAtAddress
- useEventListener
- useGasPrice
- useNonce
- useSignerAddress
Contracts
- useContractReader
- contractContextFactory
- useLoadAppContracts
- useConnectAppContracts
- useConnectAppContracts
ERC
Dapps
- useDexEthPrice
- useDexTokenList
- useResolveEnsAddress
- useResolveEnsName
Utilities
Quickstart
Install
yarn add eth-hooks
Setting up the context for eth-hooks
Add the contexts to your app
<ContractsAppContext>
<EthersAppContext>
<YourMainPage />
</EthersAppContext>
</ContractsAppContext>
You can see an example of providers in scaffold-eth-typescript app.tsx
Using the ethersAppContext & hooks
An example of using the context
const ethersContext = useEthersContext();
An example of using a hook
const [yourLocalBalance, update, status] = useBalance(ethersContext.account);
Z;
An example of changing an update interval
const [yourLocalBalance, update, status] = useBalance(ethersContext.account);
const [yourLocalBalance, update, status] = useBalance(ethersContext.account, { blockNumberInterval: 10 });
const [yourLocalBalance, update, status] = useBalance(ethersContext.account, {
refetchInterval: 100000,
blockNumberInterval: undefined,
});
const [yourLocalBalance, update, status] = useBalance(ethersContext.account, {
blockNumberInterval: 1,
query: { refetchOnWindowFocus: true },
});
An example of overriding the provider from the context
const [mainnetAdaptor] = useEthersAdaptorFromProviderOrSigners(exampleMainnetProvider);
const [yourMainnetBalance] = useBalance(ethersContext.account, mergeDefaultUpdateOptions(), {
adaptorEnabled: true,
adaptor: mainnetAdaptor,
});
Check out examples in scaffold-eth-typescript in useScaffoldHooksExamples.tsx
Pass in a provider directly into ethersAppContext
You can pass a provider into EthersAppContext directly if you don't want to use EthersModalConnect
and web3Modal
. This would be a way to override the default mechansim if you have your own login UI.
<EthersAppContext customGetEthersAppProviderLibrary={customFunction}>
<YourMainPage />
</EthersAppContext>
In the above example customFunction
should be a function that returns a TEthersProvider:
export type TGetEthersAppProviderLibrary = () => TEthersProvider;
export type TGetEthersAppProviderLibrary = (
provider: TEthersProvider | ExternalProvider | JsonRpcFetchFunc | any
) => TEthersProvider;
Using ethersAppContext with web3Modal
Ethers context will automatically give you a way to integrate web3Modal into your app.
1. Create your web3Config
The first create a web3Config. Check out their github repo for a detailed explanation: web3 modal. You could also see the example in scaffold-eth-typescript, scaffold-eth-typescript web3ModalConfig.ts
2. Create a function that returns a TEthersModalConnector
This function should have a signature that returns TEthersModalConnector
which is an interface that is implemented by EthersModalConnector
type TCreateEthersModalConnector = (id?: string) => TEthersModalConnector | undefined;
For example in scaffold-eth-typescript createLoginConnector
const createLoginConnector: TCreateEthersModalConnector = useCallback(
(id?: string) => {
if (web3Config) {
const connector = new EthersModalConnector({ ...web3Config, theme: currentTheme }, id);
return connector;
}
},
[web3Config, currentTheme]
);
You can find the details for EthersModalConnector in the api docs.
3. Create a login event handler
You can then call the function we created above in the the event handler of your login button anywhere in your app.
...
const ethersContext = useEthersContext();
const handleLoginClick = (): void => {
if (createLoginConnector != null && ethersContext?.openModal != null) {
const connector = createLoginConnector();
ethersContext.openModal(connector);
}
};
const handleLogoutClick = (): void => {
if (ethersContext?.disconnectModal != null) {
ethersContext.disconnectModal();
}
};
Using ContractAppContext
1. Generating types for your contract
The first thing you'll have to do is generate your contract types for hardhat and external contracts. Add eth-sdk
or typechain with hardhat
to generate that to a folder such as generated/contract-types
. Pull scaffold-eth-typescript for an example of this.
An example on how to use eth-sdk for external contracts
scaffold-eth-typescript uses eth-sdk
to generate types and abi for external contracts using. See the excellent documentation there for this at eth-sdk github. π Note that this would a dev dependency on your project.
An example of using hardhat with typechain
Check out the excellent typechain docs. You can find an example in scaffold-eth-typescript hardhat.config.ts
2. Creating the context with contractsContextFactory
You'll have to create a config that returns a config of your contracts. This would be heterogeneous key value pair. Each value is generated by the helper functions in eth-hooks.
For example:
export const contractConnectorConfig = () => {
try {
const result = {
YourContract: createConnectorForHardhatContract(
'YourContract',
hardhatContracts.YourContract__factory,
hardhatContractsJson
),
DAI: createConnectorForExternalContract('DAI', externalContracts.DAI__factory, externalContractsAddressMap),
UNI: createConnectorForExternalContract('UNI', externalContracts.UNI__factory, externalContractsAddressMap),
} as const;
return result;
} catch (e) {
console.error(
'β contractConnectorConfig: ERROR with loading contracts please run `yarn contracts:build or yarn contracts:rebuild`. Then run `yarn deploy`!',
e
);
}
return undefined;
};
export type TAppConnectorList = NonNullable<ReturnType<typeof contractConnectorConfig>>;
Use contractContextFactory
to create your hooks and context in your app from the above configuration. You could just copy the code below and use it.
export const {
ContractsAppContext,
useAppContractsActions,
useAppContracts,
useLoadAppContracts,
useConnectAppContracts,
} = contractsContextFactory<
keyof TAppConnectorList,
TAppConnectorList,
TTypedContract<keyof TAppConnectorList, TAppConnectorList>
>(contractConnectorConfig);
See scaffold-eth-typescript contractContext.tsx and contractConnectorConfig.ts for full examples on how to do this.
3. Using hooks to get your contracts
Now that you've created the context and hooks above you can use them in your app. The first step is to load your contracts using the hooks you've created with the factory.
useLoadAppContracts();
Next you'll want to connect the contracts.
useConnectAppContracts(asEthersAdaptor(ethersContext));
const [mainnetAdaptor] = useEthersAdaptorFromProviderOrSigners(mainnetProvider);
useConnectAppContracts(mainnetAdaptor);
Now you can get typed contracts anywhere in your app
const yourContract = useAppContracts('YourContract', ethersContext.chainId);
const mainnetDai = useAppContracts('DAI', NETWORKS.mainnet.chainId);
You can read values from the contracts using the useContractReader
hook
const [purpose, update] = useContractReader(
yourContract,
yourContract?.purpose,
[],
yourContract?.filters.SetPurpose()
);
const [purpose, update] = useContractReader(
yourContract,
yourContract?.purpose,
[],
undefined,
{ blockNumberInterval: 10 }
);
Notes
API Documentation
Check out the documentation at the eth-hooks page!
Dependencies
Main package dependencies
- ethers.js
- @uniswap/token-lists
- @web3-react: core, abstractconnector, types
- web3modal
- react-query
Peer dependencies
- react, react/dom
- uniswap/sdk