Ethereum Boilerplate: Fetching USD Values for Token Balances

Hi, here is the ERC20Balance Component from the Ethereum boilerplate code.

import { useMoralis } from "react-moralis";
import { useERC20Balance } from "../hooks/useERC20Balance";
import { Skeleton, Table } from "antd";
import { getEllipsisTxt } from "../helpers/formatters";
import useTokenPrice from "hooks/useTokenPrice";

const styles = {
  title: {
    fontSize: "30px",
    fontWeight: "700",
  },
};
function ERC20Balance(props) {
  const { assets } = useERC20Balance(props);
  const { Moralis } = useMoralis();

  const columns = [
    {
      title: "",
      dataIndex: "logo",
      key: "logo",
      render: (logo) => (
        <img
          src={logo || "https://etherscan.io/images/main/empty-token.png"}
          alt="nologo"
          width="28px"
          height="28px"
        />
      ),
    },
    {
      title: "Name",
      dataIndex: "name",
      key: "name",
      render: (name) => name,
    },
    {
      title: "Symbol",
      dataIndex: "symbol",
      key: "symbol",
      render: (symbol) => symbol,
    },
    {
      title: "Balance",
      dataIndex: "balance",
      key: "balance",
      render: (value, item) =>
        parseFloat(Moralis.Units.FromWei(value, item.decimals).toFixed(6)),
    },
    {
      title: "Address",
      dataIndex: "token_address",
      key: "token_address",
      render: (address) => getEllipsisTxt(address, 5),
    },
  ];

  console.log(assets)

  return (
    <div style={{ width: "80vw", padding: "15px", marginBottom:"2rem" }}>
      <h1 style={styles.title}>Token Balances</h1>
      <Skeleton loading={!assets}>
        <Table
        scroll={{ x: 1500 }}
          dataSource={assets}
          columns={columns}
          size="small"
          rowKey={(record) => {
            return record.token_address;
          }}
        />
      </Skeleton>
    </div>
  );
}
export default ERC20Balance;

Question

Is there a way to create a value column in which we can get the balance x price for each token? I have been experimenting with a couple of methods, and this component seemed like the perfect place (at least for me) to integrate such a thing.

Experimentation

We can use the useTokenPrice hook but it does not work while rendering, and each column would have to be associated with one another via the dataIndex and key such that we can have both address and balance together in order to fetch the price via the address and multiply it by the balance.

Suggestions

I cannot figure out a workaround, let me know if any of you can solve the issue :slight_smile:

Hi @achello

You can import hook useTokenPrice and using useEffect and useState calculate and set the value in USD. Let me know if you have any questions

@Yomoo

So the main issue is that:

useTokenPrice needs an address and a chain (the chain is not important at the moment but will be addressed later on as I will hardcode the value for now)

the useERC20Balance hook provides us with the balance and address of all the tokens for the given wallet

useEffect does not accept custom hooks within it, so we cannot call useTokenPrice if we were to iterate through all assets

Now,

We need a method to get the assets when fetched, get the address of each individual asset, plug. this address into the useTokenPrice hook and then multiply this price by the individual token balance of the specified token.

P.S. the useTokenPrice is used only for one token, so how might we apply this to the entire list?

I have tried with no avail, if you can could you please share how one might solve this issue with code provided? :slight_smile:

@Yomoo

const [address, setTokenAdd] = useState([]);

  useEffect(() => {
       if (assets) {
         assets.map((token) => {
          setTokenAdd( address => [...address, token.token_address])
    })}

  }, [assets]);

  const { tokenPrice } = useTokenPrice({address:address[3], chain:"bsc"})

This is what I was able to do myself, the only problem is that the useTokenPrice hook can only fetch one token price per component. How to solve this?

@Yomoo

This is the final solution I got, but I used Moralis API instead of the hooks, which seems likes a missed opportunity within the boilerplate as it currently does not support multi asset price lookups. This however randomises the tokens on the table each time upon refresh, therefore not the most ideal solution.

  const [tokens, setTokens] = useState([]);

  useEffect( ()  =>  {
       if (assets) {
         assets.map( async (token)  =>  {
          
          let price = await Moralis.Web3API.token.getTokenPrice({address: token.token_address, chain:"bsc"});
          let balance = parseFloat(Moralis.Units.FromWei(token.balance, token.decimals).toFixed(6))
          let value = price.usdPrice * balance
          value = "$" + (Math.round(value * 100) / 100).toLocaleString()
          console.log(balance)

          let newObj = {
            "logo":token.logo,
            "name": token.name,
            "symbol":token.symbol,
            "balance":balance,
            "token_address":token.token_address,
            "value":value
        }

        setTokens(tokens => [...tokens, newObj])
    })}

  }, [assets]);

Beware of Scams

by the way, there is the problem of scam tokens, where the balance shows tokens for a wallet that have been under a dust attack with misleading prices and misleading hopes. Trust Wallet for example mitigates this by giving just the mainstream tokens and lets you add them to your wallet to view if you please, with Moralis instead the issue is that a person using a DApp created with Moralis opens source code thinks they are rich because the balance fetching gets all tokens regardless if they are a scam or not and might fall pray to account hacking.

I will put a disclaimer on the DApp for this issue. Would love if you guys can look into it more!

Hi @achello

Moralis provides data from the blockchain, not a list of trusted tokens. Even scam tokens are information that can be useful to someone. There are various lists of verified tokens. You can do it yourself using a simple javascript array filtering.

@Yomoo
Noted thanks. What about the Moralis Hooks? is there any way I can accomplish the same task using the pre-built hooks?

@Yomoo

By the way, do you have any links to verified token lists?

Take a look at example https://github.com/ethereum-boilerplate/ethereum-boilerplate#usetokenprice

Example:

import { useTokenPrice } from "react-moralis";

const TokenPrice = () => {
  const { fetchTokenPrice, data: formattedData, error, isLoading, isFetching } = useTokenPrice(});

useEffect(()=> {
  fetchTokenPrice({ params: { address: "0x6...361",  chain: "bsc" }, onSuccess: (price) => console.log(price) })
  fetchTokenPrice({ params: { address: "0x6...361",  chain: "bsc" }, onSuccess: (price) => console.log(price) })

})

}