@polkadot/util#BN_HUNDRED TypeScript Examples

The following examples show how to use @polkadot/util#BN_HUNDRED. 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: BountyActionMessage.tsx    From crust-apps with Apache License 2.0 5 votes vote down vote up
function BountyActionMessage ({ bestNumber, blocksUntilUpdate, status }: Props): JSX.Element {
  const { t } = useTranslation();
  const { unlockAt } = useBountyStatus(status);
  const { bountyUpdatePeriod } = useBounties();

  const blocksUntilPayout = useMemo(() => unlockAt?.sub(bestNumber), [bestNumber, unlockAt]);

  const blocksPercentageLeftToShowWarning = bountyUpdatePeriod?.muln(BLOCKS_PERCENTAGE_LEFT_TO_SHOW_WARNING).div(BN_HUNDRED);
  const blocksToShowWarning = blocksPercentageLeftToShowWarning ?? BLOCKS_LEFT_TO_SHOW_WARNING;

  return (
    <div>
      {blocksUntilUpdate?.lte(BN_ZERO) && (
        <BountyInfo
          description={t<string>('Update overdue')}
          type='warning'
        />
      )}
      {blocksUntilUpdate?.lt(blocksToShowWarning) && blocksUntilUpdate?.gt(BN_ZERO) && (
        <BountyInfo
          description={t<string>('Close deadline')}
          type='warning'
        />
      )}
      {status.isApproved && (
        <BountyInfo
          description={t<string>('Waiting for Bounty Funding')}
          type='info'
        />
      )}
      {status.isCuratorProposed && (
        <BountyInfo
          description={t<string>("Waiting for Curator's acceptance")}
          type='info'
        />
      )}
      {blocksUntilPayout?.lt(BN_ZERO) &&
        <BountyInfo
          description={t<string>('Waiting for implementer to claim')}
          type='info'
        />
      }
    </div>
  );
}
Example #2
Source File: index.tsx    From crust-apps with Apache License 2.0 5 votes vote down vote up
function applyFilter (validators: ValidatorInfo[], medianComm: number, allIdentity: Record<string, DeriveHasIdentity>, { daysPayout, isBabe, maxPaid, withElected, withGroup, withIdentity, withPayout, withoutComm, withoutOver }: Flags, nominatedBy?: Record<string, NominatedBy[]>): ValidatorInfo[] {
  const displays: (string[])[] = [];
  const parentIds: string[] = [];

  return validators.filter(({ accountId, commissionPer, isElected, isFavorite, lastPayout, numNominators }): boolean => {
    if (isFavorite) {
      return true;
    }

    const stashId = accountId.toString();
    const thisIdentity = allIdentity[stashId];
    const nomCount = numNominators || nominatedBy?.[stashId]?.length || 0;

    if (
      (!withElected || isElected) &&
      (!withIdentity || !!thisIdentity?.hasIdentity) &&
      (!withPayout || !isBabe || (!!lastPayout && daysPayout.gte(lastPayout))) &&
      (!withoutComm || (
        MAX_COMM_PERCENT > 0
          ? (commissionPer >= MAX_COMM_PERCENT)
          : (!medianComm || (commissionPer < medianComm)))
      ) &&
      (!withoutOver || !maxPaid || maxPaid.muln(MAX_CAP_PERCENT).div(BN_HUNDRED).gten(nomCount))
    ) {
      if (!withGroup) {
        return true;
      } else if (!thisIdentity || !thisIdentity.hasIdentity) {
        parentIds.push(stashId);

        return true;
      } else if (!thisIdentity.parentId) {
        if (!parentIds.includes(stashId)) {
          if (thisIdentity.display) {
            const sanitized = thisIdentity.display
              .replace(/[^\x20-\x7E]/g, '')
              .replace(/-/g, ' ')
              .replace(/_/g, ' ')
              .split(' ')
              .map((p) => p.trim())
              .filter((v) => !!v);

            displays.push(sanitized);
          }

          parentIds.push(stashId);

          return true;
        }
      } else {
        parentIds.push(thisIdentity.parentId);

        return true;
      }
    }

    return false;
  });
}
Example #3
Source File: useSortedTargets.ts    From crust-apps with Apache License 2.0 5 votes vote down vote up
function extractInfo (api: ApiPromise, allAccounts: string[], electedDerive: DeriveStakingElected, waitingDerive: DeriveStakingWaiting, favorites: string[], totalIssuance: BN, lastEraInfo: LastEra, validatorStakeLimit: ValidatorStakeLimit[], guarantors: Guarantor[], totalReward: BN, validatorCount: number, historyDepth?: BN): Partial<SortedTargets> {
  const [elected, nominators] = extractSingle(api, allAccounts, electedDerive, favorites, lastEraInfo, validatorStakeLimit, guarantors, historyDepth);
  const [waiting, waitingNominators] = extractSingle(api, allAccounts, waitingDerive, favorites, lastEraInfo, validatorStakeLimit, guarantors);
  const electedTotals = elected
    .filter(({ isActive }) => isActive)
    .map(({ bondTotal }) => bondTotal)
  const waitingTotals = waiting
  .filter(({ isActive }) => isActive)
  .map(({ bondTotal }) => bondTotal)
  const activeTotals = [...electedTotals, ...waitingTotals].sort((a, b) => a.cmp(b));
  const totalStaked = activeTotals.reduce((total: BN, value) => total.iadd(value), new BN(0));
  const avgStaked = totalStaked.divn(activeTotals.length);
  const inflation = calcInflation(api, totalStaked, totalIssuance);

  // add the explicit stakedReturn
  !avgStaked.isZero() && elected.forEach((e): void => {
    if (!e.skipRewards) {
      const adjusted = avgStaked.mul(BN_HUNDRED).imuln(inflation.stakedReturn).div(e.bondTotal);

      // in some cases, we may have overflows... protect against those
      // @ts-ignore
      e.stakedReturn = Number(adjusted.gt(BN_MAX_INTEGER) ? BN_MAX_INTEGER : adjusted) / BN_HUNDRED.toNumber();
      e.stakedReturnCmp = e.stakedReturn * (100 - e.commissionPer) / 100;
    }
  });

  // all validators, calc median commission
  const tmpMinNominated = Object.values(nominators).reduce((min: BN, value) => {
    return min.isZero() || value.lt(min)
      ? value
      : min;
  }, BN_ZERO);

  const minNominated = Object.values(waitingNominators).reduce((min: BN, value) => {
    return min.isZero() || value.lt(min)
      ? value
      : min;
  }, tmpMinNominated);
  const validators = sortValidators(arrayFlatten([elected, waiting])).map(e => calculateApy(totalReward, validatorCount, totalStaked, e));
  const commValues = validators.map(({ commissionPer }) => commissionPer).sort((a, b) => a - b);
  const midIndex = Math.floor(commValues.length / 2);
  const medianComm = commValues.length
    ? commValues.length % 2
      ? commValues[midIndex]
      : (commValues[midIndex - 1] + commValues[midIndex]) / 2
    : 0;

  // ids
  const waitingIds = waiting.map(({ key }) => key);
  const validatorIds = arrayFlatten([
    elected.map(({ key }) => key),
    waitingIds
  ]);
  const nominateIds = arrayFlatten([
    elected.filter(({ isBlocking }) => !isBlocking).map(({ key }) => key),
    waiting.filter(({ isBlocking }) => !isBlocking).map(({ key }) => key)
  ]);

  return {
    avgStaked,
    inflation,
    lowStaked: activeTotals[0] || BN_ZERO,
    medianComm,
    minNominated,
    nominateIds,
    nominators: Object.keys(nominators).concat(Object.keys(waitingNominators).filter((e) => !Object.keys(nominators).includes(e))),
    totalIssuance,
    totalStaked,
    validatorIds,
    validators,
    waitingIds
  };
}
Example #4
Source File: CardSummary.tsx    From crust-apps with Apache License 2.0 5 votes vote down vote up
function CardSummary ({ children, className = '', help, label, progress }: Props): React.ReactElement<Props> | null {
  const value = progress && progress.value;
  const total = progress && progress.total;
  const left = progress && !isUndefined(value) && !isUndefined(total) && value.gten(0) && total.gtn(0)
    ? (
      value.gt(total)
        ? `>${
          progress.isPercent
            ? '100'
            : formatNumber(total)
        }`
        : (
          progress.isPercent
            ? value.mul(BN_HUNDRED).div(total).toString()
            : formatNumber(value)
        )
    )
    : undefined;

  if (progress && isUndefined(left)) {
    return null;
  }

  const isTimed = progress && progress.withTime && !isUndefined(progress.total);

  return (
    <article className={className}>
      <Labelled
        help={help}
        isSmall
        label={label}
      >
        {children}{
          progress && !progress.hideValue && (
            <>
              {isTimed && !children && (
                <BlockToTime value={progress.total} />
              )}
              <div className={isTimed ? 'isSecondary' : 'isPrimary'}>
                {!left || isUndefined(progress.total)
                  ? '-'
                  : !isTimed || progress.isPercent || !progress.value
                    ? `${left}${progress.isPercent ? '' : '/'}${
                      progress.isPercent
                        ? '%'
                        : formatNumber(progress.total)
                    }`
                    : (
                      <BlockToTime
                        className='timer'
                        value={progress.total.sub(progress.value)}
                      />
                    )
                }
              </div>
            </>
          )
        }
      </Labelled>
      {progress && !progress.hideGraph && <Progress {...progress} />}
    </article>
  );
}
Example #5
Source File: CardSummary.tsx    From subscan-multisig-react with Apache License 2.0 5 votes vote down vote up
function CardSummary({ children, className = '', help, label, progress }: Props): React.ReactElement<Props> | null {
  const value = progress && progress.value;
  const total = progress && progress.total;
  const left =
    progress && !isUndefined(value) && !isUndefined(total) && value.gten(0) && total.gtn(0)
      ? value.gt(total)
        ? `>${progress.isPercent ? '100' : formatNumber(total)}`
        : progress.isPercent
        ? value.mul(BN_HUNDRED).div(total).toString()
        : formatNumber(value)
      : undefined;

  if (progress && isUndefined(left)) {
    return null;
  }

  const isTimed = progress && progress.withTime && !isUndefined(progress.total);

  return (
    <article className={className}>
      <Labelled help={help} isSmall label={label}>
        {children}
        {progress && !progress.hideValue && (
          <>
            {isTimed && !children && <BlockToTime value={progress.total} />}
            <div className={isTimed ? 'isSecondary' : 'isPrimary'}>
              {!left || isUndefined(progress.total) ? (
                '-'
              ) : !isTimed || progress.isPercent || !progress.value ? (
                `${left}${progress.isPercent ? '' : '/'}${progress.isPercent ? '%' : formatNumber(progress.total)}`
              ) : (
                <BlockToTime className="timer" value={progress.total.sub(progress.value)} />
              )}
            </div>
          </>
        )}
      </Labelled>
      {progress && !progress.hideGraph && <Progress {...progress} />}
    </article>
  );
}
Example #6
Source File: Transfer.tsx    From crust-apps with Apache License 2.0 4 votes vote down vote up
function Transfer ({ className = '', onClose, recipientId: propRecipientId, senderId: propSenderId }: Props): React.ReactElement<Props> {
  const { t } = useTranslation();
  const { api } = useApi();
  const [amount, setAmount] = useState<BN | undefined>(BN_ZERO);
  const [hasAvailable] = useState(true);
  const [isProtected, setIsProtected] = useState(true);
  const [isAll, setIsAll] = useState(false);
  const [[maxTransfer, noFees], setMaxTransfer] = useState<[BN | null, boolean]>([null, false]);
  const [recipientId, setRecipientId] = useState<string | null>(null);
  const [senderId, setSenderId] = useState<string | null>(null);
  const [[, recipientPhish], setPhishing] = useState<[string | null, string | null]>([null, null]);
  const balances = useCall<DeriveBalancesAll>(api.derive.balances.all, [propSenderId || senderId]);
  const accountInfo = useCall<AccountInfoWithProviders | AccountInfoWithRefCount>(api.query.system.account, [propSenderId || senderId]);

  useEffect((): void => {
    const fromId = propSenderId || senderId as string;
    const toId = propRecipientId || recipientId as string;

    if (balances && balances.accountId.eq(fromId) && fromId && toId && isFunction(api.rpc.payment?.queryInfo)) {
      setTimeout((): void => {
        try {
          api.tx.balances
            .transfer(toId, balances.availableBalance)
            .paymentInfo(fromId)
            .then(({ partialFee }): void => {
              const adjFee = partialFee.muln(110).div(BN_HUNDRED);
              const maxTransfer = balances.availableBalance.sub(adjFee);

              setMaxTransfer(
                maxTransfer.gt(api.consts.balances.existentialDeposit)
                  ? [maxTransfer, false]
                  : [null, true]
              );
            })
            .catch(console.error);
        } catch (error) {
          console.error((error as Error).message);
        }
      }, 0);
    } else {
      setMaxTransfer([null, false]);
    }
  }, [api, balances, propRecipientId, propSenderId, recipientId, senderId]);

  useEffect((): void => {
    checkPhishing(propSenderId || senderId, propRecipientId || recipientId)
      .then(setPhishing)
      .catch(console.error);
  }, [propRecipientId, propSenderId, recipientId, senderId]);

  const noReference = accountInfo
    ? isRefcount(accountInfo)
      ? accountInfo.refcount.isZero()
      : accountInfo.consumers.isZero()
    : true;
  const canToggleAll = !isProtected && balances && balances.accountId.eq(propSenderId || senderId) && maxTransfer && noReference;

  return (
    <Modal
      className='app--accounts-Modal'
      header={t<string>('Send CRU')}
      size='large'
    >
      <Modal.Content>
        <div className={className}>
          <Modal.Columns hint={t<string>('The transferred balance will be subtracted (along with fees) from the sender account.')}>
            <InputAddress
              defaultValue={propSenderId}
              help={t<string>('The account you will send funds from.')}
              isDisabled={!!propSenderId}
              label={t<string>('send from account')}
              labelExtra={
                <Available
                  label={t<string>('transferrable')}
                  params={propSenderId || senderId}
                />
              }
              onChange={setSenderId}
              type='account'
            />
          </Modal.Columns>
          <Modal.Columns hint={t<string>('The beneficiary will have access to the transferred fees when the transaction is included in a block.')}>
            <InputAddress
              defaultValue={propRecipientId}
              help={t<string>('Select a contact or paste the address you want to send funds to.')}
              isDisabled={!!propRecipientId}
              label={t<string>('send to address')}
              labelExtra={
                <Available
                  label={t<string>('transferrable')}
                  params={propRecipientId || recipientId}
                />
              }
              onChange={setRecipientId}
              type='allPlus'
            />
            {recipientPhish && (
              <MarkError content={t<string>('The recipient is associated with a known phishing site on {{url}}', { replace: { url: recipientPhish } })} />
            )}
          </Modal.Columns>
          <Modal.Columns hint={t<string>('If the recipient account is new, the balance needs to be more than the existential deposit. Likewise if the sending account balance drops below the same value, the account will be removed from the state.')}>
            {canToggleAll && isAll
              ? (
                <InputBalance
                  autoFocus
                  defaultValue={maxTransfer}
                  help={t<string>('The full account balance to be transferred, minus the transaction fees')}
                  isDisabled
                  key={maxTransfer?.toString()}
                  label={t<string>('transferrable minus fees')}
                />
              )
              : (
                <>
                  <InputBalance
                    autoFocus
                    help={t<string>('Type the amount you want to transfer. Note that you can select the unit on the right e.g sending 1 milli is equivalent to sending 0.001.')}
                    isError={!hasAvailable}
                    isZeroable
                    label={t<string>('amount')}
                    onChange={setAmount}
                  />
                  <InputBalance
                    defaultValue={api.consts.balances.existentialDeposit}
                    help={t<string>('The minimum amount that an account should have to be deemed active')}
                    isDisabled
                    label={t<string>('existential deposit')}
                  />
                </>
              )
            }
          </Modal.Columns>
          <Modal.Columns hint={t('With the keep-alive option set, the account is protected against removal due to low balances.')}>
            {isFunction(api.tx.balances.transferKeepAlive) && (
              <Toggle
                className='typeToggle'
                label={
                  isProtected
                    ? t<string>('Transfer with account keep-alive checks')
                    : t<string>('Normal transfer without keep-alive checks')
                }
                onChange={setIsProtected}
                value={isProtected}
              />
            )}
            {canToggleAll && (
              <Toggle
                className='typeToggle'
                label={t<string>('Transfer the full account balance, reap the sender')}
                onChange={setIsAll}
                value={isAll}
              />
            )}
            {!isProtected && !noReference && (
              <MarkWarning content={t<string>('There is an existing reference count on the sender account. As such the account cannot be reaped from the state.')} />
            )}
            {noFees && (
              <MarkWarning content={t<string>('The transaction, after application of the transfer fees, will drop the available balance below the existential deposit. As such the transfer will fail. The account needs more free funds to cover the transaction fees.')} />
            )}
          </Modal.Columns>
        </div>
      </Modal.Content>
      <Modal.Actions onCancel={onClose}>
        <TxButton
          accountId={propSenderId || senderId}
          icon='paper-plane'
          isDisabled={!hasAvailable || !(propRecipientId || recipientId) || !amount || !!recipientPhish}
          label={t<string>('Make Transfer')}
          onStart={onClose}
          params={
            canToggleAll && isAll
              ? [propRecipientId || recipientId, maxTransfer]
              : [propRecipientId || recipientId, amount]
          }
          tx={(isProtected && api.tx.balances.transferKeepAlive) || api.tx.balances.transfer}
        />
      </Modal.Actions>
    </Modal>
  );
}
Example #7
Source File: ProposalCreate.tsx    From crust-apps with Apache License 2.0 4 votes vote down vote up
function Propose ({ className }: Props): React.ReactElement<Props> | null {
  const { t } = useTranslation();
  const { api } = useApi();
  const [accountId, setAccountId] = useState<string | null>(null);
  const [beneficiary, setBeneficiary] = useState<string | null>(null);
  const [isOpen, toggleOpen] = useToggle();
  const [value, setValue] = useState<BN | undefined>();
  const hasValue = value?.gtn(0);

  const bondPercentage = useMemo(
    () => `${api.consts.treasury.proposalBond.mul(BN_HUNDRED).div(BN_MILLION).toNumber().toFixed(2)}%`,
    [api]
  );

  return (
    <>
      {isOpen && (
        <Modal
          className={className}
          header={t<string>('Submit treasury proposal')}
          size='large'
        >
          <Modal.Content>
            <Modal.Columns hint={t<string>('This account will make the proposal and be responsible for the bond.')}>
              <InputAddress
                help={t<string>('Select the account you wish to submit the proposal from.')}
                label={t<string>('submit with account')}
                onChange={setAccountId}
                type='account'
                withLabel
              />
            </Modal.Columns>
            <Modal.Columns hint={t<string>('The beneficiary will receive the full amount if the proposal passes.')}>
              <InputAddress
                help={t<string>('The account to which the proposed balance will be transferred if approved')}
                label={t<string>('beneficiary')}
                onChange={setBeneficiary}
                type='allPlus'
              />
            </Modal.Columns>
            <Modal.Columns hint={
              <>
                <p>{t<string>('The value is the amount that is being asked for and that will be allocated to the beneficiary if the proposal is approved.')}</p>
                <p>{t<string>('Of the beneficiary amount, at least {{bondPercentage}} would need to be put up as collateral. The maximum of this and the minimum bond will be used to secure the proposal, refundable if it passes.', { replace: { bondPercentage } })}</p>
              </>
            }>
              <InputBalance
                help={t<string>('The amount that will be allocated from the treasury pot')}
                isError={!hasValue}
                label={t<string>('value')}
                onChange={setValue}
              />
              <Static
                help={t<string>('The on-chain percentage for the treasury')}
                label={t<string>('proposal bond')}
              >
                {bondPercentage}
              </Static>
              <InputBalance
                defaultValue={api.consts.treasury.proposalBondMinimum.toString()}
                help={t<string>('The minimum amount that will be bonded')}
                isDisabled
                label={t<string>('minimum bond')}
              />
              <MarkWarning content={t<string>('Be aware that once submitted the proposal will be put to a council vote. If the proposal is rejected due to a lack of info, invalid requirements or non-benefit to the network as a whole, the full bond posted (as describe above) will be lost.')} />
            </Modal.Columns>
          </Modal.Content>
          <Modal.Actions onCancel={toggleOpen}>
            <TxButton
              accountId={accountId}
              icon='plus'
              isDisabled={!accountId || !hasValue}
              label={t<string>('Submit proposal')}
              onStart={toggleOpen}
              params={[value, beneficiary]}
              tx={api.tx.treasury.proposeSpend}
            />
          </Modal.Actions>
        </Modal>
      )}
      <Button
        icon='plus'
        label={t<string>('Submit proposal')}
        onClick={toggleOpen}
      />
    </>
  );
}
Example #8
Source File: Transfer.tsx    From subscan-multisig-react with Apache License 2.0 4 votes vote down vote up
// eslint-disable-next-line complexity
function Transfer({
  className = '',
  onClose,
  onTxSuccess,
  recipientId: propRecipientId,
  senderId: propSenderId,
}: Props): React.ReactElement<Props> {
  const { t } = useTranslation();
  const { api } = useApi();
  const { multisigAccount } = useMultisig();
  const [amount, setAmount] = useState<BN | undefined>(BN_ZERO);
  const [hasAvailable] = useState(true);
  const [isProtected, setIsProtected] = useState(true);
  const [isAll, setIsAll] = useState(false);
  const [[maxTransfer, noFees], setMaxTransfer] = useState<[BN | null, boolean]>([null, false]);
  const [recipientId, setRecipientId] = useState<string | null>(null);
  const [senderId, setSenderId] = useState<string | null>(null);
  const [[, recipientPhish], setPhishing] = useState<[string | null, string | null]>([null, null]);
  const balances = useCall<DeriveBalancesAll>(api.derive.balances?.all, [propSenderId || senderId]);
  const accountInfo = useCall<AccountInfoWithProviders | AccountInfoWithRefCount>(api.query.system.account, [
    propSenderId || senderId,
  ]);
  const [multisigExtrinsic, setMultisigExtrinsic] = useState<SubmittableExtrinsic<'promise'> | null>(null);
  const [accountId, setAccountId] = useState<string | null>(null);
  const isExtensionAccount = useIsInjected();
  const [reserveAmount, setReserveAmount] = useState(0);

  const options = useMemo<KeyringSectionOption[]>(
    () =>
      ((multisigAccount?.meta?.addressPair as AddressPair[]) ?? []).map(({ address, ...others }) => ({
        ...others,
        value: address,
        key: address,
      })),
    [multisigAccount?.meta]
  );
  const [optionsAll, setOptionsAll] = useState<Record<string, Option[]>>({
    account: [],
    all: [],
  });

  const [depositBase, depositFactor] = useMemo(() => {
    return [Number(api?.consts.multisig.depositBase.toJSON()), Number(api?.consts.multisig.depositFactor.toJSON())];
  }, [api]);

  const [chainDecimal, chainToken] = useMemo(() => {
    return [api?.registry.chainDecimals[0], api?.registry.chainTokens[0]];
  }, [api]);

  const createMultiItem = useCallback(
    (option: Option): Option[] => {
      if (option.value === multisigAccount?.address) {
        return options.map((opt) => createItem(opt));
      }

      return [];
    },
    [multisigAccount?.address, options]
  );

  useEffect(() => {
    const subscription = keyring.keyringOption.optionsSubject.subscribe((all) => {
      const optAll = Object.entries(all).reduce(
        (
          result: Record<string, (Option | React.ReactNode)[]>,
          [type, value]
        ): Record<string, (Option | React.ReactNode)[]> => {
          result[type] = flatten(
            value.map((option): Option | React.ReactNode =>
              option.value === null
                ? createHeader(option)
                : createMultiItem(option as Option).filter((item) => isExtensionAccount(item.value))
            )
          );

          return result;
        },
        {}
      );

      setOptionsAll(optAll as Record<string, Option[]>);
    });

    return () => subscription.unsubscribe();
  }, [createMultiItem, isExtensionAccount]);

  // eslint-disable-next-line complexity
  useEffect((): void => {
    const fromId = propSenderId || (senderId as string);
    const toId = propRecipientId || (recipientId as string);

    if (balances && balances.accountId?.eq(fromId) && fromId && toId && isFunction(api.rpc.payment?.queryInfo)) {
      setTimeout((): void => {
        try {
          api.tx.balances
            ?.transfer(toId, balances.availableBalance)
            .paymentInfo(fromId)
            .then(({ partialFee }): void => {
              // eslint-disable-next-line no-magic-numbers
              const adjFee = partialFee.muln(110).div(BN_HUNDRED);
              const tempMaxTransfer = balances.availableBalance.sub(adjFee);

              setMaxTransfer(
                tempMaxTransfer.gt(api.consts.balances?.existentialDeposit as unknown as BN)
                  ? [tempMaxTransfer, false]
                  : [null, true]
              );
            })
            .catch(console.error);
        } catch (error) {
          console.error((error as Error).message);
        }
      }, 0);
    } else {
      setMaxTransfer([null, false]);
    }
  }, [api, balances, propRecipientId, propSenderId, recipientId, senderId]);

  useEffect((): void => {
    checkPhishing(propSenderId || senderId, propRecipientId || recipientId)
      .then(setPhishing)
      .catch(console.error);
  }, [propRecipientId, propSenderId, recipientId, senderId]);

  const noReference = accountInfo
    ? isRefcount(accountInfo)
      ? accountInfo.refcount.isZero()
      : accountInfo.consumers.isZero()
    : true;
  const canToggleAll =
    !isProtected && balances && balances.accountId?.eq(propSenderId || senderId) && maxTransfer && noReference;

  useEffect(() => {
    // eslint-disable-next-line complexity
    (async () => {
      const fn =
        canToggleAll && isAll && isFunction(api.tx.balances?.transferAll)
          ? api.tx.balances?.transferAll
          : isProtected
          ? api.tx.balances?.transferKeepAlive
          : api.tx.balances?.transfer;

      if (!fn || !propSenderId) {
        setMultisigExtrinsic(null);
        return;
      }

      const params =
        canToggleAll && isAll && isFunction(api.tx.balances?.transferAll)
          ? [{ Id: recipientId }, amount]
          : isProtected
          ? [{ Id: recipientId }, amount]
          : [{ Id: recipientId }, amount];

      const ext = fn(...params);

      // eslint-disable-next-line no-console
      // console.log('amount', amount?.toString());

      const ARG_LENGTH = 6;
      const info = await api?.query.multisig.multisigs(propSenderId, ext?.method.hash);
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      const timepoint = (info as any).isSome ? (info as any)?.unwrap().when : null;
      const { threshold, who } = extractExternal(propSenderId);
      const others: string[] = who.filter((item) => item !== accountId);
      const { weight } = (await ext?.paymentInfo(propSenderId)) || { weight: 0 };
      const module = api?.tx.multisig;
      const argsLength = module?.asMulti.meta.args.length || 0;
      const generalParams = [threshold, others, timepoint];
      const args =
        argsLength === ARG_LENGTH ? [...generalParams, ext.method.toHex(), true, weight] : [...generalParams, ext];
      // eslint-disable-next-line @typescript-eslint/ban-ts-comment
      // @ts-ignore
      const multiTx = module?.asMulti(...args);

      // eslint-disable-next-line no-console
      // console.log('hexCallData', ext.method.toHex());

      setMultisigExtrinsic(multiTx);

      // Estimate reserve amount
      try {
        if (chainDecimal) {
          setReserveAmount(
            // eslint-disable-next-line no-magic-numbers
            (depositBase * 2 + depositFactor * threshold + (depositFactor * (ext.method.toHex().length + 31)) / 32) /
              Math.pow(10, chainDecimal)
          );
        }
      } catch (err) {
        setReserveAmount(0);
      }
    })();
  }, [
    canToggleAll,
    isAll,
    api,
    isProtected,
    amount,
    recipientId,
    propSenderId,
    accountId,
    chainDecimal,
    depositBase,
    depositFactor,
  ]);

  return (
    <Modal className="app--accounts-Modal" header={t<string>('Send funds')} onClose={onClose} size="large">
      <Modal.Content>
        <div className={className}>
          <Modal.Columns
            hint={t<string>('The transferred balance will be subtracted (along with fees) from the sender account.')}
          >
            <PureInputAddress
              label={t<string>('using the selected account')}
              labelExtra={<BalanceFree label={<label>{t<string>('free balance')}</label>} params={accountId} />}
              onChange={setAccountId}
              optionsAll={optionsAll}
              type="account"
            />
          </Modal.Columns>
          <Modal.Columns
            hint={t<string>('The transferred balance will be subtracted (along with fees) from the sender account.')}
          >
            <InputAddress
              defaultValue={propSenderId}
              help={t<string>('The account you will send funds from.')}
              isDisabled={!!propSenderId}
              label={t<string>('send from account')}
              labelExtra={<Available label={t<string>('transferrable')} params={propSenderId || senderId} />}
              onChange={setSenderId}
              type="account"
            />
          </Modal.Columns>
          <Modal.Columns
            hint={t<string>(
              'The beneficiary will have access to the transferred fees when the transaction is included in a block.'
            )}
          >
            <InputAddress
              defaultValue={propRecipientId}
              help={t<string>('Select a contact or paste the address you want to send funds to.')}
              isDisabled={!!propRecipientId}
              label={t<string>('send to address')}
              labelExtra={<Available label={t<string>('transferrable')} params={propRecipientId || recipientId} />}
              onChange={setRecipientId}
              type="allPlus"
            />
            {recipientPhish && (
              <MarkError
                content={t<string>('The recipient is associated with a known phishing site on {{url}}', {
                  replace: { url: recipientPhish },
                })}
              />
            )}
          </Modal.Columns>
          <Modal.Columns
            hint={t<string>(
              'If the recipient account is new, the balance needs to be more than the existential deposit. Likewise if the sending account balance drops below the same value, the account will be removed from the state.'
            )}
          >
            {canToggleAll && isAll ? (
              <InputBalance
                autoFocus
                defaultValue={maxTransfer}
                help={t<string>('The full account balance to be transferred, minus the transaction fees')}
                isDisabled
                key={maxTransfer?.toString()}
                label={t<string>('transferrable minus fees')}
              />
            ) : (
              <>
                <InputBalance
                  autoFocus
                  help={t<string>(
                    'Type the amount you want to transfer. Note that you can select the unit on the right e.g sending 1 milli is equivalent to sending 0.001.'
                  )}
                  isError={!hasAvailable}
                  isZeroable
                  label={t<string>('amount')}
                  maxValue={maxTransfer}
                  onChange={setAmount}
                />
                <InputBalance
                  defaultValue={api.consts.balances?.existentialDeposit}
                  help={t<string>('The minimum amount that an account should have to be deemed active')}
                  isDisabled
                  label={t<string>('existential deposit')}
                />
              </>
            )}
          </Modal.Columns>
          <Modal.Columns
            hint={t('With the keep-alive option set, the account is protected against removal due to low balances.')}
          >
            {isFunction(api.tx.balances?.transferKeepAlive) && (
              <Toggle
                className="typeToggle"
                label={
                  isProtected
                    ? t<string>('Transfer with account keep-alive checks')
                    : t<string>('Normal transfer without keep-alive checks')
                }
                onChange={setIsProtected}
                value={isProtected}
              />
            )}
            {canToggleAll && (
              <Toggle
                className="typeToggle"
                label={t<string>('Transfer the full account balance, reap the sender')}
                onChange={setIsAll}
                value={isAll}
              />
            )}
            {!isProtected && !noReference && (
              <MarkWarning
                content={t<string>(
                  'There is an existing reference count on the sender account. As such the account cannot be reaped from the state.'
                )}
              />
            )}
            {noFees && (
              <MarkWarning
                content={t<string>(
                  'The transaction, after application of the transfer fees, will drop the available balance below the existential deposit. As such the transfer will fail. The account needs more free funds to cover the transaction fees.'
                )}
              />
            )}
          </Modal.Columns>
        </div>
      </Modal.Content>

      <div className="flex items-center justify-between px-5">
        <Text style={{ color: 'rgba(78,78,78,0.6)', marginLeft: '20px' }}>
          {t('multisig.estimate_reserve')} {reserveAmount} {chainToken}
        </Text>

        <Modal.Actions onCancel={onClose}>
          <TxButton
            // accountId={propSenderId || senderId}
            accountId={accountId}
            icon="paper-plane"
            isDisabled={!hasAvailable || !(propRecipientId || recipientId) || !amount || !!recipientPhish}
            label={t<string>('Make Transfer')}
            onStart={onClose}
            extrinsic={multisigExtrinsic}
            onSuccess={onTxSuccess}
            // params={
            //   canToggleAll && isAll
            //     ? isFunction(api.tx.balances?.transferAll)
            //       ? [propRecipientId || recipientId, false]
            //       : [propRecipientId || recipientId, maxTransfer]
            //     : [propRecipientId || recipientId, amount]
            // }
            // tx={
            //   canToggleAll && isAll && isFunction(api.tx.balances?.transferAll)
            //     ? api.tx.balances?.transferAll
            //     : isProtected
            //     ? api.tx.balances?.transferKeepAlive
            //     : api.tx.balances?.transfer
            // }
          />
        </Modal.Actions>
      </div>
    </Modal>
  );
}