Transfer.tsx 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. /* eslint-disable @typescript-eslint/camelcase */
  2. // Copyright 2017-2019 @polkadot/app-accounts authors & contributors
  3. // This software may be modified and distributed under the terms
  4. // of the Apache-2.0 license. See the LICENSE file for details.
  5. import { SubmittableExtrinsic } from '@polkadot/api/promise/types';
  6. import { DerivedFees } from '@polkadot/api-derive/types';
  7. import { I18nProps } from '@polkadot/react-components/types';
  8. import BN from 'bn.js';
  9. import React, { useContext, useEffect, useState } from 'react';
  10. import styled from 'styled-components';
  11. import { Button, InputAddress, InputBalance, Modal, TxButton } from '@polkadot/react-components';
  12. import { Available } from '@polkadot/react-query';
  13. import Checks from '@polkadot/react-signer/Checks';
  14. import { ApiContext } from '@polkadot/react-api';
  15. import translate from '../translate';
  16. interface Props extends I18nProps {
  17. balances_fees?: DerivedFees;
  18. className?: string;
  19. onClose: () => void;
  20. recipientId?: string;
  21. senderId?: string;
  22. }
  23. const ZERO = new BN(0);
  24. // TODO Re-enable when we have proper fee calculation (incl. weights)
  25. // async function calcMax (api: ApiPromise, balances_fees: DerivedFees | undefined, senderId: string, recipientId: string): Promise<BN> {
  26. // let maxBalance = new BN(1);
  27. // if (!balances_fees) {
  28. // return maxBalance;
  29. // }
  30. // const { transferFee, transactionBaseFee, transactionByteFee, creationFee } = balances_fees;
  31. // const [senderNonce, senderBalances, recipientBalances] = await Promise.all([
  32. // api.query.system.accountNonce<Index>(senderId),
  33. // api.derive.balances.all(senderId),
  34. // api.derive.balances.all(recipientId)
  35. // ]);
  36. // let prevMax = new BN(0);
  37. // // something goes screwy here when we move this out of the component :(
  38. // let extrinsic: any;
  39. // while (!prevMax.eq(maxBalance)) {
  40. // prevMax = maxBalance;
  41. // extrinsic = api.tx.balances.transfer(senderNonce, prevMax);
  42. // const txLength = calcTxLength(extrinsic, senderNonce);
  43. // const fees = transactionBaseFee
  44. // .add(transactionByteFee.mul(txLength))
  45. // .add(transferFee)
  46. // .add(recipientBalances.availableBalance.isZero() ? creationFee : ZERO);
  47. // maxBalance = bnMax(senderBalances.availableBalance.sub(fees), ZERO);
  48. // }
  49. // return maxBalance;
  50. // }
  51. function Transfer ({ className, onClose, recipientId: propRecipientId, senderId: propSenderId, t }: Props): React.ReactElement<Props> {
  52. const { api } = useContext(ApiContext);
  53. const [amount, setAmount] = useState<BN | undefined>(new BN(0));
  54. const [extrinsic, setExtrinsic] = useState<SubmittableExtrinsic | null>(null);
  55. const [hasAvailable, setHasAvailable] = useState(true);
  56. const [maxBalance] = useState(new BN(0));
  57. const [recipientId, setRecipientId] = useState<string | null>(propRecipientId || null);
  58. const [senderId, setSenderId] = useState<string | null>(propSenderId || null);
  59. useEffect((): void => {
  60. if (senderId && recipientId) {
  61. setExtrinsic(api.tx.balances.transfer(recipientId, amount || ZERO));
  62. // We currently have not enabled the max functionality - we don't take care of weights
  63. // calcMax(api, balances_fees, senderId, recipientId)
  64. // .then(([maxBalance]): void => setMaxBalance(maxBalance))
  65. // .catch((error: Error): void => console.error(error));
  66. }
  67. }, [amount, recipientId, senderId]);
  68. const transferrable = <span className='label'>{t('transferrable ')}</span>;
  69. return (
  70. <Modal
  71. className='app--accounts-Modal'
  72. dimmer='inverted'
  73. open
  74. >
  75. <Modal.Header>{t('Send funds')}</Modal.Header>
  76. <Modal.Content>
  77. <div className={className}>
  78. <InputAddress
  79. defaultValue={propSenderId}
  80. help={t('The account you will send funds from.')}
  81. isDisabled={!!propSenderId}
  82. label={t('send from account')}
  83. labelExtra={<Available label={transferrable} params={senderId} />}
  84. onChange={setSenderId}
  85. type='account'
  86. />
  87. <InputAddress
  88. defaultValue={propRecipientId}
  89. help={t('Select a contact or paste the address you want to send funds to.')}
  90. isDisabled={!!propRecipientId}
  91. label={t('send to address')}
  92. labelExtra={<Available label={transferrable} params={recipientId} />}
  93. onChange={setRecipientId}
  94. type='allPlus'
  95. />
  96. <InputBalance
  97. help={t('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.')}
  98. isError={!hasAvailable}
  99. label={t('amount')}
  100. maxValue={maxBalance}
  101. onChange={setAmount}
  102. withMax
  103. />
  104. <Checks
  105. accountId={senderId}
  106. extrinsic={extrinsic}
  107. isSendable
  108. onChange={setHasAvailable}
  109. />
  110. </div>
  111. </Modal.Content>
  112. <Modal.Actions>
  113. <Button.Group>
  114. <Button
  115. icon='cancel'
  116. isNegative
  117. label={t('Cancel')}
  118. onClick={onClose}
  119. />
  120. <Button.Or />
  121. <TxButton
  122. accountId={senderId}
  123. extrinsic={extrinsic}
  124. icon='send'
  125. isDisabled={!hasAvailable}
  126. isPrimary
  127. label={t('Make Transfer')}
  128. onStart={onClose}
  129. withSpinner={false}
  130. />
  131. </Button.Group>
  132. </Modal.Actions>
  133. </Modal>
  134. );
  135. }
  136. export default translate(
  137. styled(Transfer)`
  138. article.padded {
  139. box-shadow: none;
  140. margin-left: 2rem;
  141. }
  142. .balance {
  143. margin-bottom: 0.5rem;
  144. text-align: right;
  145. padding-right: 1rem;
  146. .label {
  147. opacity: 0.7;
  148. }
  149. }
  150. label.with-help {
  151. flex-basis: 10rem;
  152. }
  153. `
  154. );