Skip to content

Latest commit

 

History

History
160 lines (123 loc) · 4.73 KB

02-display-safe-assets.md

File metadata and controls

160 lines (123 loc) · 4.73 KB

Display a list of Safe's assets

Let's add a table that displays Safe's owned assets to the App. But first, you need the following pieces:

  1. A function that fetches the assets
  2. Table component
  3. Add the table component to the App

Create a file src/hooks/useSafeBalances.ts with the following content:

import SafeAppsSDK, { TokenBalance } from '@gnosis.pm/safe-apps-sdk';
import { useState, useEffect } from 'react';

function useSafeBalances(sdk: SafeAppsSDK): [TokenBalance[], boolean] {
  const [assets, setAssets] = useState<TokenBalance[]>([]);
  const [loaded, setLoaded] = useState(false);

  useEffect(() => {
    async function loadBalances() {
      const balances = await sdk.safe.experimental_getBalances();

      setAssets(balances.items.filter((item) => parseInt(item.fiatBalance) > 0));
      setLoaded(true);
    }

    loadBalances();
  }, [sdk]);

  return [assets, loaded];
}

export { useSafeBalances };

This is useSafeBalance hook that calls the SDK function sdk.safe.experimental_getBalances and filters out tokens with zero fiat balance.

You should import this hook into src/App.tsx and use it to get the list of assets owned by the Safe. Then, remove the documentation link, submitTx function and comment out the button that used the submit function and add the hook:

import React from 'react';
import styled from 'styled-components';
import { Title } from '@gnosis.pm/safe-react-components';
import { useSafeAppsSDK } from '@gnosis.pm/safe-apps-react-sdk';
import { useSafeBalances } from './hooks/useSafeBalances';

const Container = styled.div`
  padding: 1rem;
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
`;

const SafeApp = (): React.ReactElement => {
  const { sdk, safe } = useSafeAppsSDK();
  const [balances] = useSafeBalances(sdk);

  console.log({ balances });

  return (
    <Container>
      <Title size="md">Safe: {safe.safeAddress}</Title>

      {/* <Button size="lg" color="primary">
        Send the assets
      </Button> */}
    </Container>
  );
};

export default SafeApp;

If you load the App inside the Safe, you should see Safe's assets list in the console. Create a Table component that displays the assets.

src/components/BalancesTable.tsx:

import { Table } from '@gnosis.pm/safe-react-components';
import { TokenBalance, TokenInfo } from '@gnosis.pm/safe-apps-sdk';
import BigNumber from 'bignumber.js';

const ethToken: TokenInfo = {
  address: '0x0000000000000',
  type: 'NATIVE_TOKEN',
  logoUri: './eth.svg',
  symbol: 'ETH',
  name: 'Ether',
  decimals: 18,
};

const formatTokenValue = (value: number | string, decimals: number): string => {
  return new BigNumber(value).times(`1e-${decimals}`).toFixed();
};

const formatFiatValue = (value: string, currency: string): string => {
  return new Intl.NumberFormat('en-US', { style: 'currency', currency }).format(parseFloat(value));
};

function Balances({ balances }: { balances: TokenBalance[] }): JSX.Element {
  return (
    <Table
      headers={[
        { id: 'col1', label: 'Asset' },
        { id: 'col2', label: 'Amount' },
        { id: 'col3', label: `Value, USD` },
      ]}
      rows={balances.map((item: TokenBalance, index: number) => {
        const token = item.tokenInfo.type === 'NATIVE_TOKEN' ? ethToken : item.tokenInfo;

        return {
          id: `row${index}`,
          cells: [
            {
              content: (
                <div style={{ display: 'flex', alignItems: 'center' }}>
                  <img src={token.logoUri || undefined} alt={`${token.symbol} Logo`} />
                  {token.name}
                </div>
              ),
            },

            { content: formatTokenValue(item.balance, token.decimals) },
            { content: formatFiatValue(item.fiatBalance, 'USD') },
          ],
        };
      })}
    />
  );
}

export default Balances;

It iterates over the array of balances and creates corresponding DOM elements. It also includes two functions:

  • formatTokenValue - converts the token amount to a human-readable value with decimals
  • formatFiatValue - converts the fiat value according to user's locale

Let's hook it into our App.tsx:

<Container>
  <Title size="md">Safe: {safe.safeAddress}</Title>
  <BalancesTable balances={balances} />

  {/* <Button size="lg" color="primary">
        Send the assets
      </Button> */}
</Container>

Now you should be able to see the assets table when you load the App.

Screenshot display the assets

Congrats! You're halfway through - the only thing left is generating the transaction data for transfers, which you'll learn in the next section - Transfer assets.