classic-ui/services/lookupAddress.js
2022-08-05 17:50:33 +10:00

115 lines
3.4 KiB
JavaScript

// from https://github.com/ChainSafe/web3.js/issues/2683#issuecomment-547348416
import namehash from 'eth-ens-namehash'
import { BigNumber, utils } from 'ethers'
import ABI from 'web3-eth-ens/lib/resources/ABI/Resolver'
import uniq from 'lodash/uniq'
import chunk from 'lodash/chunk'
import { CHUNK_COUNT_PER_BATCH_REQUEST } from '@/constants'
export const createBatchRequestCallback = (resolve, reject) => (error, data) => {
if (error) {
reject(error)
} else {
resolve(data)
}
}
const CACHE = {}
const createFetchNodeAddresses = (registryContract, batch) => async (address) => {
const addressLower = address.toLowerCase()
const node = addressLower.substr(2) + '.addr.reverse'
const nodeHash = namehash.hash(node)
let nodeAddress = null
if (!CACHE[addressLower]) {
try {
nodeAddress = await new Promise((resolve, reject) => {
const callback = createBatchRequestCallback(resolve, reject)
const requestData = registryContract.methods.resolver(nodeHash).call.request(callback)
batch.add(requestData)
})
if (+nodeAddress === 0) nodeAddress = null
} catch (error) {
console.error(`Error resolve ens for "${address}"`, error.message)
// do nothing
}
}
return {
addressLower,
address,
nodeHash,
nodeAddress
}
}
const createFetchEnsNames = (web3, batch, results) => async (data) => {
const { address, addressLower, nodeHash, nodeAddress } = data
if (!nodeAddress) return results
if (CACHE[addressLower]) {
results[address] = CACHE[addressLower]
return results
}
const nodeContract = new web3.eth.Contract(ABI, nodeAddress)
try {
const ensName = await new Promise((resolve, reject) => {
const callback = createBatchRequestCallback(resolve, reject)
const requestData = nodeContract.methods.name(nodeHash).call.request(callback)
batch.add(requestData)
})
const isZeroAddress =
ensName.trim().length && utils.isAddress(ensName) && BigNumber.from(ensName).isZero()
if (isZeroAddress) return results
CACHE[addressLower] = ensName
results[address] = ensName
return results
} catch (error) {
console.error(`Error lookupAddress ens for "${address}"`, error.message)
return results
}
}
export const lookupAddressesRequest = async (addressList, web3, registryContract) => {
const fetchNodeAddressesBatch = new web3.BatchRequest()
const fetchNodeAddresses = createFetchNodeAddresses(registryContract, fetchNodeAddressesBatch)
const fetchNodeAddressesPromises = uniq(addressList).map(fetchNodeAddresses)
fetchNodeAddressesBatch.execute()
const nodeAddresses = await Promise.all(fetchNodeAddressesPromises)
const results = {}
const fetchEnsNamesBatch = new web3.BatchRequest()
const fetchEnsNames = createFetchEnsNames(web3, fetchEnsNamesBatch, results)
const fetchEnsNamesPromises = nodeAddresses.map(fetchEnsNames)
fetchEnsNamesBatch.execute()
await Promise.all(fetchEnsNamesPromises)
return results
}
export const lookupAddresses = async (addressList, web3) => {
const registryContract = await web3.eth.ens.registry.contract
// web3.eth.ens._lastSyncCheck = Date.now() // - need for test in fork
const addressListChunks = chunk(addressList, CHUNK_COUNT_PER_BATCH_REQUEST)
let results = {}
for await (const list of addressListChunks) {
const result = await lookupAddressesRequest(list, web3, registryContract)
results = { ...results, ...result }
}
return results
}