From eb3b87262d315f56bef12ddd58e3f856e0476401 Mon Sep 17 00:00:00 2001 From: Abraham Elmahrek Date: Wed, 15 May 2019 15:16:30 -0400 Subject: [PATCH] #228: Bitski integration --- App/NavigationProvider.js | 5 + App/components/AddressText.js | 2 +- App/components/FormattedForexAmount.js | 2 +- App/components/FormattedPercent.js | 2 +- App/components/FormattedSymbol.js | 2 +- App/components/FormattedTokenAmount.js | 2 +- App/components/PriceGraph.js | 2 +- App/components/TokenAmount.js | 2 +- App/components/TokenIcon.js | 2 +- App/components/UnlockButton.js | 2 +- .../OneButtonTokenAmountKeyboardLayout.js | 2 +- App/layouts/PinKeyboardLayout.js | 2 +- .../TwoButtonTokenAmountKeyboardLayout.js | 2 +- App/modals/ActionModal/base.js | 11 +- App/modals/PreviewOrderModal/FillOrders.js | 18 +- App/modals/PreviewOrderModal/LimitOrder.js | 8 +- App/modals/SendModal/AccountPage.js | 2 +- App/modals/SendModal/AmountPage.js | 16 +- App/modals/SendModal/base.js | 12 +- App/modals/UnlockAndSignModal/Unlocking.js | 6 +- App/modals/UnlockAndSignModal/base.js | 6 +- App/modals/WrapEtherModal/base.js | 21 +- App/screens/SettingsScreen.js | 28 +- App/screens/onboarding/BitskiLogin/base.js | 95 +++ App/screens/onboarding/BitskiLogin/index.js | 22 + .../onboarding/ImportMnemonicScreen/base.js | 5 +- App/screens/onboarding/IntroScreen/base.js | 13 +- App/screens/onboarding/PinScreen/base.js | 14 +- .../AdaptTransactionItem.js | 2 +- .../TransactionHistoryScreen/FilledItem.js | 2 +- .../TransactionItem.js | 2 +- .../trade/CreateOrderScreen/FillOrders.js | 2 +- .../trade/CreateOrderScreen/LimitOrder.js | 2 +- .../ForexProductDetailsView.js | 2 +- .../ProductDetailsView.js | 8 +- .../TokenProductDetailsView.js | 2 +- .../wallet/AccountsScreen/PortfolioDetails.js | 6 +- .../wallet/AccountsScreen/TokenDetails.js | 8 +- App/views/ForexBalanceByAssetData.js | 6 +- App/views/ForexPriceGraph.js | 2 +- App/views/LogoTicker.js | 2 +- App/views/Receipt/index.js | 6 +- App/views/TokenBalanceByAssetData.js | 6 +- App/views/TokenBalanceBySymbol.js | 6 +- App/views/TokenLockByAssetData.js | 6 +- App/views/TokenPriceGraph.js | 2 +- README.md | 59 +- actions/index.js | 3 + android/app/build.gradle | 4 + .../java/io/mobidex/WalletManagerModule.java | 34 +- android/settings.gradle | 2 + clients/0x.js | 2 +- clients/token.js | 2 +- constants/actions.js | 1 + index.js | 5 +- ios/BitskiManager.swift | 135 ++++ ios/BitskiManagerBridge.m | 23 + ios/Podfile | 4 +- ios/Podfile.lock | 39 +- ios/WalletManager.swift | 17 + ios/WalletManagerBridge.m | 2 + ios/Web3+Sign.swift | 34 + ios/mobidex.xcodeproj/project.pbxproj | 97 ++- ios/mobidex/AppDelegate.h | 4 +- ios/mobidex/AppDelegate.m | 4 + ios/mobidex/Info.plist | 13 +- lib/middleware/app.js | 9 + lib/stores/app.js | 77 +++ lib/stores/bitski.js | 34 + {utils => lib/utils}/cache.js | 0 {utils => lib/utils}/crypto.js | 0 lib/utils/display.js | 627 ++++++++++++++++++ {utils => lib/utils}/ethereum.js | 10 + {utils => lib/utils}/index.js | 1 + lib/utils/orders.js | 336 ++++++++++ lib/wallets/bitski.js | 158 +++++ lib/wallets/integrated.js | 185 ++++++ navigation/screens.js | 8 + package-lock.json | 5 + package.json | 1 + reducers/bitski.js | 20 + reducers/index.js | 2 + reducers/relayer.js | 4 +- reducers/settings.js | 11 +- services/NavigationService.js | 4 +- services/OrderService.js | 14 +- services/TransactionService.js | 6 +- services/WalletService.js | 547 +++++++-------- store.js | 84 +-- thunks/0x.js | 16 +- thunks/bitski.js | 45 ++ thunks/index.js | 1 + thunks/orders.js | 8 +- thunks/settings.js | 4 +- thunks/wallet.js | 24 +- utils/display.js | 627 ------------------ utils/orders.js | 336 ---------- 97 files changed, 2518 insertions(+), 1548 deletions(-) create mode 100644 App/screens/onboarding/BitskiLogin/base.js create mode 100644 App/screens/onboarding/BitskiLogin/index.js create mode 100644 ios/BitskiManager.swift create mode 100644 ios/BitskiManagerBridge.m create mode 100644 ios/Web3+Sign.swift create mode 100644 lib/middleware/app.js create mode 100644 lib/stores/app.js create mode 100644 lib/stores/bitski.js rename {utils => lib/utils}/cache.js (100%) rename {utils => lib/utils}/crypto.js (100%) create mode 100644 lib/utils/display.js rename {utils => lib/utils}/ethereum.js (76%) rename {utils => lib/utils}/index.js (83%) create mode 100644 lib/wallets/bitski.js create mode 100644 lib/wallets/integrated.js create mode 100644 reducers/bitski.js create mode 100644 thunks/bitski.js delete mode 100644 utils/display.js delete mode 100644 utils/orders.js diff --git a/App/NavigationProvider.js b/App/NavigationProvider.js index cea56c5..3e9195c 100644 --- a/App/NavigationProvider.js +++ b/App/NavigationProvider.js @@ -25,6 +25,7 @@ export default class NavigationProvider extends React.Component { componentId: this.props.componentId, push: this.push, pop: this.pop, + popToRoot: this.popToRoot, showModal: showModal, showErrorModal: showErrorModal, dismissModal: this.dismissModal, @@ -47,6 +48,10 @@ export default class NavigationProvider extends React.Component { Navigation.pop(this.props.componentId); }; + popToRoot = () => { + Navigation.popToRoot(this.props.componentId); + }; + dismissModal = () => { Navigation.dismissModal(this.props.componentId); }; diff --git a/App/components/AddressText.js b/App/components/AddressText.js index 9b5feff..fc5508c 100644 --- a/App/components/AddressText.js +++ b/App/components/AddressText.js @@ -2,7 +2,7 @@ import ethUtil from 'ethereumjs-util'; import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { Text } from 'react-native-elements'; -import { summarizeAddress } from '../../utils'; +import { summarizeAddress } from '../../lib/utils'; export default class AddressText extends Component { render() { diff --git a/App/components/FormattedForexAmount.js b/App/components/FormattedForexAmount.js index 8603d19..3d6e1cb 100644 --- a/App/components/FormattedForexAmount.js +++ b/App/components/FormattedForexAmount.js @@ -2,7 +2,7 @@ import { BigNumber } from '0x.js'; import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { Text } from 'react-native-elements'; -import { formatMoney } from '../../utils'; +import { formatMoney } from '../../lib/utils'; export default class FormattedForexAmount extends Component { static get propTypes() { diff --git a/App/components/FormattedPercent.js b/App/components/FormattedPercent.js index c087c57..476c403 100644 --- a/App/components/FormattedPercent.js +++ b/App/components/FormattedPercent.js @@ -2,7 +2,7 @@ import { BigNumber } from '0x.js'; import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { Text } from 'react-native-elements'; -import { formatPercent } from '../../utils'; +import { formatPercent } from '../../lib/utils'; export default class FormattedPercent extends Component { static get propTypes() { diff --git a/App/components/FormattedSymbol.js b/App/components/FormattedSymbol.js index df973d2..dc1d19b 100644 --- a/App/components/FormattedSymbol.js +++ b/App/components/FormattedSymbol.js @@ -1,7 +1,7 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { Text } from 'react-native-elements'; -import { formatSymbol } from '../../utils'; +import { formatSymbol } from '../../lib/utils'; export default class FormattedSymbol extends Component { static get propTypes() { diff --git a/App/components/FormattedTokenAmount.js b/App/components/FormattedTokenAmount.js index ec20645..769ee2d 100644 --- a/App/components/FormattedTokenAmount.js +++ b/App/components/FormattedTokenAmount.js @@ -4,7 +4,7 @@ import React from 'react'; import { Text } from 'react-native-elements'; import * as AssetService from '../../services/AssetService'; import { styles } from '../../styles'; -import { formatAmount, formatAmountWithDecimals } from '../../utils'; +import { formatAmount, formatAmountWithDecimals } from '../../lib/utils'; import FormattedSymbol from './FormattedSymbol'; export default class FormattedTokenAmount extends React.PureComponent { diff --git a/App/components/PriceGraph.js b/App/components/PriceGraph.js index cac4802..be376ec 100644 --- a/App/components/PriceGraph.js +++ b/App/components/PriceGraph.js @@ -6,7 +6,7 @@ import { G, Line, Text as SVGText } from 'react-native-svg'; import { AreaChart } from 'react-native-svg-charts'; import { colors, styles } from '../../styles'; import { styleProp } from '../../types/props/styles'; -import { colorWithAlpha } from '../../utils'; +import { colorWithAlpha } from '../../lib/utils'; import MutedText from './MutedText'; import Tabs from './Tabs'; diff --git a/App/components/TokenAmount.js b/App/components/TokenAmount.js index 9764961..52ea33f 100644 --- a/App/components/TokenAmount.js +++ b/App/components/TokenAmount.js @@ -2,7 +2,7 @@ import PropTypes from 'prop-types'; import React, { Component, Fragment } from 'react'; import { StyleSheet, View } from 'react-native'; import { Avatar, Text } from 'react-native-elements'; -import { formatAmount, formatSymbol, getImage } from '../../utils'; +import { formatAmount, formatSymbol, getImage } from '../../lib/utils'; import FormattedSymbol from './FormattedSymbol'; import MutedText from './MutedText'; import BlinkingCursor from './BlinkingCursor'; diff --git a/App/components/TokenIcon.js b/App/components/TokenIcon.js index 568c76b..17d1aa9 100644 --- a/App/components/TokenIcon.js +++ b/App/components/TokenIcon.js @@ -4,7 +4,7 @@ import { View } from 'react-native'; import { Avatar, Text } from 'react-native-elements'; import * as AssetService from '../../services/AssetService'; import { fonts, images, styles } from '../../styles'; -import { getImage } from '../../utils'; +import { getImage } from '../../lib/utils'; export default class TokenIcon extends Component { render() { diff --git a/App/components/UnlockButton.js b/App/components/UnlockButton.js index 6348b1b..fcea976 100644 --- a/App/components/UnlockButton.js +++ b/App/components/UnlockButton.js @@ -6,7 +6,7 @@ import { connect as connectNavigation } from '../../navigation'; import * as AssetService from '../../services/AssetService'; import { approve } from '../../thunks'; import { navigationProp } from '../../types/props'; -import { formatSymbol } from '../../utils'; +import { formatSymbol } from '../../lib/utils'; import Button from './Button'; class UnlockButton extends React.Component { diff --git a/App/layouts/OneButtonTokenAmountKeyboardLayout.js b/App/layouts/OneButtonTokenAmountKeyboardLayout.js index 0417299..f6ed612 100644 --- a/App/layouts/OneButtonTokenAmountKeyboardLayout.js +++ b/App/layouts/OneButtonTokenAmountKeyboardLayout.js @@ -2,7 +2,7 @@ import React, { PureComponent } from 'react'; import { SafeAreaView, ScrollView, View } from 'react-native'; import VirtualKeyboard from 'react-native-virtual-keyboard'; import { styles } from '../../styles'; -import { processVirtualKeyboardCharacter } from '../../utils'; +import { processVirtualKeyboardCharacter } from '../../lib/utils'; import Button from '../components/Button'; export default class OneButtonTokenAmountKeyboardLayout extends PureComponent { diff --git a/App/layouts/PinKeyboardLayout.js b/App/layouts/PinKeyboardLayout.js index 1f579ec..aeaed4d 100644 --- a/App/layouts/PinKeyboardLayout.js +++ b/App/layouts/PinKeyboardLayout.js @@ -2,7 +2,7 @@ import React, { PureComponent } from 'react'; import { SafeAreaView, View } from 'react-native'; import VirtualKeyboard from 'react-native-virtual-keyboard'; import { styles } from '../../styles'; -import { processVirtualKeyboardCharacter } from '../../utils'; +import { processVirtualKeyboardCharacter } from '../../lib/utils'; import PinView from '../components/PinView'; export default class PinKeyboardLayout extends PureComponent { diff --git a/App/layouts/TwoButtonTokenAmountKeyboardLayout.js b/App/layouts/TwoButtonTokenAmountKeyboardLayout.js index 1c9a2a6..334161b 100644 --- a/App/layouts/TwoButtonTokenAmountKeyboardLayout.js +++ b/App/layouts/TwoButtonTokenAmountKeyboardLayout.js @@ -2,7 +2,7 @@ import React, { PureComponent } from 'react'; import { SafeAreaView, ScrollView, View } from 'react-native'; import VirtualKeyboard from 'react-native-virtual-keyboard'; import { styles } from '../../styles'; -import { processVirtualKeyboardCharacter } from '../../utils'; +import { processVirtualKeyboardCharacter } from '../../lib/utils'; import Button from '../components/Button'; import Row from '../components/Row'; diff --git a/App/modals/ActionModal/base.js b/App/modals/ActionModal/base.js index b1ba251..9dec7f5 100644 --- a/App/modals/ActionModal/base.js +++ b/App/modals/ActionModal/base.js @@ -1,7 +1,10 @@ import PropTypes from 'prop-types'; import React from 'react'; import { Text } from 'react-native-elements'; -import { connect as connectNavigation } from '../../../navigation'; +import { + connect as connectNavigation, + waitForComponentAppear +} from '../../../navigation'; import { navigationProp } from '../../../types/props'; import BigCenter from '../../components/BigCenter'; import VerticalPadding from '../../components/VerticalPadding'; @@ -23,8 +26,10 @@ class BaseActionModal extends React.PureComponent { try { await this.props.action(); } catch (err) { - this.props.navigation.dismissModal(); - this.props.callback(err); + waitForComponentAppear(this.props.navigation.componentId, () => { + this.props.navigation.dismissModal(); + this.props.callback(err); + }); return; } diff --git a/App/modals/PreviewOrderModal/FillOrders.js b/App/modals/PreviewOrderModal/FillOrders.js index f174f58..576bad4 100644 --- a/App/modals/PreviewOrderModal/FillOrders.js +++ b/App/modals/PreviewOrderModal/FillOrders.js @@ -10,7 +10,7 @@ import { ZERO } from '../../../constants/0x'; import { connect as connectNavigation } from '../../../navigation'; import * as AssetService from '../../../services/AssetService'; import * as OrderService from '../../../services/OrderService'; -import * as WalletService from '../../../services/WalletService'; +import { WalletService } from '../../../services/WalletService'; import * as ZeroExService from '../../../services/ZeroExService'; import { colors } from '../../../styles'; import { @@ -21,7 +21,7 @@ import { pruneOrders, refreshGasPrice } from '../../../thunks'; -import { formatAmount } from '../../../utils'; +import { formatAmount } from '../../../lib/utils'; import { navigationProp } from '../../../types/props'; import Button from '../../components/Button'; import FormattedTokenAmount from '../../components/FormattedTokenAmount'; @@ -87,16 +87,16 @@ class PreviewFillOrders extends Component { const { side, amount } = this.props; const relayerFeeAsset = AssetService.getFeeAsset(); const networkFeeAsset = AssetService.getNetworkFeeAsset(); - const etherBalance = WalletService.getBalanceByAssetData( + const etherBalance = WalletService.instance.getBalanceByAssetData( networkFeeAsset.assetData ); - const feeBalance = WalletService.getBalanceByAssetData( + const feeBalance = WalletService.instance.getBalanceByAssetData( relayerFeeAsset.assetData ); - const quoteBalance = WalletService.getBalanceByAssetData( + const quoteBalance = WalletService.instance.getBalanceByAssetData( this.props.quote.assetData ); - const baseBalance = WalletService.getBalanceByAssetData( + const baseBalance = WalletService.instance.getBalanceByAssetData( this.props.base.assetData ); const baseUnitAmount = Web3Wrapper.toBaseUnitAmount( @@ -246,7 +246,7 @@ class PreviewFillOrders extends Component { } // 6. Load gas price - const gasPrice = WalletService.convertGasPriceToEth( + const gasPrice = WalletService.instance.convertGasPriceToEth( await this.props.dispatch(refreshGasPrice()) ); @@ -291,11 +291,11 @@ class PreviewFillOrders extends Component { for (const asset of assets) { wallet[asset.address] = { symbol: asset.symbol, - amount: WalletService.getBalanceByAddress(asset.address) + amount: WalletService.instance.getBalanceByAddress(asset.address) }; walletAfterTransaction[asset.address] = { symbol: asset.symbol, - amount: WalletService.getBalanceByAddress(asset.address) + amount: WalletService.instance.getBalanceByAddress(asset.address) }; } diff --git a/App/modals/PreviewOrderModal/LimitOrder.js b/App/modals/PreviewOrderModal/LimitOrder.js index 8224793..32a91ca 100644 --- a/App/modals/PreviewOrderModal/LimitOrder.js +++ b/App/modals/PreviewOrderModal/LimitOrder.js @@ -11,14 +11,14 @@ import { configureOrder, convertZeroExOrderToLimitOrder } from '../../../services/OrderService'; -import * as WalletService from '../../../services/WalletService'; +import { WalletService } from '../../../services/WalletService'; import { colors } from '../../../styles'; import { ActionErrorSuccessFlow, refreshGasPrice, submitOrder } from '../../../thunks'; -import { formatAmount, formatTimestamp } from '../../../utils'; +import { formatAmount, formatTimestamp } from '../../../lib/utils'; import { navigationProp } from '../../../types/props'; import Button from '../../components/Button'; import Row from '../../components/Row'; @@ -98,11 +98,11 @@ class PreviewLimitOrder extends Component { for (const asset of assets) { wallet[asset.address] = { symbol: asset.symbol, - amount: WalletService.getBalanceByAddress(asset.address) + amount: WalletService.instance.getBalanceByAddress(asset.address) }; walletAfterTransaction[asset.address] = { symbol: asset.symbol, - amount: WalletService.getBalanceByAddress(asset.address) + amount: WalletService.instance.getBalanceByAddress(asset.address) }; } diff --git a/App/modals/SendModal/AccountPage.js b/App/modals/SendModal/AccountPage.js index b286299..f53fe7f 100644 --- a/App/modals/SendModal/AccountPage.js +++ b/App/modals/SendModal/AccountPage.js @@ -4,7 +4,7 @@ import React from 'react'; import { connect } from 'react-redux'; import Icon from 'react-native-vector-icons/FontAwesome'; import * as TickerService from '../../../services/TickerService'; -import { formatAmount, formatMoney } from '../../../utils'; +import { formatAmount, formatMoney } from '../../../lib/utils'; import AddressInput from '../../components/AddressInput'; import TwoColumnListItem from '../../components/TwoColumnListItem'; import ConfirmationView from '../../views/ConfirmationView'; diff --git a/App/modals/SendModal/AmountPage.js b/App/modals/SendModal/AmountPage.js index f33c9e7..203077d 100644 --- a/App/modals/SendModal/AmountPage.js +++ b/App/modals/SendModal/AmountPage.js @@ -4,10 +4,10 @@ import React from 'react'; import Entypo from 'react-native-vector-icons/Entypo'; import { connect } from 'react-redux'; import * as TickerService from '../../../services/TickerService'; -import * as WalletService from '../../../services/WalletService'; +import { WalletService } from '../../../services/WalletService'; import { styles } from '../../../styles'; import { refreshGasPrice } from '../../../thunks'; -import { formatAmount, getForexIcon, isValidAmount } from '../../../utils'; +import { formatAmount, getForexIcon, isValidAmount } from '../../../lib/utils'; import MaxButton from '../../components/MaxButton'; import Row from '../../components/Row'; import TokenAmount from '../../components/TokenAmount'; @@ -40,7 +40,7 @@ class AmountPage extends TwoButtonTokenAmountKeyboardLayout { renderTop() { const { asset } = this.props; - const balance = WalletService.getBalanceByAddress(asset.address); + const balance = WalletService.instance.getBalanceByAddress(asset.address); return ( @@ -176,12 +176,16 @@ class AmountPage extends TwoButtonTokenAmountKeyboardLayout { setMaxTokenAmount = async () => { const { asset } = this.props; - const balance = WalletService.getBalanceByAddress(asset.address || null); + const balance = WalletService.instance.getBalanceByAddress( + asset.address || null + ); let amount = balance; if (!asset.address) { - const gasAmount = await WalletService.estimateEthSend(); - const gasPrice = WalletService.convertGasPriceToEth(this.props.gasPrice); + const gasAmount = await WalletService.instance.estimateEthSend(); + const gasPrice = WalletService.instance.convertGasPriceToEth( + this.props.gasPrice + ); const gasFee = gasPrice.mul(gasAmount); amount = amount.sub(gasFee); diff --git a/App/modals/SendModal/base.js b/App/modals/SendModal/base.js index 586032c..a22394e 100644 --- a/App/modals/SendModal/base.js +++ b/App/modals/SendModal/base.js @@ -6,14 +6,14 @@ import FontAwesome from 'react-native-vector-icons/FontAwesome'; import { connect } from 'react-redux'; import { ZERO } from '../../../constants/0x'; import { connect as connectNavigation } from '../../../navigation'; -import * as WalletService from '../../../services/WalletService'; +import { WalletService } from '../../../services/WalletService'; import { ReceiptActionErrorSuccessFlow, sendEther, sendTokens } from '../../../thunks'; import { navigationProp } from '../../../types/props'; -import { formatAmount } from '../../../utils'; +import { formatAmount } from '../../../lib/utils'; import AmountPage from './AmountPage'; import AccountPage from './AccountPage'; @@ -149,7 +149,7 @@ class BaseSendScreen extends Component { const extraWalletData = []; const extraUpdatedWalletData = []; const extraSections = []; - const gas = await WalletService.estimateEthSend(); + const gas = await WalletService.instance.estimateEthSend(); const action = () => this.props.dispatch(sendEther(to, amount)); const value = baseUnitAmount; @@ -168,7 +168,9 @@ class BaseSendScreen extends Component { const { asset } = this.props; const { amount } = this.state; const baseUnitAmount = Web3Wrapper.toBaseUnitAmount(amount, asset.decimals); - const balance = await WalletService.getBalanceByAssetData(asset.assetData); + const balance = await WalletService.instance.getBalanceByAssetData( + asset.assetData + ); const to = address || this.state.address; const extraWalletData = [ @@ -196,7 +198,7 @@ class BaseSendScreen extends Component { ] } ]; - const gas = await WalletService.estimateTokenSend( + const gas = await WalletService.instance.estimateTokenSend( asset.address, to, baseUnitAmount diff --git a/App/modals/UnlockAndSignModal/Unlocking.js b/App/modals/UnlockAndSignModal/Unlocking.js index 7f9cc15..b06fb9c 100644 --- a/App/modals/UnlockAndSignModal/Unlocking.js +++ b/App/modals/UnlockAndSignModal/Unlocking.js @@ -4,7 +4,7 @@ import { Text } from 'react-native-elements'; import FontAwesome from 'react-native-vector-icons/FontAwesome'; import MaterialIcon from 'react-native-vector-icons/MaterialIcons'; import { connect as connectNavigation } from '../../../navigation'; -import * as WalletService from '../../../services/WalletService'; +import { WalletService } from '../../../services/WalletService'; import { colors } from '../../../styles'; import { navigationProp } from '../../../types/props'; import BigCenter from '../../components/BigCenter'; @@ -30,12 +30,12 @@ class Unlocking extends Component { try { if (tx) { - data = await WalletService.signTransaction( + data = await WalletService.instance.signTransaction( tx, pin ? pin.slice(0, 6) : null ); } else if (message) { - data = await WalletService.signMessage( + data = await WalletService.instance.signMessage( message, pin ? pin.slice(0, 6) : null ); diff --git a/App/modals/UnlockAndSignModal/base.js b/App/modals/UnlockAndSignModal/base.js index f2d0f06..0ce06cc 100644 --- a/App/modals/UnlockAndSignModal/base.js +++ b/App/modals/UnlockAndSignModal/base.js @@ -1,7 +1,7 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { connect as connectNavigation } from '../../../navigation'; -import * as WalletService from '../../../services/WalletService'; +import { WalletService } from '../../../services/WalletService'; import { navigationProp } from '../../../types/props'; import Loading from '../../views/Loading'; import UnlockWithTouchIdentification from './UnlockWithTouchIdentification'; @@ -38,8 +38,8 @@ class UnlockAndSignModal extends Component { return this.props.navigation.dismissModal(); } - const supportsFingerPrint = await WalletService.supportsFingerPrintUnlock(); - const supportsFaceID = await WalletService.supportsFaceIDUnlock(); + const supportsFingerPrint = await WalletService.instance.supportsFingerPrintUnlock(); + const supportsFaceID = await WalletService.instance.supportsFaceIDUnlock(); if (supportsFingerPrint && !this.forceShowPin) { this.showTouchIdentification(); } else if (supportsFaceID && !this.forceShowPin) { diff --git a/App/modals/WrapEtherModal/base.js b/App/modals/WrapEtherModal/base.js index 711bbb8..06e75e1 100644 --- a/App/modals/WrapEtherModal/base.js +++ b/App/modals/WrapEtherModal/base.js @@ -7,7 +7,7 @@ import { connect } from 'react-redux'; import Entypo from 'react-native-vector-icons/Entypo'; import FontAwesome from 'react-native-vector-icons/FontAwesome'; import { formatUnitValue } from '../../../lib/utils/format'; -import * as WalletService from '../../../services/WalletService'; +import { WalletService } from '../../../services/WalletService'; import { connect as connectNavigation } from '../../../navigation'; import { styles } from '../../../styles'; import { @@ -21,7 +21,7 @@ import { isDecimalOverflow, isValidAmount, reduceDecimalOverflow -} from '../../../utils'; +} from '../../../lib/utils'; import TokenAmount from '../../components/TokenAmount'; import TwoButtonTokenAmountKeyboardLayout from '../../layouts/TwoButtonTokenAmountKeyboardLayout'; @@ -45,7 +45,8 @@ class BaseWrapEtherScreen extends TwoButtonTokenAmountKeyboardLayout { componentDidMount() { this.setState({ - amount: WalletService.getBalanceBySymbol('WETH') + amount: WalletService.instance + .getBalanceBySymbol('WETH') .toString() .split('') }); @@ -127,14 +128,14 @@ class BaseWrapEtherScreen extends TwoButtonTokenAmountKeyboardLayout { amount = formatAmount(amount).toString(); } - const weth = WalletService.getBalanceBySymbol('WETH'); + const weth = WalletService.instance.getBalanceBySymbol('WETH'); if (weth.gt(amount || 0)) { this.props.dispatch( ReceiptActionErrorSuccessFlow( this.props.navigation.componentId, { - gas: await WalletService.estimateWithdraw( + gas: await WalletService.instance.estimateWithdraw( this.getWETHChange().neg() ), value: 0 @@ -153,7 +154,9 @@ class BaseWrapEtherScreen extends TwoButtonTokenAmountKeyboardLayout { ReceiptActionErrorSuccessFlow( this.props.navigation.componentId, { - gas: await WalletService.estimateDeposit(this.getWETHChange()), + gas: await WalletService.instance.estimateDeposit( + this.getWETHChange() + ), value: this.getWETHChange() }, { @@ -169,14 +172,14 @@ class BaseWrapEtherScreen extends TwoButtonTokenAmountKeyboardLayout { } getTotalEthereum() { - const eth = WalletService.getBalanceBySymbol('ETH'); - const weth = WalletService.getBalanceBySymbol('WETH'); + const eth = WalletService.instance.getBalanceBySymbol('ETH'); + const weth = WalletService.instance.getBalanceBySymbol('WETH'); return eth.add(weth); } getWETHChange() { const { amount } = this.state; - const weth = WalletService.getBalanceBySymbol('WETH'); + const weth = WalletService.instance.getBalanceBySymbol('WETH'); const formattedAmount = formatUnitValue( new BigNumber(amount.join('') || 0).sub(weth) ); diff --git a/App/screens/SettingsScreen.js b/App/screens/SettingsScreen.js index b93eedf..c349ce6 100644 --- a/App/screens/SettingsScreen.js +++ b/App/screens/SettingsScreen.js @@ -5,17 +5,17 @@ import { Clipboard, RefreshControl, SafeAreaView, - ScrollView, - TouchableOpacity + ScrollView } from 'react-native'; import { ListItem, Text } from 'react-native-elements'; import { connect } from 'react-redux'; import { setGasLevel, setGasStation } from '../../actions'; +import { WalletService } from '../../services/WalletService'; import { addReferrer, loadUser } from '../../thunks'; import { showModal } from '../../navigation'; -import { clearState } from '../../store'; +import { clearState } from '../../lib/stores/app'; import { colors, styles } from '../../styles'; -import { clearCache } from '../../utils'; +import { clearCache } from '../../lib/utils'; import Divider from '../components/Divider'; import MutedText from '../components/MutedText'; import ReferralCodeInput from '../components/ReferralCodeInput'; @@ -161,6 +161,19 @@ class SettingsScreen extends React.Component { subtitle={Tap Here} onPress={this.clearCache} /> + {WalletService.instance.selected == 'bitski' ? ( + Tap Here} + onPress={this.removeWallet} + /> + ) : ( + Tap Here} + onPress={this.removeWallet} + /> + )} ); @@ -180,6 +193,13 @@ class SettingsScreen extends React.Component { clearCache(); }; + removeWallet = () => { + clearState(); + clearCache(); + + WalletService.instance.removeWallet(); + }; + showGasStationSelect = () => { showModal('modals.Select', { title: 'Select Gas Station', diff --git a/App/screens/onboarding/BitskiLogin/base.js b/App/screens/onboarding/BitskiLogin/base.js new file mode 100644 index 0000000..78fd6ba --- /dev/null +++ b/App/screens/onboarding/BitskiLogin/base.js @@ -0,0 +1,95 @@ +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import { InteractionManager, SafeAreaView } from 'react-native'; +import RNRestart from 'react-native-restart'; +import { connect } from 'react-redux'; +import { styles } from '../../../../styles'; +import { connect as connectNavigation } from '../../../../navigation'; +import { WalletService } from '../../../../services/WalletService'; +import { navigationProp } from '../../../../types/props'; +import MutedText from '../../../components/MutedText'; + +class BaseBitskiLoginScreen extends Component { + static get propTypes() { + return { + dispatch: PropTypes.func.isRequired, + navigation: navigationProp.isRequired + }; + } + + constructor(props) { + super(props); + + this.state = { + authorizing: true, + authorized: false + }; + } + + async componentDidMount() { + try { + if (!WalletService.instance.wallets.bitski) { + throw new Error( + 'Bitski wallet is not available. Try restarting Mobidex.' + ); + } + + const authorized = await WalletService.instance.wallets.bitski.login(); + + this.setState({ authorizing: false, authorized }); + + this.props.navigation.waitForAppear(() => { + RNRestart.Restart(); + }); + } catch (error) { + InteractionManager.runAfterInteractions(() => { + this.props.navigation.pop(); + + InteractionManager.runAfterInteractions(() => { + this.props.navigation.showErrorModal(error); + }); + }); + } finally { + this.setState({ authorizing: false }); + } + } + + render() { + if (this.state.authorizing) { + return this.renderAuthorizing(); + } else if (this.state.authorized) { + return this.renderAuthorized(); + } else { + return this.renderUnauthorized(); + } + } + + renderAuthorized() { + return ( + + You have successfully logged in with Bitski. + + ); + } + + renderUnauthorized() { + return ( + + We were not able to authorize you with Bitski :(. + + ); + } + + renderAuthorizing() { + return ( + + Authorizing with Bitski. + + ); + } +} + +export default connect( + () => ({}), + dispatch => ({ dispatch }) +)(connectNavigation(BaseBitskiLoginScreen)); diff --git a/App/screens/onboarding/BitskiLogin/index.js b/App/screens/onboarding/BitskiLogin/index.js new file mode 100644 index 0000000..b96e0f7 --- /dev/null +++ b/App/screens/onboarding/BitskiLogin/index.js @@ -0,0 +1,22 @@ +import React from 'react'; +import NavigationProvider from '../../../NavigationProvider'; +import BaseBitskiLoginScreen from './base'; + +export default class BitskiLoginScreen extends React.Component { + static options() { + return { + topBar: { + visible: false, + drawBehind: true + } + }; + } + + render() { + return ( + + + + ); + } +} diff --git a/App/screens/onboarding/ImportMnemonicScreen/base.js b/App/screens/onboarding/ImportMnemonicScreen/base.js index dd88530..9a9c9fc 100644 --- a/App/screens/onboarding/ImportMnemonicScreen/base.js +++ b/App/screens/onboarding/ImportMnemonicScreen/base.js @@ -31,7 +31,7 @@ class BaseImportMnemonicScreen extends Component { static getDerivedStateFromProps(props, state) { const mnemonic = (props.mnemonic || []).slice(); const page = props.page || 0; - const word = mnemonic[page]; + const word = state.word || mnemonic[page]; return { ...state, @@ -107,7 +107,8 @@ class BaseImportMnemonicScreen extends Component { this.setState({ submitting: true }); const addMnemonic = ((await Clipboard.getString()) || '') .split(/\s+/) - .filter(word => Boolean(word)); + .filter(word => Boolean(word)) + .slice(0, 12); if (addMnemonic.length === 0) return; diff --git a/App/screens/onboarding/IntroScreen/base.js b/App/screens/onboarding/IntroScreen/base.js index d105b6d..10aa534 100644 --- a/App/screens/onboarding/IntroScreen/base.js +++ b/App/screens/onboarding/IntroScreen/base.js @@ -4,7 +4,7 @@ import { Text } from 'react-native-elements'; import { connect } from 'react-redux'; import { connect as connectNavigation } from '../../../../navigation'; import { navigationProp } from '../../../../types/props'; -import * as WalletService from '../../../../services/WalletService'; +import { WalletService } from '../../../../services/WalletService'; import { styles } from '../../../../styles'; import BigCenter from '../../../components/BigCenter'; import Button from '../../../components/Button'; @@ -52,6 +52,15 @@ class BaseIntro extends Component { this.props.navigation.push('navigation.onboarding.ImportMnemonic') } /> + {WalletService.instance.wallets.bitski.available ? ( +