@polkadot/types/interfaces#ProxyType TypeScript Examples

The following examples show how to use @polkadot/types/interfaces#ProxyType. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: useProxies.ts    From crust-apps with Apache License 2.0 6 votes vote down vote up
function createProxy (allAccounts: string[], delegate: AccountId, type: ProxyType, delay = BN_ZERO): Proxy {
  const address = delegate.toString();

  return {
    address,
    delay,
    isOwned: allAccounts.includes(address),
    type
  };
}
Example #2
Source File: useProxies.ts    From crust-apps with Apache License 2.0 6 votes vote down vote up
export default function useProxies (address?: string | null): State {
  const { api } = useApi();
  const { allAccounts } = useAccounts();
  const mountedRef = useIsMountedRef();
  const [known, setState] = useState<State>(EMPTY_STATE);

  useEffect((): void => {
    setState(EMPTY_STATE);

    address && api.query.proxy &&
      api.query.proxy
        .proxies<ITuple<[Vec<ITuple<[AccountId, ProxyType]> | ProxyDefinition>, BalanceOf]>>(address)
        .then(([_proxies]): void => {
          const proxies = api.tx.proxy.addProxy.meta.args.length === 3
            ? (_proxies as ProxyDefinition[]).map(({ delay, delegate, proxyType }) =>
              createProxy(allAccounts, delegate, proxyType, delay)
            )
            : (_proxies as [AccountId, ProxyType][]).map(([delegate, proxyType]) =>
              createProxy(allAccounts, delegate, proxyType)
            );
          const owned = proxies.filter(({ isOwned }) => isOwned);

          mountedRef.current && setState({
            hasOwned: owned.length !== 0,
            owned,
            proxies
          });
        })
        .catch(console.error);
  }, [allAccounts, api, address, mountedRef]);

  return known;
}
Example #3
Source File: Address.tsx    From crust-apps with Apache License 2.0 6 votes vote down vote up
function filterProxies (allAccounts: string[], tx: Call | SubmittableExtrinsic<'promise'>, proxies: [string, ProxyType][]): string[] {
  // check an array of calls to all have proxies as the address
  const checkCalls = (address: string, txs: Call[]): boolean =>
    !txs.some((tx) => !filterProxies(allAccounts, tx, proxies).includes(address));

  // get the call info
  const { method, section } = findCall(tx);

  return proxies
    .filter(([address, proxy]): boolean => {
      if (!allAccounts.includes(address)) {
        return false;
      }

      switch (proxy.toString()) {
        case 'Any':
          return true;
        case 'Governance':
          return ['council', 'democracy', 'elections', 'electionsPhragmen', 'poll', 'society', 'technicalCommittee', 'tips', 'treasury'].includes(section);
        case 'IdentityJudgement':
          return section === 'identity' && method === 'provideJudgement';
        case 'NonTransfer':
          return !(section === 'balances' || (section === 'indices' && method === 'transfer') || (section === 'vesting' && method === 'vestedTransfer'));
        case 'Staking':
          return section === 'staking' ||
            (section === 'utility' && (
              (method === 'batch' && checkCalls(address, tx.args[0] as Vec<Call>)) ||
              (method === 'asLimitedSub' && checkCalls(address, [tx.args[0] as Call]))
            ));
        case 'SudoBalances':
          return (section === 'sudo' && (method === 'sudo' && findCall(tx.args[0] as Call).section === 'balances')) ||
            (section === 'utility' && (method === 'batch' && checkCalls(address, tx.args[0] as Vec<Call>)));
        default:
          return false;
      }
    })
    .map(([address]) => address);
}
Example #4
Source File: Address.tsx    From crust-apps with Apache License 2.0 6 votes vote down vote up
async function queryForProxy (api: ApiPromise, allAccounts: string[], address: string, tx: SubmittableExtrinsic<'promise'>): Promise<ProxyState | null> {
  if (isFunction(api.query.proxy?.proxies)) {
    const { isProxied } = extractExternal(address);
    const [_proxies] = await api.query.proxy.proxies<ITuple<[Vec<ITuple<[AccountId, ProxyType]> | ProxyDefinition>, BalanceOf]>>(address);
    const proxies = api.tx.proxy.addProxy.meta.args.length === 3
      ? (_proxies as ProxyDefinition[]).map(({ delegate, proxyType }): [string, ProxyType] => [delegate.toString(), proxyType])
      : (_proxies as [AccountId, ProxyType][]).map(([delegate, proxyType]): [string, ProxyType] => [delegate.toString(), proxyType]);
    const proxiesFilter = filterProxies(allAccounts, tx, proxies);

    if (proxiesFilter.length) {
      return { address, isProxied, proxies, proxiesFilter };
    }
  }

  return null;
}
Example #5
Source File: Address.tsx    From subscan-multisig-react with Apache License 2.0 6 votes vote down vote up
async function queryForProxy(
  api: ApiPromise,
  allAccounts: string[],
  address: string,
  tx: SubmittableExtrinsic<'promise'>
): Promise<ProxyState | null> {
  if (isFunction(api.query.proxy?.proxies)) {
    const { isProxied } = extractExternal(address);
    const [_proxies] = await api.query.proxy.proxies<
      ITuple<[Vec<ITuple<[AccountId, ProxyType]> | ProxyDefinition>, BalanceOf]>
    >(address);
    const proxies =
      api.tx.proxy.addProxy.meta.args.length === 3
        ? (_proxies as ProxyDefinition[]).map(({ delegate, proxyType }): [string, ProxyType] => [
            delegate.toString(),
            proxyType,
          ])
        : (_proxies as [AccountId, ProxyType][]).map(([delegate, proxyType]): [string, ProxyType] => [
            delegate.toString(),
            proxyType,
          ]);
    const proxiesFilter = filterProxies(allAccounts, tx, proxies);

    if (proxiesFilter.length) {
      return { address, isProxied, proxies, proxiesFilter };
    }
  }

  return null;
}
Example #6
Source File: ProxyOverview.tsx    From crust-apps with Apache License 2.0 5 votes vote down vote up
function createAddProxy (api: ApiPromise, account: AccountId, type: ProxyType, delay = 0): SubmittableExtrinsic<'promise'> {
  return api.tx.proxy.addProxy.meta.args.length === 2
    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
    // @ts-ignore old version
    ? api.tx.proxy.addProxy(account, type)
    : api.tx.proxy.addProxy(account, type, delay);
}
Example #7
Source File: ProxyOverview.tsx    From crust-apps with Apache License 2.0 5 votes vote down vote up
function createRmProxy (api: ApiPromise, account: AccountId, type: ProxyType, delay = 0): SubmittableExtrinsic<'promise'> {
  return api.tx.proxy.removeProxy.meta.args.length === 2
    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
    // @ts-ignore old version
    ? api.tx.proxy.removeProxy(account, type)
    : api.tx.proxy.removeProxy(account, type, delay);
}
Example #8
Source File: AddAllowAccount.tsx    From crust-apps with Apache License 2.0 5 votes vote down vote up
function createAddTx (api: ApiPromise, account: AccountId, type: ProxyType, delay = 0): SubmittableExtrinsic<'promise'> {
  return api.tx.swork.addMemberIntoAllowlist(account);
}
Example #9
Source File: RemoveAllow.tsx    From crust-apps with Apache License 2.0 5 votes vote down vote up
function createAddTx (api: ApiPromise, account: AccountId, type: ProxyType, delay = 0): SubmittableExtrinsic<'promise'> {
  return api.tx.swork.removeMemberFromAllowlist(account);
}
Example #10
Source File: Address.tsx    From subscan-multisig-react with Apache License 2.0 5 votes vote down vote up
function filterProxies(
  allAccounts: string[],
  tx: Call | SubmittableExtrinsic<'promise'>,
  proxies: [string, ProxyType][]
): string[] {
  // check an array of calls to all have proxies as the address
  const checkCalls = (address: string, txs: Call[]): boolean =>
    !txs.some((tx) => !filterProxies(allAccounts, tx, proxies).includes(address));

  // get the call info
  const { method, section } = findCall(tx);

  return proxies
    .filter(([address, proxy]): boolean => {
      if (!allAccounts.includes(address)) {
        return false;
      }

      switch (proxy.toString()) {
        case 'Any':
          return true;
        case 'Governance':
          return [
            'council',
            'democracy',
            'elections',
            'electionsPhragmen',
            'phragmenElection',
            'poll',
            'society',
            'technicalCommittee',
            'tips',
            'treasury',
          ].includes(section);
        case 'IdentityJudgement':
          return section === 'identity' && method === 'provideJudgement';
        case 'NonTransfer':
          return !(
            section === 'balances' ||
            (section === 'indices' && method === 'transfer') ||
            (section === 'vesting' && method === 'vestedTransfer')
          );
        case 'Staking':
          return (
            section === 'staking' ||
            (section === 'utility' &&
              ((method === 'batch' && checkCalls(address, tx.args[0] as Vec<Call>)) ||
                (method === 'asLimitedSub' && checkCalls(address, [tx.args[0] as Call]))))
          );
        case 'SudoBalances':
          return (
            (section === 'sudo' && method === 'sudo' && findCall(tx.args[0] as Call).section === 'balances') ||
            (section === 'utility' && method === 'batch' && checkCalls(address, tx.args[0] as Vec<Call>))
          );
        default:
          return false;
      }
    })
    .map(([address]) => address);
}
Example #11
Source File: index.tsx    From crust-apps with Apache License 2.0 4 votes vote down vote up
function Overview ({ className = '', onStatusChange }: Props): React.ReactElement<Props> {
  const { t } = useTranslation();
  const { api, systemChain } = useApi();
  const { allAccounts, hasAccounts } = useAccounts();
  const { isIpfs } = useIpfs();
  const { isLedgerEnabled } = useLedger();
  const [isCreateOpen, toggleCreate] = useToggle();
  const [isImportOpen, toggleImport] = useToggle();
  const [isLedgerOpen, toggleLedger] = useToggle();
  const [isMultisigOpen, toggleMultisig] = useToggle();
  const [isProxyOpen, toggleProxy] = useToggle();
  const [isQrOpen, toggleQr] = useToggle();
  const [favorites, toggleFavorite] = useFavorites(STORE_FAVS);
  const [{ balanceTotal }, setBalances] = useState<Balances>({ accounts: {} });
  const [filterOn, setFilter] = useState<string>('');
  const [sortedAccountsWithDelegation, setSortedAccountsWithDelegation] = useState<SortedAccount[] | undefined>();
  const [{ sortedAccounts, sortedAddresses }, setSorted] = useState<Sorted>({ sortedAccounts: [], sortedAddresses: [] });
  const delegations = useCall<Voting[]>(api.query.democracy?.votingOf?.multi, [sortedAddresses]);
  const proxies = useCall<[ProxyDefinition[], BN][]>(api.query.proxy?.proxies.multi, [sortedAddresses], {
    transform: (result: [([AccountId, ProxyType] | ProxyDefinition)[], BN][]): [ProxyDefinition[], BN][] =>
      api.tx.proxy.addProxy.meta.args.length === 3
        ? result as [ProxyDefinition[], BN][]
        : (result as [[AccountId, ProxyType][], BN][]).map(([arr, bn]): [ProxyDefinition[], BN] =>
          [arr.map(([delegate, proxyType]): ProxyDefinition => api.createType('ProxyDefinition', { delegate, proxyType })), bn]
        )
  });

  const isMainnet = systemChain !== 'Crust Maxwell';

  const isLoading = useLoadingDelay();

  const headerRef = !isMainnet ? useRef([
    [t('accounts'), 'start', 3],
    // [t('parent'), 'address media--1400'],
    [t('type'), 'address media--1400'],
    // [t('tags'), 'start'],
    [t('transactions'), 'start'],
    [t('CRU'), 'expand'],
    [t('CSM'), 'expand'],
    [t('Candy')],
    [t('CRU18')],
    [],
    [undefined, 'media--1400']
  ]) : useRef([
    [t('accounts'), 'start', 3],
    [t('parent'), 'address media--1400'],
    [t('type'), 'address media--1400'],
    [t('tags'), 'start'],
    [t('transactions'), 'start'],
    [t('CRU'), 'expand'],
    [],
    [undefined, 'media--1400']
  ]);

  useEffect((): void => {
    const sortedAccounts = sortAccounts(allAccounts, favorites);
    const sortedAddresses = sortedAccounts.map((a) => a.account.address);

    setSorted({ sortedAccounts, sortedAddresses });
  }, [allAccounts, favorites]);

  useEffect(() => {
    setSortedAccountsWithDelegation(
      sortedAccounts?.map((account, index) => {
        let delegation: Delegation | undefined;

        if (delegations && delegations[index]?.isDelegating) {
          const { balance: amount, conviction, target } = delegations[index].asDelegating;

          delegation = {
            accountDelegated: target.toString(),
            amount,
            conviction
          };
        }

        return ({
          ...account,
          delegation
        });
      })
    );
  }, [api, delegations, sortedAccounts]);

  const _setBalance = useCallback(
    (account: string, balance: BN) =>
      setBalances(({ accounts }: Balances): Balances => {
        accounts[account] = balance;

        return {
          accounts,
          balanceTotal: Object.values(accounts).reduce((total: BN, value: BN) => total.add(value), BN_ZERO)
        };
      }),
    []
  );

  const footer = useMemo(() => !isMainnet ? (
    <tr>
      <td colSpan={3} />
      {/* <td className='media--1400' /> */}
      <td colSpan={2} />
      {/* <td className='media--1500' /> */}
      <td className='number'>
        {balanceTotal && <FormatBalance value={balanceTotal} />}
      </td>
      <td />
      <td />
      <td />
      <td />
      <td className='media--1400' />
    </tr>
  ) : (
    <tr>
      <td colSpan={3} />
      <td className='media--1400' />
      <td colSpan={2} />
      <td className='media--1500' />
      <td className='number'>
        {balanceTotal && <FormatBalance value={balanceTotal} />}
      </td>
      <td />
      <td className='media--1400' />
    </tr>
  ), [balanceTotal, isMainnet]);

  const filter = useMemo(() => (
    <div className='filter--tags'>
      <Input
        autoFocus
        isFull
        label={t<string>('filter by name or tags')}
        onChange={setFilter}
        value={filterOn}
      />
    </div>
  ), [filterOn, t]);

  return (
    <div className={className}>
      {isCreateOpen && (
        <CreateModal
          onClose={toggleCreate}
          onStatusChange={onStatusChange}
        />
      )}
      {isImportOpen && (
        <ImportModal
          onClose={toggleImport}
          onStatusChange={onStatusChange}
        />
      )}
      {isLedgerOpen && (
        <Ledger onClose={toggleLedger} />
      )}
      {isMultisigOpen && (
        <Multisig
          onClose={toggleMultisig}
          onStatusChange={onStatusChange}
        />
      )}
      {isProxyOpen && (
        <Proxy
          onClose={toggleProxy}
          onStatusChange={onStatusChange}
        />
      )}
      {isQrOpen && (
        <Qr
          onClose={toggleQr}
          onStatusChange={onStatusChange}
        />
      )}
      <Button.Group>
        <Button
          icon='plus'
          isDisabled={isIpfs}
          label={t<string>('Add account')}
          onClick={toggleCreate}
        />
        <Button
          icon='sync'
          isDisabled={isIpfs}
          label={t<string>('Restore JSON')}
          onClick={toggleImport}
        />
        <Button
          icon='qrcode'
          label={t<string>('Add via Qr')}
          onClick={toggleQr}
        />
        {isLedgerEnabled && (
          <>
            <Button
              icon='project-diagram'
              label={t<string>('Add via Ledger')}
              onClick={toggleLedger}
            />
          </>
        )}
        <Button
          icon='plus'
          isDisabled={!(api.tx.multisig || api.tx.utility) || !hasAccounts}
          label={t<string>('Multisig')}
          onClick={toggleMultisig}
        />
        <Button
          icon='plus'
          isDisabled={!api.tx.proxy || !hasAccounts}
          label={t<string>('Proxied')}
          onClick={toggleProxy}
        />
      </Button.Group>
      <BannerExtension />
      <BannerClaims />
      <Table
        empty={!isLoading && sortedAccountsWithDelegation && t<string>("You don't have any accounts. Some features are currently hidden and will only become available once you have accounts.")}
        filter={filter}
        footer={footer}
        header={headerRef.current}
      >
        {!isLoading && sortedAccountsWithDelegation?.map(({ account, delegation, isFavorite }, index): React.ReactNode => isMainnet
          ? (
            <AccountMainnet
              account={account}
              delegation={delegation}
              filter={filterOn}
              isFavorite={isFavorite}
              key={`${index}:${account.address}`}
              proxy={proxies?.[index]}
              setBalance={_setBalance}
              toggleFavorite={toggleFavorite}
            />
          )
          : (
            <Account
              account={account}
              delegation={delegation}
              filter={filterOn}
              isFavorite={isFavorite}
              key={`${index}:${account.address}`}
              proxy={proxies?.[index]}
              setBalance={_setBalance}
              toggleFavorite={toggleFavorite}
            />
          ))}
      </Table>
    </div>
  );
}
Example #12
Source File: ProxyOverview.tsx    From crust-apps with Apache License 2.0 4 votes vote down vote up
function ProxyOverview ({ className, onClose, previousProxy: [existing] = EMPTY_EXISTING, proxiedAccount }: Props): React.ReactElement<Props> {
  const { t } = useTranslation();
  const { api } = useApi();
  const [batchPrevious, setBatchPrevious] = useState<SubmittableExtrinsic<'promise'>[]>([]);
  const [batchAdded, setBatchAdded] = useState<SubmittableExtrinsic<'promise'>[]>([]);
  const [extrinsic, setExtrinsic] = useState<SubmittableExtrinsic<'promise'> | null>(null);
  const [previous, setPrevious] = useState<PrevProxy[]>(
    existing.map(({ delegate, proxyType }): [AccountId, ProxyType] => [delegate, proxyType])
  );
  const [added, setAdded] = useState<PrevProxy[]>([]);

  const typeOpts = useRef(
    api.createType('ProxyType').defKeys.map((text, value) => ({ text, value }))
  );

  useEffect((): void => {
    setBatchAdded(
      added.map(([newAccount, newType]) => createAddProxy(api, newAccount, newType))
    );
  }, [api, added]);

  useEffect((): void => {
    (batchPrevious.length || batchAdded.length) &&
      setExtrinsic(() => createExtrinsic(api, batchPrevious, batchAdded));
  }, [api, batchPrevious, batchAdded]);

  const _addProxy = useCallback(
    () => setAdded((added) =>
      [...added, [
        added.length
          ? added[added.length - 1][0]
          : previous.length
            ? previous[previous.length - 1][0]
            : api.createType('AccountId', proxiedAccount),
        api.createType('ProxyType', 0)
      ]]
    ),
    [api, previous, proxiedAccount]
  );

  const _delProxy = useCallback(
    (index: number) => setAdded((added) => added.filter((_, i) => i !== index)),
    []
  );

  const _delPrev = useCallback(
    (accountId: AccountId, type: ProxyType, index: number): void => {
      setPrevious((previous) => previous.filter((_, i) => i !== index));
      setBatchPrevious((previous) => [...previous, createRmProxy(api, accountId, type)]);
    },
    [api]
  );

  const _changeProxyAccount = useCallback(
    (index: number, address: string | null) => setAdded((prevState) => {
      const newState = [...prevState];

      newState[index][0] = api.createType('AccountId', address);

      return newState;
    }),
    [api]
  );

  const _changeProxyType = useCallback(
    (index: number, newTypeNumber: number | undefined): void =>
      setAdded((added) => {
        const newState = [...added];

        newState[index][1] = api.createType('ProxyType', newTypeNumber);

        return newState;
      }),
    [api]
  );

  const isSameAdd = added.some(([accountId]) => accountId.eq(proxiedAccount));

  return (
    <Modal
      className={className}
      header={t<string>('Proxy overview')}
      size='large'
    >
      <Modal.Content>
        <Modal.Columns hint={t<string>('Any account set as proxy will be able to perform actions in place of the proxied account')}>
          <InputAddress
            isDisabled={true}
            label={t<string>('proxied account')}
            type='account'
            value={proxiedAccount}
          />
        </Modal.Columns>
        <Modal.Columns hint={t<string>('If you add several proxy accounts for the same proxy type (e.g 2 accounts set as proxy for Governance), then any of those 2 accounts will be able to perfom governance actions on behalf of the proxied account')}>
          {previous.map((value, index) => (
            <PrevProxy
              index={index}
              key={`${value.toString()}-${index}`}
              onRemove={_delPrev}
              typeOpts={typeOpts.current}
              value={value}
            />
          ))}
          {added.map((value, index) => (
            <NewProxy
              index={index}
              key={`${value.toString()}-${index}`}
              onChangeAccount={_changeProxyAccount}
              onChangeType={_changeProxyType}
              onRemove={_delProxy}
              proxiedAccount={proxiedAccount}
              typeOpts={typeOpts.current}
              value={value}
            />
          ))}
          <Button.Group>
            <Button
              icon='plus'
              label={t<string>('Add proxy')}
              onClick={_addProxy}
            />
          </Button.Group>
        </Modal.Columns>
        <Modal.Columns>
          <BatchWarning />
        </Modal.Columns>
      </Modal.Content>
      <Modal.Actions onCancel={onClose}>
        {existing.length !== 0 && (
          <TxButton
            accountId={proxiedAccount}
            icon='trash-alt'
            label={t<string>('Clear all')}
            onStart={onClose}
            tx={api.tx.proxy.removeProxies}
          />
        )}
        <TxButton
          accountId={proxiedAccount}
          extrinsic={extrinsic}
          icon='sign-in-alt'
          isDisabled={isSameAdd || (!batchPrevious.length && !batchAdded.length)}
          onStart={onClose}
        />
      </Modal.Actions>
    </Modal>
  );
}
Example #13
Source File: index.tsx    From crust-apps with Apache License 2.0 4 votes vote down vote up
function Overview ({ className = '' }: Props): React.ReactElement<Props> {
  const { t } = useTranslation();
  const { api } = useApi();
  const { allAccounts, hasAccounts } = useAccounts();
  const [favorites, toggleFavorite] = useFavorites(STORE_FAVS);
  const [, setBalances] = useState<Balances>({ accounts: {} });
  const [filterOn, setFilter] = useState<string>('');
  const [{ sortedAccounts, sortedAddresses }, setSorted] = useState<Sorted>({ sortedAccounts: [], sortedAddresses: [] });
  const [sortedAccountsWithDelegation, setSortedAccountsWithDelegation] = useState<SortedAccount[] | undefined>();
  const [ownMerchants, setOwnMerchants] = useState<SortedAccount[] | undefined>();
  const delegations = useCall<Voting[]>(api.query.democracy?.votingOf?.multi, [sortedAddresses]);
  const proxies = useCall<[ProxyDefinition[], BN][]>(api.query.proxy?.proxies.multi, [sortedAddresses], {
    transform: (result: [([AccountId, ProxyType] | ProxyDefinition)[], BN][]): [ProxyDefinition[], BN][] =>
      api.tx.proxy.addProxy.meta.args.length === 3
        ? result as [ProxyDefinition[], BN][]
        : (result as [[AccountId, ProxyType][], BN][]).map(([arr, bn]): [ProxyDefinition[], BN] =>
          [arr.map(([delegate, proxyType]): ProxyDefinition => api.createType('ProxyDefinition', { delegate, proxyType })), bn]
        )
  });
  const [allMerchants, setAllMerchants] = useState<string[]>([]);

  const isLoading = useLoadingDelay();

  const headerRef = useRef([
    [t('accounts'), 'start', 3],
    [t('reward')],
    [t('maximum receivable income')],
    [t('collateral')],
    // [t('balances'), 'expand'],
    []
  ]);

  const getAllMerchants = () => {
    let unsub: (() => void) | undefined;
    const fns: any[] = [
      [api.query.benefits.marketBenefits.entries]
    ];
    const allMerchants:string[] = [];

    api.combineLatest<any[]>(fns, ([ledgers]): void => {
      if (Array.isArray(ledgers)) {
        ledgers.forEach(([{ args: [accountId] }, value]) => {
          allMerchants.push(accountId.toString());
        });
        setAllMerchants(allMerchants);
      }
    }).then((_unsub): void => {
      unsub = _unsub;
    }).catch(console.error);

    return (): void => {
      unsub && unsub();
    };
  };

  useEffect(() => {
    getAllMerchants();
  }, []);

  useEffect(() => {
    const tmp: SortedAccount[] = [];

    if (sortedAccountsWithDelegation && allMerchants) {
      for (const myAccount of sortedAccountsWithDelegation) {
        if (allMerchants.includes(myAccount.account.address.toString())) {
          tmp.push(myAccount);
        }
      }

      setOwnMerchants(tmp);
    }
  }, [sortedAccountsWithDelegation, allMerchants]);

  useEffect((): void => {
    const sortedAccounts = sortAccounts(allAccounts, favorites);
    const sortedAddresses = sortedAccounts.map((a) => a.account.address);

    setSorted({ sortedAccounts, sortedAddresses });
  }, [allAccounts, favorites]);

  useEffect(() => {
    setSortedAccountsWithDelegation(
      sortedAccounts?.map((account, index) => {
        let delegation: Delegation | undefined;

        if (delegations && delegations[index]?.isDelegating) {
          const { balance: amount, conviction, target } = delegations[index].asDelegating;

          delegation = {
            accountDelegated: target.toString(),
            amount,
            conviction
          };
        }

        return ({
          ...account,
          delegation
        });
      })
    );
  }, [api, delegations, sortedAccounts]);

  const _setBalance = useCallback(
    (account: string, balance: BN) =>
      setBalances(({ accounts }: Balances): Balances => {
        accounts[account] = balance;

        return {
          accounts,
          balanceTotal: Object.values(accounts).reduce((total: BN, value: BN) => total.add(value), BN_ZERO)
        };
      }),
    []
  );

  const filter = useMemo(() => (
    <div className='filter--tags'>
      <Input
        autoFocus
        isFull
        label={t<string>('filter by name or tags')}
        onChange={setFilter}
        value={filterOn}
      />
    </div>
  ), [filterOn, t]);

  return (
    <div className={className}>
      {(!hasAccounts || (!isLoading && sortedAccountsWithDelegation)) && <Banner type="warning">
        <p>{t<string>('Storage merchant should first increase collateral in the “storage market benefits module” to qualify for the storage market rewards.')}&nbsp;<a href='#/benefit/storageMarket'>{t<string>('Increase collateral...')}</a></p>
      </Banner>}
      <Table
        empty={(!hasAccounts || (!isLoading && sortedAccountsWithDelegation)) && t<string>("You don't have merchant accounts. Some features are currently hidden and will only become available once you have merchant accounts.")}
        filter={filter}
        header={headerRef.current}
      >
        {!isLoading && ownMerchants?.map(({ account, delegation, isFavorite }, index): React.ReactNode => (
          <Merchant
            account={account}
            delegation={delegation}
            filter={filterOn}
            isFavorite={isFavorite}
            key={account.address}
            proxy={proxies?.[index]}
            setBalance={_setBalance}
            toggleFavorite={toggleFavorite}
          />
        ))}
      </Table>
    </div>
  );
}
Example #14
Source File: index.tsx    From crust-apps with Apache License 2.0 4 votes vote down vote up
function Overview ({ className = '' }: Props): React.ReactElement<Props> {
  const { t } = useTranslation();
  const { api } = useApi();
  const { allAccounts, hasAccounts } = useAccounts();
  const [favorites, toggleFavorite] = useFavorites(STORE_FAVS);
  const [, setBalances] = useState<Balances>({ accounts: {} });
  const [filterOn, setFilter] = useState<string>('');
  const [{ sortedAccounts, sortedAddresses }, setSorted] = useState<Sorted>({ sortedAccounts: [], sortedAddresses: [] });
  const [sortedAccountsWithDelegation, setSortedAccountsWithDelegation] = useState<SortedAccount[] | undefined>();
  const [ownMerchants, setOwnMerchants] = useState<SortedAccount[] | undefined>();
  const delegations = useCall<Voting[]>(api.query.democracy?.votingOf?.multi, [sortedAddresses]);
  const proxies = useCall<[ProxyDefinition[], BN][]>(api.query.proxy?.proxies.multi, [sortedAddresses], {
    transform: (result: [([AccountId, ProxyType] | ProxyDefinition)[], BN][]): [ProxyDefinition[], BN][] =>
      api.tx.proxy.addProxy.meta.args.length === 3
        ? result as [ProxyDefinition[], BN][]
        : (result as [[AccountId, ProxyType][], BN][]).map(([arr, bn]): [ProxyDefinition[], BN] =>
          [arr.map(([delegate, proxyType]): ProxyDefinition => api.createType('ProxyDefinition', { delegate, proxyType })), bn]
        )
  });
  const [isRegisterOpen, toggleRegister] = useToggle();
  const [allMerchants, setAllMerchants] = useState<string[]>([]);

  const isLoading = useLoadingDelay();

  const headerRef = useRef([
    [t('accounts'), 'start', 3],
    [t('reward')],
    [t('maximum receivable income')],
    [t('collateral')],
    // [t('balances'), 'expand'],
    []
  ]);

  const getAllMerchants = () => {
    let unsub: (() => void) | undefined;
    const fns: any[] = [
      [api.query.market.merchantLedgers.entries]
    ];
    const allMerchants:string[] = [];

    api.combineLatest<any[]>(fns, ([ledgers]): void => {
      if (Array.isArray(ledgers)) {
        ledgers.forEach(([{ args: [accountId] }]) => {
          allMerchants.push(accountId.toString());
        });
        setAllMerchants(allMerchants);
      }
    }).then((_unsub): void => {
      unsub = _unsub;
    }).catch(console.error);

    return (): void => {
      unsub && unsub();
    };
  };

  useEffect(() => {
    getAllMerchants();
  }, []);

  useEffect(() => {
    const tmp: SortedAccount[] = [];

    if (sortedAccountsWithDelegation && allMerchants) {
      for (const myAccount of sortedAccountsWithDelegation) {
        if (allMerchants.includes(myAccount.account.address.toString())) {
          tmp.push(myAccount);
        }
      }

      setOwnMerchants(tmp);
    }
  }, [sortedAccountsWithDelegation, allMerchants]);

  useEffect((): void => {
    const sortedAccounts = sortAccounts(allAccounts, favorites);
    const sortedAddresses = sortedAccounts.map((a) => a.account.address);

    setSorted({ sortedAccounts, sortedAddresses });
  }, [allAccounts, favorites]);

  useEffect(() => {
    // TODO: to confirm
    if ( !delegations?.length) {
      return;
    }

    setSortedAccountsWithDelegation(
      sortedAccounts?.map((account, index) => {
        let delegation: Delegation | undefined;

        if (delegations && delegations[index]?.isDelegating) {
          const { balance: amount, conviction, target } = delegations[index].asDelegating;

          delegation = {
            accountDelegated: target.toString(),
            amount,
            conviction
          };
        }

        return ({
          ...account,
          delegation
        });
      })
    );
  }, [api, delegations, sortedAccounts]);

  const _setBalance = useCallback(
    (account: string, balance: BN) =>
      setBalances(({ accounts }: Balances): Balances => {
        accounts[account] = balance;

        return {
          accounts,
          balanceTotal: Object.values(accounts).reduce((total: BN, value: BN) => total.add(value), BN_ZERO)
        };
      }),
    []
  );

  const filter = useMemo(() => (
    <div className='filter--tags'>
      <Input
        autoFocus
        isFull
        label={t<string>('filter by name or tags')}
        onChange={setFilter}
        value={filterOn}
      />
    </div>
  ), [filterOn, t]);

  return (
    <div className={className}>
      {isRegisterOpen && (
        <Register
          key='modal-transfer'
          onClose={toggleRegister}
          onSuccess={getAllMerchants}
        />
      )}
      <Button.Group>
        <Button
          icon='plus'
          label={t<string>('Register')}
          onClick={toggleRegister}
        />
      </Button.Group>
      <Table
        empty={(!hasAccounts || (!isLoading && sortedAccountsWithDelegation)) && t<string>("You don't have merchant accounts. Some features are currently hidden and will only become available once you have merchant accounts.")}
        filter={filter}
        header={headerRef.current}
      >
        {!isLoading && ownMerchants?.map(({ account, delegation, isFavorite }, index): React.ReactNode => (
          <Merchant
            account={account}
            delegation={delegation}
            filter={filterOn}
            isFavorite={isFavorite}
            key={account.address}
            proxy={proxies?.[index]}
            setBalance={_setBalance}
            toggleFavorite={toggleFavorite}
          />
        ))}
      </Table>
    </div>
  );
}