Comparing addresses

This started as a Moralis question about how to retrieve the userā€™s address. Itā€™s become a basic JavaScript question about how to compare addresses as strings.

Historical Context

Interesting. Well Iā€™m having ā€˜funā€™ writing custom ReactJS hooks and thatā€™s new. But it has its limits. For example hooks from within hooks just loop to infinity.

import { useEffect, useState } from "react";
import { useMoralis } from "react-moralis";

export const useUserAddress = (props) => {
  const { isAuthenticated, user } = useMoralis();
  const [address, setAddress] = useState();
  useEffect(() => {
    if (isAuthenticated) {
      setAddress(user.attributes[props.chain + "Address"]);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isAuthenticated, props.chain]);

  return { address };
};

useUserAddress.defaultProps = {
  chain: "eth",
};

And when I try loading it in my componentā€¦

import { useUserAddress } from "../../hooks/useUserAddress";
import { useTransactions } from "../../hooks/useTransactions";

export const TransactionList = (props) => {
  const { userAddress } = useUserAddress;
  const { Txs, isLoading } = useTransactions(userAddress);

And passing it as a prop:

export const useTransactions = (props) => {
  const { Moralis } = useMoralis();
  const [Txs, setTxs] = useState(emptyList);
  const [isLoading, setIsLoading] = useState(true);
  console.groupCollapsed("useTransactions");
13  console.log(
    props.usrAddress !== "0x"
      ? props.usrAddress + " is authenticated."
      : "Unauthenticated."
  );
...
useTransactions.defaultProps = {
  usrAddress: "0x",
};

I get TypeError: Cannot read property 'usrAddress' of undefined on line 13.

So here I am with this:

import { useEffect, useState } from "react";
import { useMoralis } from "react-moralis";

const emptyList = [];

export const useTransactions = (props) => {
  const { isAuthenticated, Moralis, user } = useMoralis();
  const [address, setAddress] = useState("0x");
  const [Txs, setTxs] = useState(emptyList);
  const [isLoading, setIsLoading] = useState(true);
  console.groupCollapsed("useTransactions");
  console.log(
    isAuthenticated !== "0x"
      ? address + " is authenticated."
      : "Unauthenticated."
  );

  useEffect(() => {
    if (isAuthenticated) {
      setAddress(user.attributes[props.chain + "Address"]);
      Moralis.Web3.getTransactions({ usePost: true }).then((userTrans) => {
        let newTxs = userTrans.map((Tx) => {
          const output = { ...Tx };
          if (Tx.fromAddr === address) {
            output.counterparty = Tx.to_address;
            output.amount = -1 * parseFloat(Tx.value);
          } else {
            output.counterparty = Tx.from_address;
            output.amount = parseFloat(Tx.value);
          }
          return output;
        });
        setTxs(newTxs);
        setIsLoading(false);
      });
    } else {
      setTxs(emptyList);
      setIsLoading(true);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [Moralis.Web3, isAuthenticated]);

  console.log(isLoading ? "Transactions loading..." : "Returning Txs: ", Txs);
  console.groupEnd();

  return { Txs, isLoading };
};

And Iā€™m getting this non-compare:
image

Which means this if stanza is failing its compare (no, the to_address is not the same too):

if (Tx.fromAddr === address) {
   output.counterparty = Tx.to_address;
   output.amount = -1 * parseFloat(Tx.value);
} else {
   output.counterparty = Tx.from_address;
   output.amount = parseFloat(Tx.value);
 }

And Iā€™ve tried using Stringā€™s .equalto(), but I canā€™t get the typecast to stick and it only gives me String(Tx.fromAddr).equalto() is not a function.

Thoughts?

Mia culpa. Speling counts. :face_with_monocle:

import { useEffect, useState } from "react";
import { useMoralis } from "react-moralis";

const emptyList = [];

export const useTransactions = (props) => {
  const { isAuthenticated, Moralis, user } = useMoralis();
  const [address, setAddress] = useState("0x");
  const [Txs, setTxs] = useState(emptyList);
  const [isLoading, setIsLoading] = useState(true);
  console.groupCollapsed("useTransactions");
  console.log(
    isAuthenticated !== "0x"
      ? address + " is authenticated."
      : "Unauthenticated."
  );

  useEffect(() => {
    if (isAuthenticated) {
      setAddress(user.attributes[props.chain + "Address"]);
      Moralis.Web3.getTransactions({ usePost: true }).then((userTrans) => {
        let newTxs = userTrans.map((Tx) => {
          const output = { ...Tx };
          switch (address) {
            case Tx.from_address:
              output.counterparty = Tx.to_address;
              output.amount = -1 * parseFloat(Tx.value);
              break;
            case Tx.to_address:
              output.counterparty = Tx.from_address;
              output.amount = 1 * parseFloat(Tx.value);
              break;
            case undefined:
              output.counterparty = undefined;
              output.amount = undefined;
              break;
            default:
              output.counterparty = null;
              output.amount = null;
              break;
          }
          return output;
        });
        setTxs(newTxs);
        setIsLoading(false);
      });
    } else {
      setTxs(emptyList);
      setIsLoading(true);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [Moralis.Web3, isAuthenticated]);

  console.log(isLoading ? "Transactions loading..." : "Returning Txs: ", Txs);
  console.groupEnd();

  return { Txs, isLoading };
};

image

Works!

But if Iā€™m a user now Iā€™m looking at this wondering ā€œwtf is all this chicken scratch?ā€ It needs to look up name and symbol from those counterparty addresses, if available.

put the console.log of address in the useEffect() where itā€™s being comparedā€¦ perhaps the value of address doesnā€™t have the updated value at the time of comparison.Perhaps this is better.

const userAddress = user.attributes[props.chain + "Address"]
setAddress(userAddress)
...
if (Tx.fromAddr === userAddress) {
 ... etc
}

EDIT : oh I see you got it working. good stuff! :partying_face:

Iā€™ve been burned using console.log inside useEffect() before. Itā€™s not a stable pattern. Falling back it worked to force the inputs across to the outputs as I did in my switch() stanza above. Old Fortran trick. That helped me identify my spelling mistake.

And it doesnā€™t trip the Observer Effect, which runs wild in React callbacks.