mirror of
https://github.com/status-im/MyCrypto.git
synced 2025-02-18 14:07:31 +00:00
Refactor Generate Transaction (#960)
* Make generic modal * Allow generic modals to be injected into send button component * Refactor generate transaction, cleanup transaction sagas, simplify signing process * Get passing unit tests * Make previous test more comprehensive * Fix ts errors
This commit is contained in:
parent
f748f22e2e
commit
84bae60c02
@ -1,9 +1,8 @@
|
|||||||
import {
|
import {
|
||||||
SignTransactionFailedAction,
|
SignTransactionFailedAction,
|
||||||
SignLocalTransactionRequestedAction,
|
|
||||||
SignWeb3TransactionRequestedAction,
|
|
||||||
SignLocalTransactionSucceededAction,
|
SignLocalTransactionSucceededAction,
|
||||||
SignWeb3TransactionSucceededAction
|
SignWeb3TransactionSucceededAction,
|
||||||
|
SignTransactionRequestedAction
|
||||||
} from '../actionTypes';
|
} from '../actionTypes';
|
||||||
import { TypeKeys } from '../constants';
|
import { TypeKeys } from '../constants';
|
||||||
|
|
||||||
@ -12,6 +11,12 @@ const signTransactionFailed = (): SignTransactionFailedAction => ({
|
|||||||
type: TypeKeys.SIGN_TRANSACTION_FAILED
|
type: TypeKeys.SIGN_TRANSACTION_FAILED
|
||||||
});
|
});
|
||||||
|
|
||||||
|
type TSignTransactionRequested = typeof signTransactionRequested;
|
||||||
|
const signTransactionRequested = (payload: SignTransactionRequestedAction['payload']) => ({
|
||||||
|
type: TypeKeys.SIGN_TRANSACTION_REQUESTED,
|
||||||
|
payload
|
||||||
|
});
|
||||||
|
|
||||||
type TSignLocalTransactionSucceeded = typeof signLocalTransactionSucceeded;
|
type TSignLocalTransactionSucceeded = typeof signLocalTransactionSucceeded;
|
||||||
const signLocalTransactionSucceeded = (
|
const signLocalTransactionSucceeded = (
|
||||||
payload: SignLocalTransactionSucceededAction['payload']
|
payload: SignLocalTransactionSucceededAction['payload']
|
||||||
@ -20,14 +25,6 @@ const signLocalTransactionSucceeded = (
|
|||||||
payload
|
payload
|
||||||
});
|
});
|
||||||
|
|
||||||
type TSignLocalTransactionRequested = typeof signLocalTransactionRequested;
|
|
||||||
const signLocalTransactionRequested = (
|
|
||||||
payload: SignLocalTransactionRequestedAction['payload']
|
|
||||||
): SignLocalTransactionRequestedAction => ({
|
|
||||||
type: TypeKeys.SIGN_LOCAL_TRANSACTION_REQUESTED,
|
|
||||||
payload
|
|
||||||
});
|
|
||||||
|
|
||||||
type TSignWeb3TransactionSucceeded = typeof signWeb3TransactionSucceeded;
|
type TSignWeb3TransactionSucceeded = typeof signWeb3TransactionSucceeded;
|
||||||
const signWeb3TransactionSucceeded = (
|
const signWeb3TransactionSucceeded = (
|
||||||
payload: SignWeb3TransactionSucceededAction['payload']
|
payload: SignWeb3TransactionSucceededAction['payload']
|
||||||
@ -36,23 +33,13 @@ const signWeb3TransactionSucceeded = (
|
|||||||
payload
|
payload
|
||||||
});
|
});
|
||||||
|
|
||||||
type TSignWeb3TransactionRequested = typeof signWeb3TransactionRequested;
|
|
||||||
const signWeb3TransactionRequested = (
|
|
||||||
payload: SignWeb3TransactionRequestedAction['payload']
|
|
||||||
): SignWeb3TransactionRequestedAction => ({
|
|
||||||
type: TypeKeys.SIGN_WEB3_TRANSACTION_REQUESTED,
|
|
||||||
payload
|
|
||||||
});
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
signTransactionRequested,
|
||||||
signTransactionFailed,
|
signTransactionFailed,
|
||||||
signLocalTransactionSucceeded,
|
signLocalTransactionSucceeded,
|
||||||
signLocalTransactionRequested,
|
|
||||||
signWeb3TransactionSucceeded,
|
signWeb3TransactionSucceeded,
|
||||||
signWeb3TransactionRequested,
|
|
||||||
TSignLocalTransactionSucceeded,
|
TSignLocalTransactionSucceeded,
|
||||||
TSignLocalTransactionRequested,
|
|
||||||
TSignWeb3TransactionSucceeded,
|
TSignWeb3TransactionSucceeded,
|
||||||
TSignWeb3TransactionRequested,
|
TSignTransactionFailed,
|
||||||
TSignTransactionFailed
|
TSignTransactionRequested
|
||||||
};
|
};
|
||||||
|
@ -8,8 +8,8 @@ import { TypeKeys } from 'actions/transaction/constants';
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* Signing / Async actions */
|
/* Signing / Async actions */
|
||||||
interface SignLocalTransactionRequestedAction {
|
interface SignTransactionRequestedAction {
|
||||||
type: TypeKeys.SIGN_LOCAL_TRANSACTION_REQUESTED;
|
type: TypeKeys.SIGN_TRANSACTION_REQUESTED;
|
||||||
payload: EthTx;
|
payload: EthTx;
|
||||||
}
|
}
|
||||||
interface SignLocalTransactionSucceededAction {
|
interface SignLocalTransactionSucceededAction {
|
||||||
@ -17,10 +17,6 @@ interface SignLocalTransactionSucceededAction {
|
|||||||
payload: { signedTransaction: Buffer; indexingHash: string; noVerify?: boolean }; // dont verify against fields, for pushTx
|
payload: { signedTransaction: Buffer; indexingHash: string; noVerify?: boolean }; // dont verify against fields, for pushTx
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SignWeb3TransactionRequestedAction {
|
|
||||||
type: TypeKeys.SIGN_WEB3_TRANSACTION_REQUESTED;
|
|
||||||
payload: EthTx;
|
|
||||||
}
|
|
||||||
interface SignWeb3TransactionSucceededAction {
|
interface SignWeb3TransactionSucceededAction {
|
||||||
type: TypeKeys.SIGN_WEB3_TRANSACTION_SUCCEEDED;
|
type: TypeKeys.SIGN_WEB3_TRANSACTION_SUCCEEDED;
|
||||||
payload: { transaction: Buffer; indexingHash: string; noVerify?: boolean };
|
payload: { transaction: Buffer; indexingHash: string; noVerify?: boolean };
|
||||||
@ -30,16 +26,14 @@ interface SignTransactionFailedAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SignAction =
|
type SignAction =
|
||||||
| SignLocalTransactionRequestedAction
|
| SignTransactionRequestedAction
|
||||||
| SignLocalTransactionSucceededAction
|
| SignLocalTransactionSucceededAction
|
||||||
| SignWeb3TransactionRequestedAction
|
|
||||||
| SignWeb3TransactionSucceededAction
|
| SignWeb3TransactionSucceededAction
|
||||||
| SignTransactionFailedAction;
|
| SignTransactionFailedAction;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
SignLocalTransactionRequestedAction,
|
SignTransactionRequestedAction,
|
||||||
SignLocalTransactionSucceededAction,
|
SignLocalTransactionSucceededAction,
|
||||||
SignWeb3TransactionRequestedAction,
|
|
||||||
SignWeb3TransactionSucceededAction,
|
SignWeb3TransactionSucceededAction,
|
||||||
SignTransactionFailedAction,
|
SignTransactionFailedAction,
|
||||||
SignAction
|
SignAction
|
||||||
|
@ -12,9 +12,8 @@ export enum TypeKeys {
|
|||||||
GET_NONCE_SUCCEEDED = 'GET_NONCE_SUCCEEDED',
|
GET_NONCE_SUCCEEDED = 'GET_NONCE_SUCCEEDED',
|
||||||
GET_NONCE_FAILED = 'GET_NONCE_FAILED',
|
GET_NONCE_FAILED = 'GET_NONCE_FAILED',
|
||||||
|
|
||||||
SIGN_WEB3_TRANSACTION_REQUESTED = 'SIGN_WEB3_TRANSACTION_REQUESTED',
|
SIGN_TRANSACTION_REQUESTED = 'SIGN_TRANSACTION_REQUESTED',
|
||||||
SIGN_WEB3_TRANSACTION_SUCCEEDED = 'SIGN_WEB3_TRANSACTION_SUCCEEDED',
|
SIGN_WEB3_TRANSACTION_SUCCEEDED = 'SIGN_WEB3_TRANSACTION_SUCCEEDED',
|
||||||
SIGN_LOCAL_TRANSACTION_REQUESTED = 'SIGN_LOCAL_TRANSACTION_REQUESTED',
|
|
||||||
SIGN_LOCAL_TRANSACTION_SUCCEEDED = 'SIGN_LOCAL_TRANSACTION_SUCCEEDED',
|
SIGN_LOCAL_TRANSACTION_SUCCEEDED = 'SIGN_LOCAL_TRANSACTION_SUCCEEDED',
|
||||||
SIGN_TRANSACTION_FAILED = 'SIGN_TRANSACTION_FAILED',
|
SIGN_TRANSACTION_FAILED = 'SIGN_TRANSACTION_FAILED',
|
||||||
|
|
||||||
|
13
common/components/GenerateTransaction.tsx
Normal file
13
common/components/GenerateTransaction.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { GenerateTransactionFactory } from './GenerateTransactionFactory';
|
||||||
|
import React from 'react';
|
||||||
|
import translate from 'translations';
|
||||||
|
|
||||||
|
export const GenerateTransaction: React.SFC<{}> = () => (
|
||||||
|
<GenerateTransactionFactory
|
||||||
|
withProps={({ disabled, isWeb3Wallet, onClick }) => (
|
||||||
|
<button disabled={disabled} className="btn btn-info btn-block" onClick={onClick}>
|
||||||
|
{isWeb3Wallet ? translate('Send to MetaMask / Mist') : translate('DEP_signtx')}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
@ -1,43 +0,0 @@
|
|||||||
import {
|
|
||||||
signLocalTransactionRequested,
|
|
||||||
signWeb3TransactionRequested,
|
|
||||||
TSignLocalTransactionRequested,
|
|
||||||
TSignWeb3TransactionRequested,
|
|
||||||
SignLocalTransactionRequestedAction,
|
|
||||||
SignWeb3TransactionRequestedAction
|
|
||||||
} from 'actions/transaction';
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import { connect, Dispatch } from 'react-redux';
|
|
||||||
import { bindActionCreators } from 'redux';
|
|
||||||
import { AppState } from 'reducers';
|
|
||||||
type Payload =
|
|
||||||
| SignLocalTransactionRequestedAction['payload']
|
|
||||||
| SignWeb3TransactionRequestedAction['payload'];
|
|
||||||
type Signer = (
|
|
||||||
payload: Payload
|
|
||||||
) => () => SignLocalTransactionRequestedAction | SignWeb3TransactionRequestedAction;
|
|
||||||
|
|
||||||
interface DispatchProps {
|
|
||||||
signer: TSignLocalTransactionRequested | TSignWeb3TransactionRequested;
|
|
||||||
}
|
|
||||||
interface Props {
|
|
||||||
isWeb3: boolean;
|
|
||||||
withSigner(signer: Signer): React.ReactElement<any> | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
class Container extends Component<DispatchProps & Props, {}> {
|
|
||||||
public render() {
|
|
||||||
return this.props.withSigner(this.sign);
|
|
||||||
}
|
|
||||||
|
|
||||||
private sign = (payload: Payload) => () => this.props.signer(payload);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const WithSigner = connect(null, (dispatch: Dispatch<AppState>, ownProps: Props) => {
|
|
||||||
return bindActionCreators(
|
|
||||||
{
|
|
||||||
signer: ownProps.isWeb3 ? signWeb3TransactionRequested : signLocalTransactionRequested
|
|
||||||
},
|
|
||||||
dispatch
|
|
||||||
);
|
|
||||||
})(Container);
|
|
@ -1 +0,0 @@
|
|||||||
export * from './GenerateTransaction';
|
|
20
common/components/GenerateTransactionFactory/Container.tsx
Normal file
20
common/components/GenerateTransactionFactory/Container.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { signTransactionRequested, TSignTransactionRequested } from 'actions/transaction';
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
|
interface DispatchProps {
|
||||||
|
signTransactionRequested: TSignTransactionRequested;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OwnProps {
|
||||||
|
isWeb3: boolean;
|
||||||
|
withSigner(signer: TSignTransactionRequested): React.ReactElement<any> | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Container extends Component<DispatchProps & OwnProps, {}> {
|
||||||
|
public render() {
|
||||||
|
return this.props.withSigner(this.props.signTransactionRequested);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const WithSigner = connect(null, { signTransactionRequested })(Container);
|
@ -1,4 +1,3 @@
|
|||||||
import translate from 'translations';
|
|
||||||
import { WithSigner } from './Container';
|
import { WithSigner } from './Container';
|
||||||
import EthTx from 'ethereumjs-tx';
|
import EthTx from 'ethereumjs-tx';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
@ -12,6 +11,12 @@ import {
|
|||||||
} from 'selectors/transaction';
|
} from 'selectors/transaction';
|
||||||
import { getWalletType } from 'selectors/wallet';
|
import { getWalletType } from 'selectors/wallet';
|
||||||
|
|
||||||
|
export interface CallbackProps {
|
||||||
|
disabled: boolean;
|
||||||
|
isWeb3Wallet: boolean;
|
||||||
|
onClick(): void;
|
||||||
|
}
|
||||||
|
|
||||||
interface StateProps {
|
interface StateProps {
|
||||||
transaction: EthTx;
|
transaction: EthTx;
|
||||||
networkRequestPending: boolean;
|
networkRequestPending: boolean;
|
||||||
@ -21,16 +26,21 @@ interface StateProps {
|
|||||||
validGasLimit: boolean;
|
validGasLimit: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
class GenerateTransactionClass extends Component<StateProps> {
|
interface OwnProps {
|
||||||
|
withProps(props: CallbackProps): React.ReactElement<any> | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Props = OwnProps & StateProps;
|
||||||
|
|
||||||
|
class GenerateTransactionFactoryClass extends Component<Props> {
|
||||||
public render() {
|
public render() {
|
||||||
const {
|
const {
|
||||||
isFullTransaction,
|
isFullTransaction,
|
||||||
isWeb3Wallet,
|
isWeb3Wallet,
|
||||||
transaction,
|
|
||||||
networkRequestPending,
|
networkRequestPending,
|
||||||
|
|
||||||
validGasPrice,
|
validGasPrice,
|
||||||
validGasLimit
|
validGasLimit,
|
||||||
|
transaction
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const isButtonDisabled =
|
const isButtonDisabled =
|
||||||
@ -38,24 +48,22 @@ class GenerateTransactionClass extends Component<StateProps> {
|
|||||||
return (
|
return (
|
||||||
<WithSigner
|
<WithSigner
|
||||||
isWeb3={isWeb3Wallet}
|
isWeb3={isWeb3Wallet}
|
||||||
withSigner={signer => (
|
withSigner={signer =>
|
||||||
<button
|
this.props.withProps({
|
||||||
disabled={isButtonDisabled}
|
disabled: isButtonDisabled,
|
||||||
className="btn btn-info btn-block"
|
isWeb3Wallet,
|
||||||
onClick={signer(transaction)}
|
onClick: () => signer(transaction)
|
||||||
>
|
})
|
||||||
{isWeb3Wallet ? translate('Send to MetaMask / Mist') : translate('DEP_signtx')}
|
}
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const GenerateTransaction = connect((state: AppState) => ({
|
export const GenerateTransactionFactory = connect((state: AppState) => ({
|
||||||
...getTransaction(state),
|
...getTransaction(state),
|
||||||
networkRequestPending: isNetworkRequestPending(state),
|
networkRequestPending: isNetworkRequestPending(state),
|
||||||
isWeb3Wallet: getWalletType(state).isWeb3Wallet,
|
isWeb3Wallet: getWalletType(state).isWeb3Wallet,
|
||||||
validGasPrice: isValidGasPrice(state),
|
validGasPrice: isValidGasPrice(state),
|
||||||
validGasLimit: isValidGasLimit(state)
|
validGasLimit: isValidGasLimit(state)
|
||||||
}))(GenerateTransactionClass);
|
}))(GenerateTransactionFactoryClass);
|
1
common/components/GenerateTransactionFactory/index.ts
Normal file
1
common/components/GenerateTransactionFactory/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './GenerateTransactionFactory';
|
@ -14,7 +14,7 @@ const INITIAL_STATE: State = {
|
|||||||
pending: false
|
pending: false
|
||||||
};
|
};
|
||||||
|
|
||||||
const signLocalTransactionRequested = (): State => ({
|
const signTransactionRequested = (): State => ({
|
||||||
...INITIAL_STATE,
|
...INITIAL_STATE,
|
||||||
pending: true
|
pending: true
|
||||||
});
|
});
|
||||||
@ -30,7 +30,7 @@ const signLocalTransactionSucceeded = (
|
|||||||
web3: { transaction: null }
|
web3: { transaction: null }
|
||||||
});
|
});
|
||||||
|
|
||||||
const signWeb3TranscationRequested = (
|
const signWeb3TranscationSucceeded = (
|
||||||
_: State,
|
_: State,
|
||||||
{ payload }: SignWeb3TransactionSucceededAction
|
{ payload }: SignWeb3TransactionSucceededAction
|
||||||
): State => ({
|
): State => ({
|
||||||
@ -47,12 +47,12 @@ const reset = () => INITIAL_STATE;
|
|||||||
|
|
||||||
export const sign = (state: State = INITIAL_STATE, action: SignAction | ResetAction) => {
|
export const sign = (state: State = INITIAL_STATE, action: SignAction | ResetAction) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case TK.SIGN_LOCAL_TRANSACTION_REQUESTED:
|
case TK.SIGN_TRANSACTION_REQUESTED:
|
||||||
return signLocalTransactionRequested();
|
return signTransactionRequested();
|
||||||
case TK.SIGN_LOCAL_TRANSACTION_SUCCEEDED:
|
case TK.SIGN_LOCAL_TRANSACTION_SUCCEEDED:
|
||||||
return signLocalTransactionSucceeded(state, action);
|
return signLocalTransactionSucceeded(state, action);
|
||||||
case TK.SIGN_WEB3_TRANSACTION_SUCCEEDED:
|
case TK.SIGN_WEB3_TRANSACTION_SUCCEEDED:
|
||||||
return signWeb3TranscationRequested(state, action);
|
return signWeb3TranscationSucceeded(state, action);
|
||||||
case TK.SIGN_TRANSACTION_FAILED:
|
case TK.SIGN_TRANSACTION_FAILED:
|
||||||
return signTransactionFailed();
|
return signTransactionFailed();
|
||||||
case TK.RESET:
|
case TK.RESET:
|
||||||
|
@ -12,11 +12,16 @@ import { SetCurrentValueAction, TypeKeys } from 'actions/transaction';
|
|||||||
import { toTokenBase } from 'libs/units';
|
import { toTokenBase } from 'libs/units';
|
||||||
import { validateInput, IInput } from 'sagas/transaction/validationHelpers';
|
import { validateInput, IInput } from 'sagas/transaction/validationHelpers';
|
||||||
import { validNumber, validDecimal } from 'libs/validators';
|
import { validNumber, validDecimal } from 'libs/validators';
|
||||||
export function* setCurrentValue({ payload }: SetCurrentValueAction): SagaIterator {
|
|
||||||
|
export function* setCurrentValue(action: SetCurrentValueAction): SagaIterator {
|
||||||
const etherTransaction = yield select(isEtherTransaction);
|
const etherTransaction = yield select(isEtherTransaction);
|
||||||
|
const setter = etherTransaction ? setValueField : setTokenValue;
|
||||||
|
return yield call(valueHandler, action, setter);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function* valueHandler({ payload }: SetCurrentValueAction, setter) {
|
||||||
const decimal: number = yield select(getDecimal);
|
const decimal: number = yield select(getDecimal);
|
||||||
const unit: string = yield select(getUnit);
|
const unit: string = yield select(getUnit);
|
||||||
const setter = etherTransaction ? setValueField : setTokenValue;
|
|
||||||
|
|
||||||
if (!validNumber(+payload) || !validDecimal(payload, decimal)) {
|
if (!validNumber(+payload) || !validDecimal(payload, decimal)) {
|
||||||
return yield put(setter({ raw: payload, value: null }));
|
return yield put(setter({ raw: payload, value: null }));
|
||||||
@ -51,6 +56,7 @@ export function* reparseCurrentValue(value: IInput): SagaIterator {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const currentValue = [
|
export const currentValue = [
|
||||||
takeEvery([TypeKeys.CURRENT_VALUE_SET], setCurrentValue),
|
takeEvery([TypeKeys.CURRENT_VALUE_SET], setCurrentValue),
|
||||||
takeEvery([TypeKeys.GAS_LIMIT_FIELD_SET, TypeKeys.GAS_PRICE_FIELD_SET], revalidateCurrentValue)
|
takeEvery([TypeKeys.GAS_LIMIT_FIELD_SET, TypeKeys.GAS_PRICE_FIELD_SET], revalidateCurrentValue)
|
||||||
|
@ -4,12 +4,11 @@ import { getNetworkConfig } from 'selectors/config';
|
|||||||
import { select, call, put, take } from 'redux-saga/effects';
|
import { select, call, put, take } from 'redux-saga/effects';
|
||||||
import {
|
import {
|
||||||
signTransactionFailed,
|
signTransactionFailed,
|
||||||
SignWeb3TransactionRequestedAction,
|
|
||||||
SignLocalTransactionRequestedAction,
|
|
||||||
GetFromFailedAction,
|
GetFromFailedAction,
|
||||||
GetFromSucceededAction,
|
GetFromSucceededAction,
|
||||||
getFromRequested,
|
getFromRequested,
|
||||||
TypeKeys as TK
|
TypeKeys as TK,
|
||||||
|
SignTransactionRequestedAction
|
||||||
} from 'actions/transaction';
|
} from 'actions/transaction';
|
||||||
import Tx from 'ethereumjs-tx';
|
import Tx from 'ethereumjs-tx';
|
||||||
import { NetworkConfig } from 'config';
|
import { NetworkConfig } from 'config';
|
||||||
@ -22,7 +21,7 @@ interface IFullWalletAndTransaction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const signTransactionWrapper = (func: (IWalletAndTx: IFullWalletAndTransaction) => SagaIterator) =>
|
const signTransactionWrapper = (func: (IWalletAndTx: IFullWalletAndTransaction) => SagaIterator) =>
|
||||||
function*(partialTx: SignLocalTransactionRequestedAction | SignWeb3TransactionRequestedAction) {
|
function*(partialTx: SignTransactionRequestedAction) {
|
||||||
try {
|
try {
|
||||||
const IWalletAndTx: IFullWalletAndTransaction = yield call(
|
const IWalletAndTx: IFullWalletAndTransaction = yield call(
|
||||||
getWalletAndTransaction,
|
getWalletAndTransaction,
|
||||||
@ -40,9 +39,7 @@ const signTransactionWrapper = (func: (IWalletAndTx: IFullWalletAndTransaction)
|
|||||||
* the rest of the tx parameters from the action
|
* the rest of the tx parameters from the action
|
||||||
* @param partialTx
|
* @param partialTx
|
||||||
*/
|
*/
|
||||||
function* getWalletAndTransaction(
|
function* getWalletAndTransaction(partialTx: SignTransactionRequestedAction['payload']) {
|
||||||
partialTx: (SignLocalTransactionRequestedAction | SignWeb3TransactionRequestedAction)['payload']
|
|
||||||
) {
|
|
||||||
// get the wallet we're going to sign with
|
// get the wallet we're going to sign with
|
||||||
const wallet: null | IFullWallet = yield select(getWalletInst);
|
const wallet: null | IFullWallet = yield select(getWalletInst);
|
||||||
if (!wallet) {
|
if (!wallet) {
|
||||||
|
@ -7,11 +7,13 @@ import {
|
|||||||
TypeKeys,
|
TypeKeys,
|
||||||
reset,
|
reset,
|
||||||
SignWeb3TransactionSucceededAction,
|
SignWeb3TransactionSucceededAction,
|
||||||
SignLocalTransactionSucceededAction
|
SignLocalTransactionSucceededAction,
|
||||||
|
SignTransactionRequestedAction
|
||||||
} from 'actions/transaction';
|
} from 'actions/transaction';
|
||||||
import { computeIndexingHash } from 'libs/transaction';
|
import { computeIndexingHash } from 'libs/transaction';
|
||||||
import { serializedAndTransactionFieldsMatch } from 'selectors/transaction';
|
import { serializedAndTransactionFieldsMatch } from 'selectors/transaction';
|
||||||
import { showNotification } from 'actions/notifications';
|
import { showNotification } from 'actions/notifications';
|
||||||
|
import { getWalletType, IWalletType } from 'selectors/wallet';
|
||||||
|
|
||||||
export function* signLocalTransactionHandler({
|
export function* signLocalTransactionHandler({
|
||||||
tx,
|
tx,
|
||||||
@ -64,9 +66,15 @@ function* verifyTransaction({
|
|||||||
yield put(reset());
|
yield put(reset());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function* handleTransactionRequest(action: SignTransactionRequestedAction): SagaIterator {
|
||||||
|
const walletType: IWalletType = yield select(getWalletType);
|
||||||
|
const signingHandler = walletType.isWeb3Wallet ? signWeb3Transaction : signLocalTransaction;
|
||||||
|
return yield call(signingHandler, action);
|
||||||
|
}
|
||||||
|
|
||||||
export const signing = [
|
export const signing = [
|
||||||
takeEvery(TypeKeys.SIGN_LOCAL_TRANSACTION_REQUESTED, signLocalTransaction),
|
takeEvery(TypeKeys.SIGN_TRANSACTION_REQUESTED, handleTransactionRequest),
|
||||||
takeEvery(TypeKeys.SIGN_WEB3_TRANSACTION_REQUESTED, signWeb3Transaction),
|
|
||||||
takeEvery(
|
takeEvery(
|
||||||
[TypeKeys.SIGN_LOCAL_TRANSACTION_SUCCEEDED, TypeKeys.SIGN_WEB3_TRANSACTION_SUCCEEDED],
|
[TypeKeys.SIGN_LOCAL_TRANSACTION_SUCCEEDED, TypeKeys.SIGN_WEB3_TRANSACTION_SUCCEEDED],
|
||||||
verifyTransaction
|
verifyTransaction
|
||||||
|
@ -6,8 +6,10 @@ import { validateInput } from 'sagas/transaction/validationHelpers';
|
|||||||
import {
|
import {
|
||||||
setCurrentValue,
|
setCurrentValue,
|
||||||
revalidateCurrentValue,
|
revalidateCurrentValue,
|
||||||
reparseCurrentValue
|
reparseCurrentValue,
|
||||||
|
valueHandler
|
||||||
} from 'sagas/transaction/current/currentValue';
|
} from 'sagas/transaction/current/currentValue';
|
||||||
|
import { cloneableGenerator, SagaIteratorClone } from 'redux-saga/utils';
|
||||||
|
|
||||||
const itShouldBeDone = gen => {
|
const itShouldBeDone = gen => {
|
||||||
it('should be done', () => {
|
it('should be done', () => {
|
||||||
@ -15,77 +17,69 @@ const itShouldBeDone = gen => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('setCurrentValue*', () => {
|
describe('valueHandler', () => {
|
||||||
const sharedLogic = (gen, etherTransaction, decimal: number) => {
|
const action: any = { payload: '5.1' };
|
||||||
it('should select isEtherTransaction', () => {
|
const setter = setValueField;
|
||||||
expect(gen.next().value).toEqual(select(isEtherTransaction));
|
const decimal = 1;
|
||||||
});
|
const gen: { [key: string]: SagaIteratorClone } = {};
|
||||||
|
|
||||||
it('should select getDecimal', () => {
|
const failCases = {
|
||||||
expect(gen.next(etherTransaction).value).toEqual(select(getDecimal));
|
invalidDecimal: 0,
|
||||||
});
|
invalidNumber: {
|
||||||
it('should select getUnit', () => {
|
decimal: 1,
|
||||||
expect(gen.next(decimal).value).toEqual(select(getUnit));
|
action: { payload: 'x' }
|
||||||
});
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('when invalid number or decimal', () => {
|
gen.pass = cloneableGenerator(valueHandler)(action, setter);
|
||||||
const invalidDecimal: any = {
|
gen.invalidNumber = cloneableGenerator(valueHandler)(
|
||||||
payload: '10.01'
|
failCases.invalidNumber.action as any,
|
||||||
};
|
setter
|
||||||
const invalidNumber: any = {
|
);
|
||||||
payload: 'invalidNumber'
|
const value = toTokenBase(action.payload, decimal);
|
||||||
};
|
const unit = 'eth';
|
||||||
const etherTransaction = true;
|
|
||||||
const decimal = 1;
|
|
||||||
const gen1 = setCurrentValue(invalidNumber);
|
|
||||||
const gen2 = setCurrentValue(invalidDecimal);
|
|
||||||
|
|
||||||
sharedLogic(gen2, etherTransaction, decimal);
|
it('should select getDecimal', () => {
|
||||||
sharedLogic(gen1, etherTransaction, decimal);
|
expect(gen.pass.next().value).toEqual(select(getDecimal));
|
||||||
|
expect(gen.invalidNumber.next().value).toEqual(select(getDecimal));
|
||||||
|
});
|
||||||
|
it('should select getUnit', () => {
|
||||||
|
gen.invalidDecimal = gen.pass.clone();
|
||||||
|
|
||||||
it('should put setter', () => {
|
expect(gen.pass.next(decimal).value).toEqual(select(getUnit));
|
||||||
expect(gen1.next().value).toEqual(
|
expect(gen.invalidNumber.next(decimal).value).toEqual(select(getUnit));
|
||||||
put(setValueField({ raw: invalidNumber.payload, value: null }))
|
expect(gen.invalidDecimal.next(failCases.invalidDecimal).value).toEqual(select(getUnit));
|
||||||
);
|
|
||||||
expect(gen2.next().value).toEqual(
|
|
||||||
put(setValueField({ raw: invalidDecimal.payload, value: null }))
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
itShouldBeDone(gen1);
|
|
||||||
itShouldBeDone(gen2);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when valid number and decimal', () => {
|
it('should fail on invalid number or decimal and put null as a value', () => {
|
||||||
const payload = '100';
|
expect(gen.invalidNumber.next(unit).value).toEqual(
|
||||||
const action: any = { payload };
|
put(setter({ raw: failCases.invalidNumber.action.payload, value: null }))
|
||||||
const etherTransaction = true;
|
);
|
||||||
const unit = 'ether';
|
expect(gen.invalidDecimal.next(unit).value).toEqual(
|
||||||
const decimal = 0;
|
put(setter({ raw: action.payload, value: null }))
|
||||||
const value = toTokenBase(payload, decimal);
|
);
|
||||||
const isValid = true;
|
|
||||||
|
|
||||||
const gen = setCurrentValue(action);
|
|
||||||
|
|
||||||
sharedLogic(gen, etherTransaction, decimal);
|
|
||||||
it('should call validateInput', () => {
|
|
||||||
expect(gen.next(unit).value).toEqual(call(validateInput, value, unit));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should put setter', () => {
|
|
||||||
expect(gen.next(isValid).value).toEqual(
|
|
||||||
put(
|
|
||||||
setValueField({
|
|
||||||
raw: payload,
|
|
||||||
value
|
|
||||||
})
|
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
itShouldBeDone(gen);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should call isValid', () => {
|
||||||
|
expect(gen.pass.next(unit).value).toEqual(call(validateInput, value, unit));
|
||||||
|
});
|
||||||
|
it('should put setter', () => {
|
||||||
|
expect(gen.pass.next(true).value).toEqual(put(setter({ raw: action.payload, value })));
|
||||||
|
});
|
||||||
|
|
||||||
|
itShouldBeDone(gen.pass);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('setCurrentValue*', () => {
|
||||||
|
const action: any = { payload: '5' };
|
||||||
|
const gen = setCurrentValue(action);
|
||||||
|
it('should select isEtherTransaction', () => {
|
||||||
|
expect(gen.next().value).toEqual(select(isEtherTransaction));
|
||||||
|
});
|
||||||
|
it('should call valueHandler', () => {
|
||||||
|
expect(gen.next(isEtherTransaction).value).toEqual(call(valueHandler, action, setValueField));
|
||||||
|
});
|
||||||
|
itShouldBeDone(gen);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('revalidateCurrentValue*', () => {
|
describe('revalidateCurrentValue*', () => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user