/ common / features / message / sagas.ts
sagas.ts
  1  import { SagaIterator } from 'redux-saga';
  2  import { put, take, all, apply, takeEvery, call, select } from 'redux-saga/effects';
  3  
  4  import { translateRaw } from 'translations';
  5  import { verifySignedMessage } from 'libs/signing';
  6  import { IFullWallet } from 'libs/wallet';
  7  import { padLeftEven } from 'libs/values';
  8  import Web3Node from 'libs/nodes/web3';
  9  import * as configNodesSelectors from 'features/config/nodes/selectors';
 10  import { notificationsActions } from 'features/notifications';
 11  import { paritySignerTypes, paritySignerActions } from 'features/paritySigner';
 12  import { walletSelectors } from 'features/wallet';
 13  import * as types from './types';
 14  import * as actions from './actions';
 15  
 16  export function* signingWrapper(
 17    handler: (wallet: IFullWallet, message: string) => SagaIterator,
 18    action: types.SignMessageRequestedAction
 19  ): SagaIterator {
 20    const payloadMessage = action.payload;
 21    const wallet = yield select(walletSelectors.getWalletInst);
 22  
 23    try {
 24      yield call(handler, wallet, payloadMessage);
 25    } catch (err) {
 26      yield put(
 27        notificationsActions.showNotification(
 28          'danger',
 29          translateRaw('SIGN_MSG_FAIL', { $err: err.message }),
 30          5000
 31        )
 32      );
 33      yield put(actions.signMessageFailed());
 34    }
 35  }
 36  
 37  export function messageToData(messageToTransform: string): string {
 38    return (
 39      '0x' +
 40      Array.from(Buffer.from(messageToTransform, 'utf8'))
 41        .map(n => padLeftEven(n.toString(16)))
 42        .join('')
 43    );
 44  }
 45  
 46  function* signLocalMessage(wallet: IFullWallet, msg: string): SagaIterator {
 47    const address = yield apply(wallet, wallet.getAddressString);
 48    const nodeLib: Web3Node = yield select(configNodesSelectors.getNodeLib);
 49    const sig: string = yield apply(wallet, wallet.signMessage, [msg, nodeLib]);
 50  
 51    yield put(
 52      actions.signLocalMessageSucceeded({
 53        address,
 54        msg,
 55        sig,
 56        version: '2'
 57      })
 58    );
 59  }
 60  
 61  function* signParitySignerMessage(wallet: IFullWallet, msg: string): SagaIterator {
 62    const address = yield apply(wallet, wallet.getAddressString);
 63    const data = yield call(messageToData, msg);
 64  
 65    yield put(paritySignerActions.requestMessageSignature(address, data));
 66  
 67    const { payload: sig }: paritySignerTypes.FinalizeSignatureAction = yield take(
 68      paritySignerTypes.ParitySignerActions.FINALIZE_SIGNATURE
 69    );
 70  
 71    if (!sig) {
 72      throw new Error(translateRaw('ERROR_38'));
 73    }
 74  
 75    yield put(
 76      actions.signLocalMessageSucceeded({
 77        address,
 78        msg,
 79        sig,
 80        version: '2'
 81      })
 82    );
 83  }
 84  
 85  function* handleMessageRequest(action: types.SignMessageRequestedAction): SagaIterator {
 86    const walletType: walletSelectors.IWalletType = yield select(walletSelectors.getWalletType);
 87  
 88    const signingHandler = walletType.isParitySignerWallet
 89      ? signParitySignerMessage
 90      : signLocalMessage;
 91  
 92    return yield call(signingWrapper, signingHandler, action);
 93  }
 94  
 95  function* verifySignature(action: types.SignLocalMessageSucceededAction): SagaIterator {
 96    const success = yield call(verifySignedMessage, action.payload);
 97  
 98    if (success) {
 99      yield put(
100        notificationsActions.showNotification(
101          'success',
102          translateRaw('SIGN_MSG_SUCCESS', { $address: action.payload.address })
103        )
104      );
105    } else {
106      yield put(actions.signMessageFailed());
107      yield put(notificationsActions.showNotification('danger', translateRaw('ERROR_38')));
108    }
109  }
110  
111  export const signing = [
112    takeEvery(types.MessageActions.SIGN_REQUESTED, handleMessageRequest),
113    takeEvery(types.MessageActions.SIGN_LOCAL_SUCCEEDED, verifySignature)
114  ];
115  
116  export function* messageSaga(): SagaIterator {
117    yield all([...signing]);
118  }