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
π Check out the documentation at Eth-hooks-documentation
See this video summary on v4 features!
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.
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.
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.
Check out the documentation at the eth-hooks page!
Ethers App Context
- useBlockNumberContext
- useEthersContext
Network
- useBalance
- useBlockNumber
- useContractExistsAtAddress
- useEventListener
- useGasPrice
- useNonce
- useSignerAddress
Contracts
- useContractReader
- contractContextFactory
- useLoadAppContracts
- useConnectAppContracts
- useConnectAppContracts
ERC
- useTokenBalance
Dapps
- useDexEthPrice
- useDexTokenList
- useResolveEnsAddress
- useResolveEnsName
Utilities
- useBurnerSigner
yarn add 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
An example of using the context
const ethersContext = useEthersContext();
// you now have access to signer, provider, account (address), etc... See IEthersContext for details
An example of using a hook
// ---------------------
// π¦ get your balance
// ---------------------
// This instance uses the provider from the context in useBalance internally
const [yourLocalBalance, update, status] = useBalance(ethersContext.account);
Z;
An example of changing an update interval
// normally the hooks update every block
const [yourLocalBalance, update, status] = useBalance(ethersContext.account);
// you can change the update schedule to every 10 blocks, the default is every 1 block:
const [yourLocalBalance, update, status] = useBalance(ethersContext.account, { blockNumberInterval: 10 });
// you can change the update schedule to every polling, min is 10000ms
const [yourLocalBalance, update, status] = useBalance(ethersContext.account, {
refetchInterval: 100000,
blockNumberInterval: undefined,
});
// you can use advanced react-query update options
const [yourLocalBalance, update, status] = useBalance(ethersContext.account, {
blockNumberInterval: 1,
query: { refetchOnWindowFocus: true },
});
An example of overriding the provider from the context
// get an adaptor from a provider or signer
const [mainnetAdaptor] = useEthersAdaptorFromProviderOrSigners(exampleMainnetProvider);
// pass in the override variable
const [yourMainnetBalance] = useBalance(ethersContext.account, mergeDefaultUpdateOptions(), {
adaptorEnabled: true,
adaptor: mainnetAdaptor,
});
Check out examples in scaffold-eth-typescript in useScaffoldHooksExamples.tsx
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:
// a simple example
export type TGetEthersAppProviderLibrary = () => TEthersProvider;
// a function that transforms a provider into a TEthersProvider
export type TGetEthersAppProviderLibrary = (
provider: TEthersProvider | ExternalProvider | JsonRpcFetchFunc | any
) => TEthersProvider;
Ethers context will automatically give you a way to integrate web3Modal into your app.
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
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
// theme: can be 'light' or 'dark'
// web3Config: is for web3Modal configuration
// id: allows you to programatically to a provider defined for the modal, see the web3Modal for details.
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.
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();
// to handle a login
const handleLoginClick = (): void => {
if (createLoginConnector != null && ethersContext?.openModal != null) {
const connector = createLoginConnector();
ethersContext.openModal(connector);
}
};
// to handle a log out
const handleLogoutClick = (): void => {
if (ethersContext?.disconnectModal != null) {
ethersContext.disconnectModal();
}
};
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.
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.
- a config of
{contractNames: address}
externalContractConfig.ts - a config for eth-sdk-config.ts
- and calling the
eth-sdk
with the folder of your config file as a parameter e.g.yarn eth-sdk -p ./src/generated
Check out the excellent typechain docs. You can find an example in scaffold-eth-typescript hardhat.config.ts
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:
// a function that generates the config. Note that your types have to exist already!
export const contractConnectorConfig = () => {
try {
const result = {
// ππ½ββοΈ Add your hadrdhat contracts here
YourContract: createConnectorForHardhatContract(
'YourContract',
hardhatContracts.YourContract__factory,
hardhatContractsJson
),
// ππ½ββοΈ Add your external contracts here, make sure to define the address in `externalContractsConfig.ts`
DAI: createConnectorForExternalContract('DAI', externalContracts.DAI__factory, externalContractsAddressMap),
UNI: createConnectorForExternalContract('UNI', externalContracts.UNI__factory, externalContractsAddressMap),
// ππ½ββοΈ Add your external abi here (unverified contracts)`
// DAI: createConnectorForExternalAbi('DAI', { 1: {address: 'xxxx'}}, abi),
} 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;
};
// create a type from the return value of the function above
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.
// you're passing in function `contractConnectorConfig` from above into the factory. You then have to use the type we defined to type the factory outputs.
export const {
ContractsAppContext,
useAppContractsActions,
useAppContracts,
useLoadAppContracts,
useConnectAppContracts,
} = contractsContextFactory<
/* the contractNames (keys) in config output */
keyof TAppConnectorList,
/* the type of the config output */
TAppConnectorList,
/* A type that infers the value of each contractName: contract pair*/
TTypedContract<keyof TAppConnectorList, TAppConnectorList>
>(contractConnectorConfig);
See scaffold-eth-typescript contractContext.tsx and contractConnectorConfig.ts for full examples on how to do this.
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.
// π» load contracts
useLoadAppContracts();
Next you'll want to connect the contracts.
// π connect to contracts for current network & signer
useConnectAppContracts(asEthersAdaptor(ethersContext));
// π connect to contracts for mainnet network & signer
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
// keep track of a variable from the contract in the local React state:
const [purpose, update] = useContractReader(
/* the contract */
yourContract,
/* the contract variable or function to read */
yourContract?.purpose,
/* the arguments, they are typed tuple */
[],
/* optional: if you want your contracts to only update on event */
yourContract?.filters.SetPurpose()
);
// keep track of a variable from the contract in the local React state:
const [purpose, update] = useContractReader(
/* the contract */
yourContract,
/* the contract variable or function to read */
yourContract?.purpose,
/* the arguments, they are typed tuple */
[],
undefined,
/* optional: update every 10 blocks */
{ blockNumberInterval: 10 }
);
Check out the documentation at the eth-hooks page!
- ethers.js
- @uniswap/token-lists
- @web3-react: core, abstractconnector, types
- web3modal
- react-query
- react, react/dom
- uniswap/sdk