{"id":19441495,"url":"https://github.com/dgca/use-wagmi-contracts","last_synced_at":"2025-04-25T00:30:46.433Z","repository":{"id":188114208,"uuid":"678114209","full_name":"dgca/use-wagmi-contracts","owner":"dgca","description":"Convert Solidity ABIs into a ready-to-consume React utility functions","archived":false,"fork":false,"pushed_at":"2023-09-06T17:44:22.000Z","size":329,"stargazers_count":26,"open_issues_count":2,"forks_count":6,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-10-31T17:57:54.530Z","etag":null,"topics":["ethereum","react","solidity","viem","wagmi"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dgca.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2023-08-13T18:16:14.000Z","updated_at":"2024-09-10T23:02:01.000Z","dependencies_parsed_at":"2023-08-13T20:53:06.590Z","dependency_job_id":null,"html_url":"https://github.com/dgca/use-wagmi-contracts","commit_stats":null,"previous_names":["dgca/use-wagmi-contracts"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dgca%2Fuse-wagmi-contracts","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dgca%2Fuse-wagmi-contracts/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dgca%2Fuse-wagmi-contracts/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dgca%2Fuse-wagmi-contracts/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dgca","download_url":"https://codeload.github.com/dgca/use-wagmi-contracts/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223973523,"owners_count":17234470,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ethereum","react","solidity","viem","wagmi"],"created_at":"2024-11-10T15:35:50.323Z","updated_at":"2024-11-10T15:35:51.060Z","avatar_url":"https://github.com/dgca.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# `use-wagmi-contracts`\n\n## Description\n\nThis project includes a set of tools to transform Solidity contract ABIs into structured objects containing all contract methods. All methods are strongly typed, and both read and write methods are included.\n\nIt also includes a React hook to automatically provide the required `wagmi` arguments to the contract methods, and a way to provide a default contract address for each of your contracts.\n\nFinally, it includes a utility for those using TypeChain to make processing your contract ABIs even easier.\n\n## Live Demo 🎥\n\nIf you like videos, I put together this demo of creating a project using Rainbowkit + Hardhat + `use-wagmi-contracts` from scratch.\n\n### [Check it out on YouTube](https://www.youtube.com/watch?v=sdL6a28EHcE) 👈\n\n## Requirements\n\n- React 18+\n- Viem 0.x\n- Wagmi 1.x\n  - Note this library does not work with previous verisons of `wagmi` that used `ethers`.\n  - If you are using older versions of `wagmi` + `ethers`, check out [`use-typechain-contracts`](https://www.npmjs.com/package/use-typechain-contracts).\n\n## Installation\n\n```\nyarn add @type_of/use-wagmi-contracts\n# or\nnpm install @type_of/use-wagmi-contracts\n```\n\n## Setup\n\nThe recommended way to use this library is to use the `WagmiContractsProvider` component to wrap your app. This will give you a convenient `useContracts()` hook that you can use to access your contracts, and all contract methods will have the appropriate `wagmi` arguments bound to them already.\n\nTo keep things organized, create a new file to initialize the library. In this example, we'll refer to this as `/path/to/WagmiContractsProvider`.\n\nInitialize the library using `initUseWagmiContracts`. It expects an `AbiMap`, which is an object with the following shape below.\n\n```tsx\nconst abiMap = {\n  ContractName: {\n    abi: ContractAbi,\n    defaultAddress: \"0x1234...\", // Optional\n  },\n  OtherContract: {\n    abi: OtherAbi,\n  },\n  ...\n}\n```\n\n---\n\n### \u003cspan style=\"color:red\"\u003eNote to TypeChain users:\u003c/span\u003e\n\nIf you are using the TypeChain library to generate your contract ABIs, you can use the `processTypechainAbis` function to generate the `AbiMap` for you. See the \"Using TypeChain\" section.\n\n---\n\nThe keys of the `AbiMap` are the names that you'll use later to refer to your contracts. `defaultAddress` is optional, and can be used to provide a default address for your contract. If you don't provide a default address, you'll need to provide one when you call the contract methods.\n\nOnce you have your `AbiMap`, you can initialize the library by calling `initUseWagmiContracts` with your `AbiMap`.\n\nThis returns an object with two properties: `WagmiContractsProvider` and `useContracts`. Export these for later consumption.\n\n```tsx\n// /path/to/WagmiContractsProvider.tsx\nimport { initUseWagmiContracts } from \"@type_of/use-wagmi-contracts\";\n\nconst abiMap = {...};\n\nconst { WagmiContractsProvider, useContracts } = initUseWagmiContracts(abiMap);\n\nexport { WagmiContractsProvider, useContracts };\n```\n\n### Using TypeChain\n\nIf you use TypeChain to generate your contract ABIs, you can use the `processTypechainAbis` function to generate the `AbiMap` for you. Assuming you have a `typechain-types` directory in your project, you can do the following:\n\n```tsx\n// /path/to/WagmiContractsProvider.tsx\nimport { initUseWagmiContracts, processTypechainAbis } from \"@type_of/use-wagmi-contracts\";\nimport * as typechain from '/path/to/typechain-types';\n\nconst abiMap = processTypechainAbis(typechain, {\n  ContractName: {\n    defaultAddress: \"0x1234...\",\n  },\n});\n\nconst { WagmiContractsProvider, useContracts } = initUseWagmiContracts(abiMap);\n\nexport { WagmiContractsProvider, useContracts };\n```\n\nThe second argument to `processTypechainAbis` is an object that allows you to provide default addresses for your contracts. If you don't provide a default address, you'll need to provide one when you call the contract methods.\n\n### Wrapping your app with `WagmiContractsProvider`\n\nNext, wrap your app with the `WagmiContractsProvider` component you created. Note that this must go inside the `\u003cWagmiConfig\u003e` component since calls `wagmi` hooks.\n\n```tsx\nimport { WagmiContractsProvider } from \"/path/to/WagmiContractsProvider\";\n\nexport function App({ children }) {\n  return (\n    \u003cWagmiConfig config={wagmiConfig}\u003e\n      \u003cWagmiContractsProvider\u003e\n        {children}\n      \u003c/WagmiContractsProvider\u003e\n    \u003c/WagmiConfig\u003e\n  )\n}\n```\n\nThat's it! You can now use the `useContracts` hook to access your contracts and call their methods.\n\n## Communicating with contracts\n\nTo communicate with your your contracts, use the `useContracts` hook. This hook returns a map of your contracts, with each contract containing a map of its methods.\n\n### Using the viem `readContract` and `writeContract` approach\n\nSay we have a very simple contract that looks like this:\n\n```js\ncontract ValueStore {\n  bool public value = false;\n\n  function getValue() external view returns(bool) {\n    return value;\n  }\n\n  function setValue(bool _nextValue) external returns(bool) {\n    value = _nextValue;\n    return value;\n  }\n}\n```\n\nAssume we named this contract \"ValueStore\" in the `AbiMap`, and we provided a default address. If we want to get the value, we can do the following:\n\n(Note that this is a very bare bones approach to data fetching, and I would recommend using something like `@tanstack/react-query` to handle caching and data invalidation.)\n\n```tsx\nimport { useContracts } from \"/path/to/WagmiContractsProvider\";\n\nfunction GetValueDemo() {\n  const contracts = useContracts();\n  const [value, setValue] = useState\u003cboolean | null\u003e(null);\n\n  useEffect(() =\u003e {\n    const getValue = async () =\u003e {\n      /**\n       * Note that we don't need to provide an address to `ValueStore()` since we\n       * provided a default address in * the AbiMap.\n       *\n       * Also note that getValue takes no arguments because the contract method also\n       * takes no arguments. We'll see an example that takes arguments below.\n       */\n      const value = await contracts.ValueStore().getValue();\n      setValue(value);\n    }\n\n    getValue();\n  }, [contracts]);\n\n  if (value === null) return null;\n\n  return (\n    \u003cp\u003eThe value is: {value ? 'TRUE' : 'FALSE'}\u003c/p\u003e\n  );\n}\n```\n\nThat's a very simple example of a read method. Now, let's look at a write method.\n\n```tsx\nimport { useContracts } from \"/path/to/WagmiContractsProvider\";\n\nfunction SetValueDemo() {\n  const contracts = useContracts();\n  const [lastWrittenValue, setLastWrittenValue] = useState\u003cboolean | null\u003e(null);\n\n  const handleWrite = useCallback(async () =\u003e {\n    try {\n      /**\n       * The function signature for `setValue` will be typed based on the contract ABI.\n       *\n       * Unlike read methods, write methods return a tuple of `[hash, result]``. The hash\n       * is the transaction hash, and the result is the return value of the method. If the\n       * method doesn't return anything, the result will be `undefined`.\n       */\n      const [hash, result] = await contracts.ValueStore().setValue(Math.random() \u003e 0.5);\n      setLastWrittenValue(result);\n      console.log('Success!');\n    } catch (err) {\n      console.error(err);\n    }\n  }, [contracts]);\n\n  return (\n    \u003cdiv\u003e\n      \u003cp\u003e\n        The last written value was: {lastWrittenValue === null\n          ? 'null'\n          : lastWrittenValue ? 'TRUE' : 'FALSE'}\n      \u003c/p\u003e\n      \u003cbutton onClick={handleWrite}\u003e\n        Set Random Value\n      \u003c/button\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n### Using wagmi's `useContractRead` and `useContractWrite` hooks\n\nThis library also provides wrappers around wagmi's `useContractRead` and `useContractWrite` hooks for every contract method. Note that for simplicity and to differentiate, ours are named `useRead` and `useWrite`.\n\nTo learn how to use them, let's look at an example. We'll use the same contract example as above.\n\n```js\ncontract ValueStore {\n  bool public value = false;\n\n  function getValue() external view returns(bool) {\n    return value;\n  }\n\n  function setValue(bool _nextValue) external returns(bool) {\n    value = _nextValue;\n    return value;\n  }\n}\n```\n\nWagmi's `useContractRead` and `useContractWrite` hooks are wrappers over `react-query`, and they return an object with properties about your request, such as `loading`, `data`, `error`, etc. The return value of these hooks will be a React Query `useQuery` or `useMutation` hook, depending on whether the method is a read or write method. Read the [`react-query` docs](https://tanstack.com/query/v3/) for more information.\n\nTo read contract data, you can do the following:\n\n```tsx\nimport { useContracts } from \"/path/to/WagmiContractsProvider\";\n\nfunction GetValueDemo() {\n  const contracts = useContracts();\n\n  const valueResult = contracts.ValueStore().getValue.useRead();\n\n  if (valueResult.loading) return null;\n\n  return (\n    \u003cp\u003eThe value is: {valueResult.data ? 'TRUE' : 'FALSE'}\u003c/p\u003e\n  );\n}\n```\n\nTo write data using `useWrite`, you can do the following:\n\n```tsx\nimport { useContracts } from \"/path/to/WagmiContractsProvider\";\n\nfunction SetValueDemo() {\n  const contracts = useContracts();\n  const handleSetValue = contracts.ValueStore().setValue.useWrite({\n    args: [Math.random() \u003e 0.5]\n  });\n\n  return (\n    \u003cdiv\u003e\n      \u003cbutton onClick={handleSetValue.write}\u003e\n        Set Random Value\n      \u003c/button\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\nBoth `useRead` and `useWrite` take an object as their argument, and this object is merged with wagmi's `useContractRead` and `useContractWrite` hooks. This means you can pass any of the options that `useContractRead` and `useContractWrite` accept.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdgca%2Fuse-wagmi-contracts","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdgca%2Fuse-wagmi-contracts","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdgca%2Fuse-wagmi-contracts/lists"}