diff --git a/src/components/AddressCheck.tsx b/src/components/AddressCheck.tsx
index b77f33c84..08c56dba7 100644
--- a/src/components/AddressCheck.tsx
+++ b/src/components/AddressCheck.tsx
@@ -1,20 +1,14 @@
-import React, { useContext, useEffect, useState } from 'react'
+import React, { useContext } from 'react'
import { ContractAddressContext } from '../context/ContractAddressesContext'
import styles from '../css/AddressCheck.module.css'
function AddressCheck() {
const data = useContext(ContractAddressContext)
- const [loading, setLoading] = useState(true)
const checks = data.checks
const failedChecks = data.checks.failedChecks
const allChecksPassed = data.checks.allChecksPassed
- useEffect(() => {
- if (checks && Object.keys(checks).length > 0) {
- // Check if checks object isn't empty
- setLoading(false)
- }
- }, [checks])
+ const loading = !checks || Object.keys(checks).length === 0
if (loading) {
return (
@@ -29,8 +23,6 @@ function AddressCheck() {
)
}
- // allChecksPassed = false // only for testing!!
-
// Log failed checks to the console
if (!allChecksPassed) {
console.log('Some checks failed:', failedChecks)
diff --git a/src/components/ContractAddress.tsx b/src/components/ContractAddress.tsx
index 3d7e479e9..8c9a23795 100644
--- a/src/components/ContractAddress.tsx
+++ b/src/components/ContractAddress.tsx
@@ -1,4 +1,4 @@
-import React, { useContext, useState, useEffect } from 'react'
+import React, { useContext } from 'react'
import { ContractAddressContext } from '../context/ContractAddressesContext'
/**
@@ -14,19 +14,13 @@ import { ContractAddressContext } from '../context/ContractAddressesContext'
*/
const ContractAddress = ({ contractName }) => {
const data = useContext(ContractAddressContext)
- const [loading, setLoading] = useState(true)
const addresses = data.addresses
+ const loading = !data
const getNestedProperty = (obj, keys) => {
return keys.reduce((acc, key) => acc && acc[key], obj)
}
- useEffect(() => {
- if (data) {
- setLoading(false)
- }
- }, [data])
-
if (loading) {
return Loading Contract Address...
}
diff --git a/src/components/StaticContractAddress.tsx b/src/components/StaticContractAddress.tsx
index 79c3b5624..58e2acf96 100644
--- a/src/components/StaticContractAddress.tsx
+++ b/src/components/StaticContractAddress.tsx
@@ -1,10 +1,7 @@
-import React, { useContext, useState, useEffect } from 'react'
-import { ContractAddressContext } from '../context/ContractAddressesContext'
+import React from 'react'
import * as constants from '../ethereum/constants'
const ContractAddress = ({ contractName }) => {
- const data = useContext(ContractAddressContext)
-
const getNestedProperty = (obj, keys) => {
return keys.reduce((acc, key) => acc && acc[key], obj)
}
diff --git a/src/context/ContractAddressesContext.tsx b/src/context/ContractAddressesContext.tsx
index d16c65f5a..45a5276dd 100644
--- a/src/context/ContractAddressesContext.tsx
+++ b/src/context/ContractAddressesContext.tsx
@@ -13,7 +13,7 @@ import { ContractAddresses } from '../ethereum/types'
export const ContractAddressContext = createContext<{
addresses: ContractAddresses | Record
checks: Record
-}>({ addresses: {}, checks: {} }) // Modified code: Updated context type
+}>({ addresses: {}, checks: {} })
/**
* Provides contract addresses to the component tree.
@@ -43,17 +43,17 @@ export const ContractAddressProvider = ({ children }) => {
useEffect(() => {
const fetchAddresses = async () => {
try {
- let checkFlag: boolean | undefined
+ let checkFlag: boolean | undefined = true
const failedChecks: string[] = []
- checkFlag = true
+
const topLevelData = await fetchTopLevelAddressesFromENS(
publicClient,
checkFlag,
failedChecks
)
- checkFlag = topLevelData?.checkFlag
if (!topLevelData)
throw new Error('Failed to fetch top-level contract addresses')
+ checkFlag = topLevelData.checkFlag
const protocolPeripheryData = await fetchAndCheckProtocolAddresses(
topLevelData.addresses.v3ProtocolAddressProvider,
@@ -61,9 +61,9 @@ export const ContractAddressProvider = ({ children }) => {
checkFlag,
failedChecks
)
- checkFlag = protocolPeripheryData?.checkFlag
if (!protocolPeripheryData || !protocolPeripheryData?.addresses)
throw new Error('Failed to fetch protocol addresses')
+ checkFlag = protocolPeripheryData.checkFlag
const releaseRegistryData = await fetchAndCheckFromReleaseRegistry(
topLevelData.addresses.v3ReleaseRegistry,
@@ -71,9 +71,9 @@ export const ContractAddressProvider = ({ children }) => {
checkFlag,
failedChecks
)
- checkFlag = releaseRegistryData?.checkFlag
if (!releaseRegistryData)
throw new Error('Failed to fetch release registry addresses')
+ checkFlag = releaseRegistryData?.checkFlag
const yearnV3Data = await fetchAndCheckYearnV3Addresses(
topLevelData.addresses.v3RoleManager,
@@ -81,8 +81,8 @@ export const ContractAddressProvider = ({ children }) => {
checkFlag,
failedChecks
)
- checkFlag = yearnV3Data?.checkFlag
if (!yearnV3Data) throw new Error('Failed to fetch Yearn V3 addresses')
+ checkFlag = yearnV3Data.checkFlag
const addressesData: ContractAddresses = {
topLevel: topLevelData.addresses,
diff --git a/src/context/ContractDataContext.tsx b/src/context/ContractDataContext.tsx
index b083cc6d6..77a635e35 100644
--- a/src/context/ContractDataContext.tsx
+++ b/src/context/ContractDataContext.tsx
@@ -1,16 +1,20 @@
-// src/context/ContractDataContext.tsx
-import React, { createContext, useState, useEffect, useContext } from 'react'
+import React, {
+ createContext,
+ useState,
+ useEffect,
+ useContext,
+ useMemo,
+} from 'react'
import { PublicClientContext } from './PublicClientContext'
import * as ABIs from '../ethereum/ABIs'
-import { createPublicClient, getContract, http, getAddress } from 'viem'
-import { mainnet } from 'viem/chains'
+import { getAddress, getContract } from 'viem'
-interface MethodWithArgs {
+type MethodWithArgs = {
name: string
args: string[]
}
-interface ContractReadData {
+type ContractReadData = {
name: string
chain: string
address: string
@@ -39,69 +43,102 @@ const isContractReadData = (obj: any): obj is ContractReadData => {
export const ContractDataContext = createContext({})
-export const ContractDataProvider = ({ children, contractParams }) => {
- const [data, setData] = useState({})
- const publicClient = useContext(PublicClientContext)
+/**
+ * Fetches data from multiple contract read calls and updates the state with the results.
+ *
+ * @param {ContractReadData[]} contractReadParams - An array of contract read parameters, each containing the contract address, ABI name, and methods to call.
+ * @param {any} publicClient - The public client used to interact with the blockchain.
+ * @param {Record} ABIs - A record of ABI names to ABI definitions.
+ * @param {(value: React.SetStateAction<{}>) => void} setData - A function to update the state with the fetched data.
+ *
+ * @returns {Promise} A promise that resolves when all contract read calls have been completed and the state has been updated.
+ *
+ * @throws Will throw an error if there is an issue with fetching contract data.
+ */
+const fetchData = async (
+ contractReadParams: ContractReadData[],
+ publicClient,
+ ABIs,
+ setData: {
+ (value: React.SetStateAction<{}>): void
+ (arg0: (prevData: any) => any): void
+ }
+) => {
+ try {
+ for (const contractReadCall of contractReadParams) {
+ const address = contractReadCall.address
+ const abi = ABIs[contractReadCall.abiName]
- useEffect(() => {
- const fetchData = async () => {
- try {
- const contractReadParams: ContractReadData[] = []
- for (const rpcCall of contractParams) {
- if (isContractReadData(rpcCall)) {
- contractReadParams.push(rpcCall)
- } else {
- console.error('Invalid contract read data:', rpcCall)
- }
+ if (!publicClient) {
+ console.error('publicClient is null')
+ return
+ }
+
+ const contract = getContract({
+ address: getAddress(address),
+ abi: abi,
+ client: publicClient,
+ })
+
+ // Dynamically call methods from contractReadCall
+ const methodCalls = contractReadCall.methods.map((method) => {
+ if (typeof method === 'string') {
+ // @ts-ignore
+ return contract.read[method]()
+ } else {
+ // @ts-ignore
+ return contract.read[method.name](method.args)
}
- for (const contractReadCall of contractReadParams) {
- const address = contractReadCall.address
+ })
- const abi = ABIs[contractReadCall.abiName]
+ const results = await Promise.all(methodCalls) // Await all method calls
- if (!publicClient) {
- console.error('publicClient is null')
- return
+ setData((prevData) => {
+ const newData = { ...prevData }
+ results.forEach((result, index) => {
+ const methodName =
+ typeof contractReadCall.methods[index] === 'string'
+ ? contractReadCall.methods[index]
+ : contractReadCall.methods[index].name
+ if (!newData[contractReadCall.name]) {
+ newData[contractReadCall.name] = {}
}
- const contract = getContract({
- address: getAddress(address),
- abi: abi,
- client: publicClient,
- })
-
- // Dynamically call methods from contractReadCall
- const methodCalls = contractReadCall.methods.map((method) => {
- if (typeof method === 'string') {
- return contract.read[method]() // Call method without arguments
- } else {
- return contract.read[method.name](method.args) // Call method with arguments
- }
- })
+ newData[contractReadCall.name][methodName] = result
+ })
+ return newData
+ })
+ }
+ } catch (error) {
+ console.error('Error fetching contract data:', error)
+ }
+}
- const results = await Promise.all(methodCalls) // Await all method calls
+/**
+ * Provides contract data to its children components.
+ *
+ * This context provider fetches on-chain data based on the provided contract parameters
+ * and makes it available to its children components via context.
+ *
+ * @param {Object} props - The props object.
+ * @param {React.ReactNode} props.children - The child components that will have access to the contract data.
+ * @param {Array} props.contractParams - The parameters used to fetch contract data.
+ *
+ * @returns {JSX.Element} The context provider component that supplies contract data.
+ */
+export const ContractDataProvider = ({ children, contractParams }) => {
+ const [data, setData] = useState({})
+ const publicClient = useContext(PublicClientContext)
- setData((prevData) => {
- const newData = { ...prevData }
- results.forEach((result, index) => {
- const methodName =
- typeof contractReadCall.methods[index] === 'string'
- ? contractReadCall.methods[index]
- : contractReadCall.methods[index].name
- if (!newData[contractReadCall.name]) {
- newData[contractReadCall.name] = {}
- }
- newData[contractReadCall.name][methodName] = result
- })
- return newData
- })
- }
- } catch (error) {
- console.error('Error fetching contract data:', error)
- }
- }
+ // Memoize contractReadParams to prevent unnecessary re-renders
+ const contractReadParams = useMemo(
+ () => contractParams.filter(isContractReadData),
+ [contractParams]
+ )
- fetchData()
- }, [contractParams, publicClient])
+ useEffect(() => {
+ console.log('fetching on-chain data...')
+ fetchData(contractReadParams, publicClient, ABIs, setData)
+ }, [contractReadParams, publicClient])
return (