'use strict'
/**
* A Vanilla JS library to simply use EthereumList's data
* @author Dorian Bayart
* @version 0.1.0
* @license MIT
*/
/**
* The URL to fetch data from
* @const {string}
*/
const CHAINLIST_URL = 'https://chainid.network/chains.json'
/**
* A global variable to store fetched data
* @type {ChainList}
*/
let chainList
/**
* A ChainList object
* @class
*/
class ChainList {
/**
* @property {array} list - An array of {@Chain}
*/
#list
/**
* Create a ChainList - Keep chains containing at least one explorer on the EIP-3091 standard
*
* @constructor
* @param {object[]} - An array of unknown objects representing chains data
*/
constructor(list) {
this.#list = list
.filter(chain => chain.explorers?.find(explorer => explorer.standard === 'EIP3091'))
.map(chain => new Chain(chain))
}
/**
* Return a ChainList object
*
* @method
* @async
* @static
* @return {ChainList}
*/
static fetch = async () => {
const response = await fetch(CHAINLIST_URL)
const list = await response.json()
chainList = new ChainList(list)
return chainList
}
/**
* Return all chains
*
* @return {Chain[]} - All the chains
*/
getList() {
return this.#list
}
/**
* Return a chain found by chainId
*
* @param {number} chainId - The chain unique id
* @return {Chain}
*/
getByChainId(chainId) {
return this.getList().find(chain => chain.chainId() === chainId)
}
/**
* Return a list of chains filtered by name
*
* @param {string} name - The name to filter
* @return {Chain[] | null}
*/
searchByName(name) {
return this.getList().filter(chain => chain.name().toLowerCase().includes(name.toLowerCase()))
}
}
/**
* A Chain
* @class
*/
class Chain {
#chain
#chainId
#explorer
#infoURL
#name
#nativeCurrency
#shortName
/**
* Create a Chain
*
* @constructor
* @param {object} data - An object representing a chain
*/
constructor(data) {
this.#chain = data.chain
this.#chainId = data.chainId
this.#explorer = data.explorers?.find(explorer => explorer.standard === 'EIP3091')
this.#infoURL = data.infoURL
this.#name = data.name
this.#nativeCurrency = data.nativeCurrency
this.#shortName = data.shortName
}
/**
* Find or fetch data to build a Chain object
*
* @method
* @async
* @static
* @param {number} - The chainId of the Chain
* @return {Chain}
*/
static fetchChain = async (id) => {
// use the chainList global variable if already fetched
if(chainList && chainList.getList().length) {
return chainList.getList().find(chain => chain.chainId() === id)
}
const response = await fetch(CHAINLIST_URL)
const chains = await response.json()
return new Chain(chains.find(chain => chain.chainId() === id))
}
/**
* Return the chain group name
*
* @return {string}
*/
chain() {
return this.#chain
}
/**
* Return the chainId
*
* @return {number}
*/
chainId() {
return this.#chainId
}
/**
* Return the explorer name
*
* @return {string | undefined}
*/
explorerName() {
if(this.#explorer?.name) return this.#explorer.name
return
}
/**
* Return the explorer base URL
*
* @return {string | undefined}
*/
explorerUrl() {
if(this.#explorer?.url) return this.#explorer.url
return
}
/**
* Return the main URL
*
* @return {string}
*/
infoURL() {
return this.#infoURL
}
/**
* Return the name
*
* @return {string}
*/
name() {
return this.#name
}
/**
* Return the native currency
*
* @return {objct}
*/
nativeCurrency() {
return this.#nativeCurrency
}
/**
* Return the short name - See EIP-3770 https://eips.ethereum.org/EIPS/eip-3770
*
* @return {string}
*/
shortName() {
return this.#shortName
}
/**
* Return a link to Explorer for a given Block Hash
*
* @param {string} blockHashOrHeight - A block hash or block height
* @return {string | null}
*/
block(blockHashOrHeight) {
if(this.explorerUrl()) return `${this.explorerUrl()}/block/${blockHashOrHeight}`
return
}
/**
* Return a link to Explorer for a given Transaction Hash
*
* @param {string} txHash - A transaction hash
* @return {string | null}
*/
tx(txHash) {
if(this.explorerUrl()) return `${this.explorerUrl()}/tx/${txHash}`
return
}
/**
* Return a link to Explorer for a given Address
*
* @param {string} accountAddress - An account address
* @return {string | null}
*/
address(accountAddress) {
if(this.explorerUrl()) return `${this.explorerUrl()}/address/${accountAddress}`
return
}
/**
* Return a link to Explorer for a given ERC-20 Token Address
*
* @param {string} tokenAddress - A token contract address
* @return {string | null}
*/
token(tokenAddress) {
if(this.explorerUrl()) return `${this.explorerUrl()}/token/${tokenAddress}`
return
}
}