View on GitHub
File Changes

                      
export default class YoroiTranferActions {
  startTransferFunds: Action<void> = new Action();
+
  startTransferPaperFunds: Action<void> = new Action();
  setupTransferFundsWithMnemonic: Action<{
    recoveryPhrase: string,
    publicDeriver: PublicDeriverWithCachedMeta,

                      
export type IsValidMnemonicRequest = {
  mnemonic: string,
-
  numberOfWords: ?number
+
  numberOfWords: number
};
export type IsValidMnemonicResponse = boolean;
export type IsValidMnemonicFunc = (

                      
export type IsValidPaperMnemonicRequest = {
  mnemonic: string,
-
  numberOfWords: ?number
+
  numberOfWords: number
};
export type IsValidPaperMnemonicResponse = boolean;
export type IsValidPaperMnemonicFunc = (

                      
export type UnscramblePaperMnemonicRequest = {
  mnemonic: string,
-
  numberOfWords: ?number,
+
  numberOfWords: number,
  password?: string,
};
export type UnscramblePaperMnemonicResponse = [?string, number];
/** Check validty of mnemonic (including checksum) */
export const isValidEnglishAdaMnemonic = (
  phrase: string,
-
  numberOfWords: ?number = 15
+
  numberOfWords: number
) => {
  // Note: splitting on spaces will not work for Japanese-encoded mnemonics who use \u3000 instead
  // We only use English mnemonics in Yoroi so this is okay.
import {
  isValidEnglishAdaMnemonic
} from './cryptoWallet';
+
import config from '../../../../config';

                      
/**
 * Variation of the mnemonic to seed as defined by BIP39
/** Check validty of paper mnemonic (including checksum) */
export const isValidEnglishAdaPaperMnemonic = (
  phrase: string,
-
  numberOfWords: ?number = 27
+
  numberOfWords: number
) => {
  // Any password will return some valid unscrambled mnemonic
  // so we just pass a fake password to pass downstream validation
-
  const fakePassword = numberOfWords === 21 ? 'xxx' : undefined;
+
  const fakePassword = numberOfWords === config.wallets.YOROI_PAPER_RECOVERY_PHRASE_WORD_COUNT
+
    ? 'xxx'
+
    : undefined;
  const [unscrambled, unscrambledLen] =
    unscramblePaperAdaMnemonic(phrase, numberOfWords, fakePassword);
  if (unscrambled != null && unscrambledLen) {
/** Check validty of paper mnemonic (including checksum) */
export const unscramblePaperAdaMnemonic = (
  phrase: string,
-
  numberOfWords: ?number = 27,
+
  numberOfWords: number,
  password?: string,
): [?string, number] => {
  const words = phrase.split(' ');
  if (words.length === numberOfWords) {
-
    if (numberOfWords === 27) {
+
    if (numberOfWords === config.wallets.DAEDALUS_PAPER_RECOVERY_PHRASE_WORD_COUNT) {
      if (password != null) {
-
        throw new Error('Password is not expected for a 27-word paper!');
+
        throw new Error(
+
          `Password is not expected for a ${config.wallets.DAEDALUS_PAPER_RECOVERY_PHRASE_WORD_COUNT}-word paper!`
+
        );
      }
      const [scrambledMnemonics, passwordMnemonics] = [words.slice(0, 18), words.slice(18)];
      try {
          password
        );

                      
-
        return [newEntropy.to_english_mnemonics(), 12];
+
        return [
+
          newEntropy.to_english_mnemonics(),
+
          config.wallets.DAEDALUS_RECOVERY_PHRASE_WORD_COUNT
+
        ];
      } catch (e) {
        Logger.error('Failed to unscramble paper mnemonic! ' + stringifyError(e));
        return [undefined, 0];
      }
    }
-
    if (numberOfWords === 21) {
+
    if (numberOfWords === config.wallets.YOROI_PAPER_RECOVERY_PHRASE_WORD_COUNT) {
      if (password == null) {
-
        throw new Error('Password is expected for a 21-word paper!');
+
        throw new Error(
+
          `Password is expected for a ${config.wallets.YOROI_PAPER_RECOVERY_PHRASE_WORD_COUNT}-word paper!`
+
        );
      }
      try {
        const entropy = mnemonicToEntropy(phrase);
        const newEntropy = RustModule.WalletV2.paper_wallet_unscramble(
          Buffer.from(entropy, 'hex'),
          password
        );
-
        return [newEntropy.to_english_mnemonics(), 15];
+
        return [
+
          newEntropy.to_english_mnemonics(),
+
          config.wallets.WALLET_RECOVERY_PHRASE_WORD_COUNT
+
        ];
      } catch (e) {
        Logger.error('Failed to unscramble paper mnemonic! ' + stringifyError(e));
        return [undefined, 0];
import {
  loadLovefieldDB,
} from '../storage/database/index';
+
import config from '../../../../config';

                      
const VALID_DD_PAPER = {
  words: 'fire shaft radar three ginger receive result phrase song staff scorpion food undo will have expire nice uncle dune until lift unlock exist step world slush disagree',
});

                      
test('Is valid Daedalus paper mnemonic', async () => {
-
  expect(isValidEnglishAdaPaperMnemonic(VALID_DD_PAPER.words, 27)).toEqual(true);
+
  expect(isValidEnglishAdaPaperMnemonic(
+
    VALID_DD_PAPER.words,
+
    config.wallets.DAEDALUS_PAPER_RECOVERY_PHRASE_WORD_COUNT
+
  )).toEqual(true);
  expect(isValidEnglishAdaPaperMnemonic(VALID_DD_PAPER.words, 30)).toEqual(false);
  // Note: expect these to print error to console
-
  expect(isValidEnglishAdaPaperMnemonic(INVALID_DD_PAPER_1, 27)).toEqual(false);
-
  expect(isValidEnglishAdaPaperMnemonic(INVALID_DD_PAPER_2, 27)).toEqual(false);
+
  expect(isValidEnglishAdaPaperMnemonic(
+
    INVALID_DD_PAPER_1,
+
    config.wallets.DAEDALUS_PAPER_RECOVERY_PHRASE_WORD_COUNT
+
  )).toEqual(false);
+
  expect(isValidEnglishAdaPaperMnemonic(
+
    INVALID_DD_PAPER_2,
+
    config.wallets.DAEDALUS_PAPER_RECOVERY_PHRASE_WORD_COUNT
+
  )).toEqual(false);
});

                      
test('Unscramble Daedalus paper produces 12 valid words', async () => {
-
  const [words, count] = unscramblePaperAdaMnemonic(VALID_DD_PAPER.words, 27);
-
  expect(count).toEqual(12);
+
  const [words, count] = unscramblePaperAdaMnemonic(
+
    VALID_DD_PAPER.words,
+
    config.wallets.DAEDALUS_PAPER_RECOVERY_PHRASE_WORD_COUNT
+
  );
+
  expect(count).toEqual(config.wallets.DAEDALUS_RECOVERY_PHRASE_WORD_COUNT);
  if (words == null) throw new Error('failed to unscramble in test');
  expect(validateMnemonic(words)).toEqual(true);
});

                      
test('Unscramble Daedalus paper matches expected address', async () => {
-
  const [words] = unscramblePaperAdaMnemonic(VALID_DD_PAPER.words, 27);
+
  const [words] = unscramblePaperAdaMnemonic(
+
    VALID_DD_PAPER.words,
+
    config.wallets.DAEDALUS_PAPER_RECOVERY_PHRASE_WORD_COUNT
+
  );
  expect(words).toBeTruthy();
  if (words != null) {
    const daedalusWallet = getCryptoDaedalusWalletFromMnemonics(words);

                      
declare var CONFIG: ConfigType;
const addressesLimit = CONFIG.app.addressRequestSize;
-
const transactionsLimit: number = config.wallets.TRANSACTION_REQUEST_SIZE;

                      
/**
 * Makes calls to Yoroi backend service
  const transactions = previousTxs.concat(history);

                      
  // If we reached the API limit, call API again to get more results
-
  if (history.length === transactionsLimit) {
+
  if (history.length === config.wallets.TRANSACTION_REQUEST_SIZE) {
    const newBest = getLatestTransaction(history);
    if (newBest === undefined) {
      // if we don't have a single tx in a block
});

                      
type Props = {|
-
  onSubmit: Function,
-
  onBack: Function,
-
  mnemonicValidator: Function,
+
  onSubmit: { recoveryPhrase: string } => void,
+
  onBack: void => void,
+
  mnemonicValidator: string => boolean,
  validWords: Array<string>,
  step0: string,
  mnemonicLength: number,

                      
import AnnotatedLoader from './AnnotatedLoader';
import WarningBox from '../widgets/WarningBox';
+
import type { TransferStatusT } from '../../types/TransferTypes';
+
import { TransferStatus } from '../../types/TransferTypes';
+
import type { $npm$ReactIntl$IntlFormat } from 'react-intl';

                      
import styles from './TransferWaitingPage.scss';

                      
});

                      
type Props = {|
-
  status: string
+
  status: TransferStatusT
|};

                      
@observer
        <div className={styles.annotatedLoaderWrapper}>
          <AnnotatedLoader
            title={intl.formatMessage(messages.title)}
-
            details={intl.formatMessage(messages[status])}
+
            details={this.getMessage(intl, status)}
          />
        </div>
      </div>
    );
  }
+

                      
+
  getMessage(
+
    intl: $npm$ReactIntl$IntlFormat,
+
    status: TransferStatusT,
+
  ): string {
+
    switch (status) {
+
      case TransferStatus.RESTORING_ADDRESSES:
+
        return intl.formatMessage(messages.restoringAddresses);
+
      case TransferStatus.CHECKING_ADDRESSES:
+
        return intl.formatMessage(messages.checkingAddresses);
+
      case TransferStatus.GENERATING_TX:
+
        return intl.formatMessage(messages.generatingTx);
+
      default: throw new Error('TransferWaitingPage::getMessage unexpected status');
+
    }
+
  }
}
  mnemonicLabel15: {
    id: 'yoroiTransfer.start.instructions.mnemonic-15',
    defaultMessage: '!!!15-word mnemonic',
-
  }
+
  },
+
  yoroiPaperLabel: {
+
    id: 'yoroiTransfer.start.instructions.yoroiPaper',
+
    defaultMessage: '!!!Yoroi paper wallet',
+
  },
});

                      
type Props = {|
-
  onNext: void => void,
+
  on15Words: void => void,
+
  onPaper: void => void,
  classicTheme: boolean,
  onFollowInstructionsPrerequisites: void => void,
  disableTransferFunds: boolean,
  render() {
    const { intl } = this.context;
    const {
-
      onNext,
+
      on15Words,
+
      onPaper,
      onFollowInstructionsPrerequisites,
      disableTransferFunds,
    } = this.props;
                  {intl.formatMessage(globalMessages.transferTitleText)}
                </div>
                <Button
-
                  className={`next ${commonClasses}`}
+
                  className={`next 15words ${commonClasses}`}
                  label={intl.formatMessage(messages.mnemonicLabel15)}
-
                  onClick={onNext}
+
                  onClick={on15Words}
+
                  skin={ButtonSkin}
+
                  disabled={disableTransferFunds}
+
                />
+
                <Button
+
                  className={`next yoroiPaper ${commonClasses}`}
+
                  label={intl.formatMessage(messages.yoroiPaperLabel)}
+
                  onClick={onPaper}
                  skin={ButtonSkin}
                  disabled={disableTransferFunds}
                />
m
+2/-0
    MAX_ALLOWED_UNUSED_ADDRESSES: 20,
    TRANSACTION_REQUEST_SIZE: 20,
    DAEDALUS_RECOVERY_PHRASE_WORD_COUNT: 12,
+
    DAEDALUS_PAPER_RECOVERY_PHRASE_WORD_COUNT: 27,
    WALLET_RECOVERY_PHRASE_WORD_COUNT: 15,
+
    YOROI_PAPER_RECOVERY_PHRASE_WORD_COUNT: 21,
    hardwareWallet: {
      trezorT: {
        VENDOR: 'trezor.io',
import { observer } from 'mobx-react';
import { defineMessages, intlShape } from 'react-intl';
import TransferMnemonicPage from '../../components/transfer/TransferMnemonicPage';
+
import config from '../../config';

                      
const messages = defineMessages({
  step0: {
      mnemonicLength,
      classicTheme
    } = this.props;
-
    const message = mnemonicLength === 27 ? messages.step0Paper : messages.step0;
+
    const message = mnemonicLength === config.wallets.DAEDALUS_PAPER_RECOVERY_PHRASE_WORD_COUNT
+
      ? messages.step0Paper
+
      : messages.step0;

                      
    return (
      <TransferMnemonicPage
import environment from '../../environment';
import { ROUTES } from '../../routes-config';
import config from '../../config';
+
import { TransferStatus } from '../../types/TransferTypes';

                      
import { formattedWalletAmount } from '../../utils/formatters';

                      
    const daedalusTransfer = this._getDaedalusTransferStore();

                      
    switch (daedalusTransfer.status) {
-
      case 'uninitialized':
+
      case TransferStatus.UNINITIALIZED:
        return (
          <TransferLayout>
            <TransferInstructionsPage
            />
          </TransferLayout>
        );
-
      case 'gettingMnemonics':
+
      case TransferStatus.GETTING_MNEMONICS:
        return (
          <TransferLayout>
            <DaedalusTransferFormPage
            />
          </TransferLayout>
        );
-
      case 'gettingPaperMnemonics':
+
      case TransferStatus.GETTING_PAPER_MNEMONICS:
        return (
          <TransferLayout>
            <DaedalusTransferFormPage
              onSubmit={this.setupTransferFundsWithMnemonic}
              onBack={this.backToUninitialized}
-
              mnemonicValidator={mnemonic => wallets.isValidPaperMnemonic(mnemonic, 27)}
+
              mnemonicValidator={mnemonic => wallets.isValidPaperMnemonic(
+
                mnemonic,
+
                config.wallets.DAEDALUS_PAPER_RECOVERY_PHRASE_WORD_COUNT
+
              )}
              validWords={validWords}
-
              mnemonicLength={27}
+
              mnemonicLength={config.wallets.DAEDALUS_PAPER_RECOVERY_PHRASE_WORD_COUNT}
              classicTheme={profile.isClassicTheme}
            />
          </TransferLayout>
        );
-
      case 'gettingMasterKey':
+
      case TransferStatus.GETTING_MASTER_KEY:
        return (
          <TransferLayout>
            <DaedalusTransferMasterKeyFormPage
            />
          </TransferLayout>
        );
-
      case 'restoringAddresses':
-
      case 'checkingAddresses':
-
      case 'generatingTx':
+
      case TransferStatus.RESTORING_ADDRESSES:
+
      case TransferStatus.CHECKING_ADDRESSES:
+
      case TransferStatus.GENERATING_TX:
        return (
          <TransferLayout>
            <DaedalusTransferWaitingPage status={daedalusTransfer.status} />
          </TransferLayout>
        );
-
      case 'readyToTransfer':
+
      case TransferStatus.READY_TO_TRANSFER:
        if (daedalusTransfer.transferTx == null) {
          return null; // TODO: throw error? Shoudln't happen
        }
            />
          </TransferLayout>
        );
-
      case 'error':
+
      case TransferStatus.ERROR:
        return (
          <TransferLayout>
            <DaedalusTransferErrorPage
import React, { Component } from 'react';
import { observer } from 'mobx-react';
import TransferWaitingPage from '../../components/transfer/TransferWaitingPage';
+
import type { TransferStatusT } from '../../types/TransferTypes';

                      
type Props = {|
-
  status: string
+
  status: TransferStatusT
|};

                      
@observer

                      
type Props = {|
  onSubmit: { recoveryPhrase: string } => void,
-
  onBack: Function,
-
  mnemonicValidator: Function,
+
  onBack: void => void,
+
  mnemonicValidator: string => boolean,
  validWords: Array<string>,
  mnemonicLength: number,
  classicTheme: boolean,
import { ROUTES } from '../../routes-config';
import config from '../../config';
import { formattedWalletAmount } from '../../utils/formatters';
+
import { TransferStatus } from '../../types/TransferTypes';

                      
// Stay this long on the success page, then jump to the wallet transactions page
const SUCCESS_PAGE_STAY_TIME = 5 * 1000;
    this._getYoroiTransferActions().startTransferFunds.trigger();
  }

                      
+
  startTransferPaperFunds = () => {
+
    this._getYoroiTransferActions().startTransferPaperFunds.trigger();
+
  }
+

                      
  setupTransferFundsWithMnemonic = (payload: {
    recoveryPhrase: string,
  }) => {
    const yoroiTransfer = this._getYoroiTransferStore();

                      
    switch (yoroiTransfer.status) {
-
      case 'uninitialized':
+
      case TransferStatus.UNINITIALIZED:
        return (
          <TransferLayout>
            <YoroiTransferStartPage
-
              onNext={this.startTransferFunds}
+
              on15Words={this.startTransferFunds}
+
              onPaper={this.startTransferPaperFunds}
              classicTheme={profile.isClassicTheme}
              onFollowInstructionsPrerequisites={this.goToCreateWallet}
              disableTransferFunds={yoroiTransfer.disableTransferFunds}
            />
          </TransferLayout>
        );
-
      case 'gettingMnemonics':
+
      case TransferStatus.GETTING_MNEMONICS:
        return (
          <TransferLayout>
            <YoroiTransferFormPage
            />
          </TransferLayout>
        );
-
      case 'restoringAddresses':
-
      case 'checkingAddresses':
-
      case 'generatingTx':
+
      case TransferStatus.GETTING_PAPER_MNEMONICS:
+
        return (
+
          <TransferLayout>
+
            <YoroiTransferFormPage
+
              onSubmit={this.setupTransferFundsWithMnemonic}
+
              onBack={this.backToUninitialized}
+
              mnemonicValidator={mnemonic => wallets.isValidPaperMnemonic(
+
                mnemonic,
+
                config.wallets.YOROI_PAPER_RECOVERY_PHRASE_WORD_COUNT
+
              )}
+
              validWords={validWords}
+
              mnemonicLength={config.wallets.YOROI_PAPER_RECOVERY_PHRASE_WORD_COUNT}
+
              classicTheme={profile.isClassicTheme}
+
            />
+
          </TransferLayout>
+
        );
+
      case TransferStatus.RESTORING_ADDRESSES:
+
      case TransferStatus.CHECKING_ADDRESSES:
+
      case TransferStatus.GENERATING_TX:
        return (
          <TransferLayout>
            <YoroiTransferWaitingPage status={yoroiTransfer.status} />
          </TransferLayout>
        );
-
      case 'readyToTransfer':
+
      case TransferStatus.READY_TO_TRANSFER:
        if (yoroiTransfer.transferTx == null) {
          return null; // TODO: throw error? Shoudln't happen
        }
            />
          </TransferLayout>
        );
-
      case 'error':
+
      case TransferStatus.ERROR:
        return (
          <TransferLayout>
            <YoroiTransferErrorPage
            />
          </TransferLayout>
        );
-
      case 'success':
+
      case TransferStatus.SUCCESS:
        return (
          <TransferLayout>
            <YoroiTransferSuccessPage
import React, { Component } from 'react';
import { observer } from 'mobx-react';
import { defineMessages, intlShape } from 'react-intl';
+
import type { TransferStatusT } from '../../types/TransferTypes';
+
import { TransferStatus } from '../../types/TransferTypes';
+
import type { $npm$ReactIntl$IntlFormat } from 'react-intl';
+

                      
import AnnotatedLoader from '../../components/transfer/AnnotatedLoader';

                      
const messages = defineMessages({
});

                      
type Props = {|
-
  status: string
+
  status: TransferStatusT
|};

                      
@observer
    return (
      <AnnotatedLoader
        title={intl.formatMessage(messages.title)}
-
        details={intl.formatMessage(messages[status])}
+
        details={this.getMessage(intl, status)}
      />
    );
  }
+

                      
+
  getMessage(
+
    intl: $npm$ReactIntl$IntlFormat,
+
    status: TransferStatusT,
+
  ): string {
+
    switch (status) {
+
      case TransferStatus.RESTORING_ADDRESSES:
+
        return intl.formatMessage(messages.restoringAddresses);
+
      case TransferStatus.CHECKING_ADDRESSES:
+
        return intl.formatMessage(messages.checkingAddresses);
+
      case TransferStatus.GENERATING_TX:
+
        return intl.formatMessage(messages.generatingTx);
+
      default: throw new Error('TransferWaitingPage::getMessage unexpected status');
+
    }
+
  }
}

                      
  isValidMnemonic = (
    mnemonic: string,
-
    numberOfWords: ?number
+
    numberOfWords: number
  ): boolean => this.api.ada.isValidMnemonic({ mnemonic, numberOfWords });

                      
  isValidPaperMnemonic = (
    mnemonic: string,
-
    numberOfWords: ?number
+
    numberOfWords: number
  ): boolean => this.api.ada.isValidPaperMnemonic({ mnemonic, numberOfWords });

                      
  // =================== WALLET RESTORATION ==================== //
  localizedError
} from '../../i18n/LocalizableError';
import type {
-
  TransferStatus,
+
  TransferStatusT,
  TransferTx
} from '../../types/TransferTypes';
+
import { TransferStatus } from '../../types/TransferTypes';
import {
  getAddressesKeys,
  generateTransferTx

                      
export default class DaedalusTransferStore extends Store {

                      
-
  @observable status: TransferStatus = 'uninitialized';
+
  @observable status: TransferStatusT = TransferStatus.UNINITIALIZED;
  @observable disableTransferFunds: boolean = true;
  @observable error: ?LocalizableError = null;
  @observable transferTx: ?TransferTx = null;
  }

                      
  _startTransferFunds = (): void => {
-
    this._updateStatus('gettingMnemonics');
+
    this._updateStatus(TransferStatus.GETTING_MNEMONICS);
  }

                      
  _startTransferPaperFunds = (): void => {
-
    this._updateStatus('gettingPaperMnemonics');
+
    this._updateStatus(TransferStatus.GETTING_PAPER_MNEMONICS);
  }

                      
  _startTransferMasterKey = (): void => {
-
    this._updateStatus('gettingMasterKey');
+
    this._updateStatus(TransferStatus.GETTING_MASTER_KEY);
  }

                      
  /** @Attention:
    }
    const nextInternalAddress = nextInternal.addressInfo.addr.Hash;

                      
-
    this._updateStatus('restoringAddresses');
+
    this._updateStatus(TransferStatus.RESTORING_ADDRESSES);
    runInAction(() => {
      this.ws = new WebSocket(websocketUrl);
    });
        const data = JSON.parse(event.data);
        Logger.info(`[ws::message] on: ${data.msg}`);
        if (data.msg === MSG_TYPE_RESTORE) {
-
          this._updateStatus('checkingAddresses');
+
          this._updateStatus(TransferStatus.CHECKING_ADDRESSES);
          const checker = RustModule.WalletV2.DaedalusAddressChecker.new(wallet);
          const addressKeys = getAddressesKeys({ checker, fullUtxo: data.addresses });
-
          this._updateStatus('generatingTx');
+
          this._updateStatus(TransferStatus.GENERATING_TX);

                      
          const transferTx = await generateTransferTx({
            outputAddr: nextInternalAddress,
          runInAction(() => {
            this.transferTx = transferTx;
          });
-
          this._updateStatus('readyToTransfer');
+
          this._updateStatus(TransferStatus.READY_TO_TRANSFER);
        }
      } catch (error) {
        Logger.error(`DaedalusTransferStore::_setupTransferWebSocket ${stringifyError(error)}`);
        runInAction(() => {
-
          this.status = 'error';
+
          this.status = TransferStatus.ERROR;
          this.error = localizedError(error);
        });
      }
        );

                      
        runInAction(() => {
-
          this.status = 'error';
+
          this.status = TransferStatus.ERROR;
          this.error = new WebSocketRestoreError();
        });
      } else {
  }

                      
  _backToUninitialized = (): void => {
-
    this._updateStatus('uninitialized');
+
    this._updateStatus(TransferStatus.UNINITIALIZED);
  }

                      
  /** Updates the status that we show to the user as transfer progresses */
  @action.bound
-
  _updateStatus(s: TransferStatus): void {
+
  _updateStatus(s: TransferStatusT): void {
    this.status = s;
  }

                      

                      
  @action.bound
  _reset(): void {
-
    this.status = 'uninitialized';
+
    this.status = TransferStatus.UNINITIALIZED;
    this.error = null;
    this.transferTx = null;
    this.transferFundsRequest.reset();
  localizedError
} from '../../i18n/LocalizableError';
import type {
-
  TransferStatus,
+
  TransferStatusT,
  TransferTx
} from '../../types/TransferTypes';
+
import { TransferStatus } from '../../types/TransferTypes';
import { generateTransferTx } from '../../api/ada/daedalusTransfer';
import environment from '../../environment';
import type { SignedResponse } from '../../api/ada/lib/state-fetch/types';

                      
export default class YoroiTransferStore extends Store {

                      
-
  @observable status: TransferStatus = 'uninitialized';
+
  @observable status: TransferStatusT = TransferStatus.UNINITIALIZED;
  @observable disableTransferFunds: boolean = true;
  @observable transferFundsRequest: Request<TransferFundsFunc>
    = new Request<TransferFundsFunc>(this._transferFundsRequest);
    } catch (error) {
      Logger.error(`YoroiTransferStore ${stringifyError(error)}`);
      runInAction(() => {
-
        this.status = 'error';
+
        this.status = TransferStatus.ERROR;
        this.error = localizedError(error);
      });
      throw error;
    ]);
    const actions = this.actions.ada.yoroiTransfer;
    actions.startTransferFunds.listen(this._startTransferFunds);
+
    actions.startTransferPaperFunds.listen(this._startTransferPaperFunds);
    actions.setupTransferFundsWithMnemonic.listen(
      this._errorWrapper(this._setupTransferFundsWithMnemonic)
    );
  }

                      
  _startTransferFunds = () => {
-
    this._updateStatus('gettingMnemonics');
+
    this._updateStatus(TransferStatus.GETTING_MNEMONICS);
+
  }
+

                      
+
  _startTransferPaperFunds = () => {
+
    this._updateStatus(TransferStatus.GETTING_PAPER_MNEMONICS);
  }

                      
  /** @Attention:
    recoveryPhrase: string,
    publicDeriver: PublicDeriverWithCachedMeta,
  }): Promise<void> => {
-
    this._updateStatus('checkingAddresses');
+
    this._updateStatus(TransferStatus.CHECKING_ADDRESSES);
    this.recoveryPhrase = payload.recoveryPhrase;
    const transferTx = await this._generateTransferTxFromMnemonic(
      payload.recoveryPhrase,
-
      () => this._updateStatus('generatingTx'),
+
      () => this._updateStatus(TransferStatus.GENERATING_TX),
      payload.publicDeriver
    );
    runInAction(() => {
      this.transferTx = transferTx;
    });

                      
-
    this._updateStatus('readyToTransfer');
+
    this._updateStatus(TransferStatus.READY_TO_TRANSFER);
  }

                      
  _backToUninitialized = (): void => {
-
    this._updateStatus('uninitialized');
+
    this._updateStatus(TransferStatus.UNINITIALIZED);
  }

                      
  /** Updates the status that we show to the user as transfer progresses */
  @action.bound
-
  _updateStatus(s: TransferStatus): void {
+
  _updateStatus(s: TransferStatusT): void {
    this.status = s;
  }

                      
      await this.transferFundsRequest.execute({
        signedTx: transferTx.signedTx
      });
-
      this._updateStatus('success');
+
      this._updateStatus(TransferStatus.SUCCESS);
      await next();
      this.reset();
    } catch (error) {

                      
  @action.bound
  reset(): void {
-
    this.status = 'uninitialized';
+
    this.status = TransferStatus.UNINITIALIZED;
    this.error = null;
    this.transferTx = null;
    this.transferFundsRequest.reset();
import BigNumber from 'bignumber.js';
import { RustModule } from '../api/ada/lib/cardanoCrypto/rustLoader';

                      
-
export type TransferStatus =
-
    'uninitialized'
-
  | 'gettingMnemonics'
-
  | 'gettingPaperMnemonics'
-
  | 'gettingMasterKey'
-
  | 'restoringAddresses'
-
  | 'checkingAddresses'
-
  | 'generatingTx'
-
  | 'readyToTransfer'
-
  | 'error'
-
  | 'success'
+
export const TransferStatus = Object.freeze({
+
  UNINITIALIZED: 0,
+
  GETTING_MNEMONICS: 1,
+
  GETTING_PAPER_MNEMONICS: 2,
+
  GETTING_MASTER_KEY: 3,
+
  RESTORING_ADDRESSES: 4,
+
  CHECKING_ADDRESSES: 5,
+
  GENERATING_TX: 6,
+
  READY_TO_TRANSFER: 7,
+
  ERROR: 7,
+
  SUCCESS: 8,
+
});
+
export type TransferStatusT = $Values<typeof TransferStatus>;

                      
/** Contains all information necessary to send and display the Daedalus transfer transaction */
export type TransferTx = {