364 lines
11 KiB
TypeScript
364 lines
11 KiB
TypeScript
import * as _ from 'lodash';
|
|
import {ZeroEx} from '0x.js';
|
|
import BigNumber from 'bignumber.js';
|
|
import {utils} from 'ts/utils/utils';
|
|
import {
|
|
GenerateOrderSteps,
|
|
Side,
|
|
SideToAssetToken,
|
|
Direction,
|
|
BlockchainErrs,
|
|
SignatureData,
|
|
TokenByAddress,
|
|
TokenStateByAddress,
|
|
Order,
|
|
Action,
|
|
ActionTypes,
|
|
ScreenWidths,
|
|
ProviderType,
|
|
TokenState,
|
|
} from 'ts/types';
|
|
|
|
// Instead of defaulting the docs version to an empty string, we pre-populate it with
|
|
// a valid version value. This does not need to be updated however, since onLoad, it
|
|
// is always replaced with a value retrieved from our S3 bucket.
|
|
const DEFAULT_DOCS_VERSION = '0.0.0';
|
|
|
|
export interface State {
|
|
// Portal
|
|
blockchainErr: BlockchainErrs;
|
|
blockchainIsLoaded: boolean;
|
|
generateOrderStep: GenerateOrderSteps;
|
|
networkId: number;
|
|
orderExpiryTimestamp: BigNumber;
|
|
orderFillAmount: BigNumber;
|
|
orderTakerAddress: string;
|
|
orderSignatureData: SignatureData;
|
|
orderSalt: BigNumber;
|
|
nodeVersion: string;
|
|
screenWidth: ScreenWidths;
|
|
shouldBlockchainErrDialogBeOpen: boolean;
|
|
sideToAssetToken: SideToAssetToken;
|
|
tokenByAddress: TokenByAddress;
|
|
tokenStateByAddress: TokenStateByAddress;
|
|
userAddress: string;
|
|
userEtherBalance: BigNumber;
|
|
// Note: cache of supplied orderJSON in fill order step. Do not use for anything else.
|
|
userSuppliedOrderCache: Order;
|
|
|
|
// Docs
|
|
docsVersion: string;
|
|
availableDocVersions: string[];
|
|
|
|
// Shared
|
|
flashMessage: string|React.ReactNode;
|
|
providerType: ProviderType;
|
|
injectedProviderName: string;
|
|
};
|
|
|
|
const INITIAL_STATE: State = {
|
|
// Portal
|
|
blockchainErr: '',
|
|
blockchainIsLoaded: false,
|
|
generateOrderStep: GenerateOrderSteps.ChooseAssets,
|
|
networkId: undefined,
|
|
orderExpiryTimestamp: utils.initialOrderExpiryUnixTimestampSec(),
|
|
orderFillAmount: undefined,
|
|
orderSignatureData: {
|
|
hash: '',
|
|
r: '',
|
|
s: '',
|
|
v: 27,
|
|
},
|
|
orderTakerAddress: '',
|
|
orderSalt: ZeroEx.generatePseudoRandomSalt(),
|
|
nodeVersion: undefined,
|
|
screenWidth: utils.getScreenWidth(),
|
|
shouldBlockchainErrDialogBeOpen: false,
|
|
sideToAssetToken: {
|
|
[Side.deposit]: {},
|
|
[Side.receive]: {},
|
|
},
|
|
tokenByAddress: {},
|
|
tokenStateByAddress: {},
|
|
userAddress: '',
|
|
userEtherBalance: new BigNumber(0),
|
|
userSuppliedOrderCache: undefined,
|
|
|
|
// Docs
|
|
docsVersion: DEFAULT_DOCS_VERSION,
|
|
availableDocVersions: [DEFAULT_DOCS_VERSION],
|
|
|
|
// Shared
|
|
flashMessage: undefined,
|
|
providerType: ProviderType.INJECTED,
|
|
injectedProviderName: '',
|
|
};
|
|
|
|
export function reducer(state: State = INITIAL_STATE, action: Action) {
|
|
switch (action.type) {
|
|
// Portal
|
|
case ActionTypes.RESET_STATE:
|
|
return INITIAL_STATE;
|
|
|
|
case ActionTypes.UPDATE_ORDER_SALT: {
|
|
return _.assign({}, state, {
|
|
orderSalt: action.data,
|
|
});
|
|
}
|
|
|
|
case ActionTypes.UPDATE_NODE_VERSION: {
|
|
return _.assign({}, state, {
|
|
nodeVersion: action.data,
|
|
});
|
|
}
|
|
|
|
case ActionTypes.UPDATE_ORDER_FILL_AMOUNT: {
|
|
return _.assign({}, state, {
|
|
orderFillAmount: action.data,
|
|
});
|
|
}
|
|
|
|
case ActionTypes.UPDATE_SHOULD_BLOCKCHAIN_ERR_DIALOG_BE_OPEN: {
|
|
return _.assign({}, state, {
|
|
shouldBlockchainErrDialogBeOpen: action.data,
|
|
});
|
|
}
|
|
|
|
case ActionTypes.UPDATE_USER_ETHER_BALANCE: {
|
|
return _.assign({}, state, {
|
|
userEtherBalance: action.data,
|
|
});
|
|
}
|
|
|
|
case ActionTypes.UPDATE_USER_SUPPLIED_ORDER_CACHE: {
|
|
return _.assign({}, state, {
|
|
userSuppliedOrderCache: action.data,
|
|
});
|
|
}
|
|
|
|
case ActionTypes.CLEAR_TOKEN_BY_ADDRESS: {
|
|
return _.assign({}, state, {
|
|
tokenByAddress: {},
|
|
});
|
|
}
|
|
|
|
case ActionTypes.ADD_TOKEN_TO_TOKEN_BY_ADDRESS: {
|
|
const newTokenByAddress = state.tokenByAddress;
|
|
newTokenByAddress[action.data.address] = action.data;
|
|
return _.assign({}, state, {
|
|
tokenByAddress: newTokenByAddress,
|
|
});
|
|
}
|
|
|
|
case ActionTypes.REMOVE_TOKEN_TO_TOKEN_BY_ADDRESS: {
|
|
const newTokenByAddress = state.tokenByAddress;
|
|
delete newTokenByAddress[action.data.address];
|
|
return _.assign({}, state, {
|
|
tokenByAddress: newTokenByAddress,
|
|
});
|
|
}
|
|
|
|
case ActionTypes.UPDATE_TOKEN_BY_ADDRESS: {
|
|
const tokenByAddress = state.tokenByAddress;
|
|
const tokens = action.data;
|
|
_.each(tokens, token => {
|
|
const updatedToken = _.assign({}, tokenByAddress[token.address], token);
|
|
tokenByAddress[token.address] = updatedToken;
|
|
});
|
|
return _.assign({}, state, {
|
|
tokenByAddress,
|
|
});
|
|
}
|
|
|
|
case ActionTypes.UPDATE_TOKEN_STATE_BY_ADDRESS: {
|
|
const tokenStateByAddress = state.tokenStateByAddress;
|
|
const updatedTokenStateByAddress = action.data;
|
|
_.each(updatedTokenStateByAddress, (tokenState: TokenState, address: string) => {
|
|
const updatedTokenState = _.assign({}, tokenStateByAddress[address], tokenState);
|
|
tokenStateByAddress[address] = updatedTokenState;
|
|
});
|
|
return _.assign({}, state, {
|
|
tokenStateByAddress,
|
|
});
|
|
}
|
|
|
|
case ActionTypes.REMOVE_FROM_TOKEN_STATE_BY_ADDRESS: {
|
|
const tokenStateByAddress = state.tokenStateByAddress;
|
|
const tokenAddress = action.data;
|
|
delete tokenStateByAddress[tokenAddress];
|
|
return _.assign({}, state, {
|
|
tokenStateByAddress,
|
|
});
|
|
}
|
|
|
|
case ActionTypes.REPLACE_TOKEN_ALLOWANCE_BY_ADDRESS: {
|
|
const tokenStateByAddress = state.tokenStateByAddress;
|
|
const allowance = action.data.allowance;
|
|
const tokenAddress = action.data.address;
|
|
tokenStateByAddress[tokenAddress] = _.assign({}, tokenStateByAddress[tokenAddress], {
|
|
allowance,
|
|
});
|
|
return _.assign({}, state, {
|
|
tokenStateByAddress,
|
|
});
|
|
}
|
|
|
|
case ActionTypes.REPLACE_TOKEN_BALANCE_BY_ADDRESS: {
|
|
const tokenStateByAddress = state.tokenStateByAddress;
|
|
const balance = action.data.balance;
|
|
const tokenAddress = action.data.address;
|
|
tokenStateByAddress[tokenAddress] = _.assign({}, tokenStateByAddress[tokenAddress], {
|
|
balance,
|
|
});
|
|
return _.assign({}, state, {
|
|
tokenStateByAddress,
|
|
});
|
|
}
|
|
|
|
case ActionTypes.UPDATE_TOKEN_BALANCE_BY_ADDRESS: {
|
|
const tokenStateByAddress = state.tokenStateByAddress;
|
|
const balanceDelta = action.data.balanceDelta;
|
|
const tokenAddress = action.data.address;
|
|
const currBalance = tokenStateByAddress[tokenAddress].balance;
|
|
tokenStateByAddress[tokenAddress] = _.assign({}, tokenStateByAddress[tokenAddress], {
|
|
balance: currBalance.plus(balanceDelta),
|
|
});
|
|
return _.assign({}, state, {
|
|
tokenStateByAddress,
|
|
});
|
|
}
|
|
|
|
case ActionTypes.UPDATE_ORDER_SIGNATURE_DATA: {
|
|
return _.assign({}, state, {
|
|
orderSignatureData: action.data,
|
|
});
|
|
}
|
|
|
|
case ActionTypes.UPDATE_SCREEN_WIDTH: {
|
|
return _.assign({}, state, {
|
|
screenWidth: action.data,
|
|
});
|
|
}
|
|
|
|
case ActionTypes.UPDATE_BLOCKCHAIN_IS_LOADED: {
|
|
return _.assign({}, state, {
|
|
blockchainIsLoaded: action.data,
|
|
});
|
|
}
|
|
|
|
case ActionTypes.BLOCKCHAIN_ERR_ENCOUNTERED: {
|
|
return _.assign({}, state, {
|
|
blockchainErr: action.data,
|
|
});
|
|
}
|
|
|
|
case ActionTypes.UPDATE_NETWORK_ID: {
|
|
return _.assign({}, state, {
|
|
networkId: action.data,
|
|
});
|
|
}
|
|
|
|
case ActionTypes.UPDATE_GENERATE_ORDER_STEP: {
|
|
const direction = action.data;
|
|
let nextGenerateOrderStep = state.generateOrderStep;
|
|
if (direction === Direction.forward) {
|
|
nextGenerateOrderStep += 1;
|
|
} else if (state.generateOrderStep !== 0) {
|
|
nextGenerateOrderStep -= 1;
|
|
}
|
|
return _.assign({}, state, {
|
|
generateOrderStep: nextGenerateOrderStep,
|
|
});
|
|
}
|
|
|
|
case ActionTypes.UPDATE_CHOSEN_ASSET_TOKEN: {
|
|
const newSideToAssetToken = _.assign({}, state.sideToAssetToken, {
|
|
[action.data.side]: action.data.token,
|
|
});
|
|
return _.assign({}, state, {
|
|
sideToAssetToken: newSideToAssetToken,
|
|
});
|
|
}
|
|
|
|
case ActionTypes.UPDATE_CHOSEN_ASSET_TOKEN_ADDRESS: {
|
|
const newAssetToken = state.sideToAssetToken[action.data.side];
|
|
newAssetToken.address = action.data.address;
|
|
const newSideToAssetToken = _.assign({}, state.sideToAssetToken, {
|
|
[action.data.side]: newAssetToken,
|
|
});
|
|
return _.assign({}, state, {
|
|
sideToAssetToken: newSideToAssetToken,
|
|
});
|
|
}
|
|
|
|
case ActionTypes.SWAP_ASSET_TOKENS: {
|
|
const newSideToAssetToken = _.assign({}, state.sideToAssetToken, {
|
|
[Side.deposit]: state.sideToAssetToken[Side.receive],
|
|
[Side.receive]: state.sideToAssetToken[Side.deposit],
|
|
});
|
|
return _.assign({}, state, {
|
|
sideToAssetToken: newSideToAssetToken,
|
|
});
|
|
}
|
|
|
|
case ActionTypes.UPDATE_ORDER_EXPIRY: {
|
|
return _.assign({}, state, {
|
|
orderExpiryTimestamp: action.data,
|
|
});
|
|
}
|
|
|
|
case ActionTypes.UPDATE_ORDER_TAKER_ADDRESS: {
|
|
return _.assign({}, state, {
|
|
orderTakerAddress: action.data,
|
|
});
|
|
}
|
|
|
|
case ActionTypes.UPDATE_USER_ADDRESS: {
|
|
return _.assign({}, state, {
|
|
userAddress: action.data,
|
|
});
|
|
}
|
|
|
|
// Docs
|
|
case ActionTypes.UPDATE_LIBRARY_VERSION: {
|
|
return _.assign({}, state, {
|
|
docsVersion: action.data,
|
|
});
|
|
}
|
|
case ActionTypes.UPDATE_AVAILABLE_LIBRARY_VERSIONS: {
|
|
return _.assign({}, state, {
|
|
availableDocVersions: action.data,
|
|
});
|
|
}
|
|
|
|
// Shared
|
|
case ActionTypes.SHOW_FLASH_MESSAGE: {
|
|
return _.assign({}, state, {
|
|
flashMessage: action.data,
|
|
});
|
|
}
|
|
|
|
case ActionTypes.HIDE_FLASH_MESSAGE: {
|
|
return _.assign({}, state, {
|
|
flashMessage: undefined,
|
|
});
|
|
}
|
|
|
|
case ActionTypes.UPDATE_PROVIDER_TYPE: {
|
|
return _.assign({}, state, {
|
|
providerType: action.data,
|
|
});
|
|
}
|
|
|
|
case ActionTypes.UPDATE_INJECTED_PROVIDER_NAME: {
|
|
return _.assign({}, state, {
|
|
injectedProviderName: action.data,
|
|
});
|
|
}
|
|
|
|
default:
|
|
return state;
|
|
}
|
|
}
|