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.