Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: instapay global currency #992

Merged
merged 8 commits into from
Aug 15, 2019
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/components/UI/EthInput/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,7 @@ class EthInput extends PureComponent {
)}
</View>
<View style={[styles.actions]}>
{!paymentChannelTransaction && secondaryCurrency && (
{secondaryCurrency && (
<FontAwesome
onPress={() => this.switchInternalPrimaryCurrency(secondaryAmount)} // eslint-disable-line react/jsx-no-bind
name="exchange"
Expand Down
11 changes: 7 additions & 4 deletions app/components/Views/AssetCard/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ import { View, StyleSheet, Text, ImageBackground } from 'react-native';
import { colors, fontStyles } from '../../../styles/common';
import PropTypes from 'prop-types';
import ElevatedView from 'react-native-elevated-view';
import { strings } from '../../../../locales/i18n';

const styles = StyleSheet.create({
wrapper: {
backgroundColor: colors.white,
borderRadius: 8,
height: 200
minHeight: 200
},
contentWrapper: {
marginHorizontal: 30,
Expand All @@ -20,12 +21,14 @@ const styles = StyleSheet.create({
},
balance: {
...fontStyles.normal,
fontSize: 40
fontSize: 40,
textTransform: 'uppercase'
},
balanceFiat: {
...fontStyles.normal,
fontSize: 12,
color: colors.grey200
color: colors.grey200,
textTransform: 'uppercase'
},
description: {
...fontStyles.normal,
Expand Down Expand Up @@ -74,7 +77,7 @@ export default class AssetCard extends PureComponent {
imageStyle={styles.watermarkImage}
>
<View style={styles.contentWrapper}>
<Text style={styles.title}>Balance</Text>
<Text style={styles.title}>{strings('payment_request.balance')}</Text>
<Text style={styles.balance}>{balance}</Text>
<Text style={styles.balanceFiat}>{balanceFiat}</Text>
</View>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ exports[`PaymentChannelDeposit should render correctly 1`] = `
},
}
}
primaryCurrency="usd"
selectedAddress="0x1"
ticker="ETH"
/>
`;
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,23 @@ import { connect } from 'react-redux';
import { strings } from '../../../../../locales/i18n';
import Logger from '../../../../util/Logger';
import AppConstants from '../../../../core/AppConstants';
import { weiToFiat, toWei, isDecimal, isBN } from '../../../../util/number';
import {
weiToFiat,
toWei,
isDecimal,
weiToFiatNumber,
fiatNumberToWei,
renderFromWei,
fromWei
} from '../../../../util/number';
import { renderAccountName } from '../../../../util/address';
import Identicon from '../../../UI/Identicon';
import MaterialIcon from 'react-native-vector-icons/MaterialIcons';
import contractMap from 'eth-contract-metadata';
import AssetIcon from '../../../UI/AssetIcon';
import { hexToBN } from 'gaba/util';
import { toChecksumAddress } from 'ethereumjs-util';
import { getTicker } from '../../../../util/transactions';

const TOO_LOW = 'too_low';
const TOO_HIGH = 'too_high';
Expand Down Expand Up @@ -166,6 +175,9 @@ const styles = StyleSheet.create({
textAlign: 'center',
fontSize: 12,
...fontStyles.normal
},
secondaryValues: {
flexDirection: 'row'
}
});

Expand Down Expand Up @@ -198,14 +210,23 @@ class Deposit extends PureComponent {
/**
/* Identities object required to get account name
*/
identities: PropTypes.object
identities: PropTypes.object,
/**
* Current provider ticker
*/
ticker: PropTypes.string,
/**
* Primary currency, either ETH or Fiat
*/
primaryCurrency: PropTypes.string
};

state = {
amount: undefined,
validAmount: false,
depositing: undefined,
invalidAmountType: undefined
invalidAmountType: undefined,
value: undefined
};

amountInput = React.createRef();
Expand All @@ -227,7 +248,7 @@ class Deposit extends PureComponent {
return;
}
try {
const params = { depositAmount: this.state.amount.replace(',', '.') };
const params = { depositAmount: fromWei(this.state.value) };
Logger.log('About to deposit', params);
this.setState({ depositing: true });
await PaymentChannelsClient.deposit(params);
Expand All @@ -246,20 +267,30 @@ class Deposit extends PureComponent {
};

updateAmount = async amount => {
await this.setState({ amount });
const { conversionRate, primaryCurrency } = this.props;
let processedValue;
const pointAmount = amount.replace(',', '.');
const validDecimal = isDecimal(pointAmount);
if (validDecimal) {
if (primaryCurrency === 'ETH') {
processedValue = toWei(pointAmount);
} else {
processedValue = fiatNumberToWei(pointAmount, conversionRate);
}
}
await this.setState({ amount, value: processedValue });
this.validateDeposit();
};

validateDeposit = async () => {
const { selectedAddress, accounts } = this.props;
let { amount } = this.state;
const { value, amount } = this.state;
if (!amount) return;
amount = amount.replace(',', '.');
const { balance } = accounts[selectedAddress];
let error, invalidAmountType;
let validAmount = true;
if (isDecimal(amount) && isBN(toWei(amount))) {
if (hexToBN(balance).lt(toWei(amount))) {
if (isDecimal(amount.replace(',', '.'))) {
if (hexToBN(balance).lt(value)) {
validAmount = false;
error = strings('transaction.insufficient');
}
Expand All @@ -268,7 +299,7 @@ class Deposit extends PureComponent {
error = strings('transaction.invalid_amount');
}

const depositAmountNumber = parseFloat(amount);
const depositAmountNumber = parseFloat(fromWei(value));
const { MAX_DEPOSIT_TOKEN, getExchangeRate } = PaymentChannelsClient;

const ETH = parseFloat(getExchangeRate());
Expand All @@ -280,7 +311,7 @@ class Deposit extends PureComponent {
invalidAmountType = TOO_HIGH;
}

if (amount < minDepositAmount) {
if (depositAmountNumber < minDepositAmount) {
validAmount = false;
invalidAmountType = TOO_LOW;
}
Expand Down Expand Up @@ -359,14 +390,18 @@ class Deposit extends PureComponent {
}

render() {
const { conversionRate, currentCurrency } = this.props;
const { amount, validAmount, error } = this.state;
const decimalAmount = amount && amount.replace(',', '.');
const conversionAmount = weiToFiat(
toWei((isDecimal(decimalAmount) && decimalAmount) || 0),
conversionRate,
currentCurrency.toUpperCase()
);
const { conversionRate, currentCurrency, ticker, primaryCurrency } = this.props;
const { amount, validAmount, error, value } = this.state;
let secondaryAmount, currency, secondaryCurrency;
if (primaryCurrency === 'ETH') {
secondaryAmount = weiToFiatNumber(value, conversionRate).toString();
secondaryCurrency = currentCurrency.toUpperCase();
currency = getTicker(ticker);
} else {
secondaryAmount = renderFromWei(value);
secondaryCurrency = getTicker(ticker);
currency = currentCurrency.toUpperCase();
}
return (
<TouchableWithoutFeedback style={styles.root} onPress={Keyboard.dismiss}>
<View style={styles.root}>
Expand All @@ -389,10 +424,19 @@ class Deposit extends PureComponent {
onSubmitEditing={this.validateDeposit}
onBlur={this.promptValidationWarnings}
/>
<Text style={styles.inputCurrency}>{strings('unit.eth')}</Text>
<Text style={styles.inputCurrency}>{currency}</Text>
</View>

<Text style={styles.fiatValue}>{conversionAmount}</Text>
{secondaryAmount !== undefined && (
<View style={styles.secondaryValues}>
<Text style={styles.fiatValue} numberOfLines={1}>
{secondaryAmount}
</Text>
<Text style={styles.fiatValue} numberOfLines={1}>
{' ' + secondaryCurrency}
</Text>
</View>
)}
{this.renderMinimumsOrSpinner()}
{!!error && <Text style={styles.invalidAmountError}>{error}</Text>}

Expand Down Expand Up @@ -429,7 +473,9 @@ const mapStateToProps = state => ({
accounts: state.engine.backgroundState.AccountTrackerController.accounts,
currentCurrency: state.engine.backgroundState.CurrencyRateController.currentCurrency,
conversionRate: state.engine.backgroundState.CurrencyRateController.conversionRate,
identities: state.engine.backgroundState.PreferencesController.identities
identities: state.engine.backgroundState.PreferencesController.identities,
ticker: state.engine.backgroundState.NetworkController.provider.ticker,
primaryCurrency: state.settings.primaryCurrency
});

export default connect(mapStateToProps)(Deposit);
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,17 @@ describe('PaymentChannelDeposit', () => {
PreferencesController: {
selectedAddress: '0x1',
identities: { '0x1': { name: 'Account 1' } }
},
NetworkController: {
provider: {
type: 'ropsten',
ticker: 'ETH'
}
}
}
},
settings: {
primaryCurrency: 'usd'
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { connect } from 'react-redux';
import { newTransaction } from '../../../../actions/transaction';
import PaymentChannelsClient from '../../../../core/PaymentChannelsClient';
import Logger from '../../../../util/Logger';
import { fromTokenMinimalUnit } from '../../../../util/number';

const EDIT = 'edit';

Expand Down Expand Up @@ -93,7 +94,7 @@ class PaymentChannelSend extends PureComponent {
try {
const params = {
sendRecipient: transaction.to,
sendAmount: transaction.readableValue.replace(',', '.')
sendAmount: fromTokenMinimalUnit(transaction.value, 18)
};

if (isNaN(params.sendAmount) || params.sendAmount.trim() === '') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ exports[`PaymentChannel should render correctly 1`] = `
paymentChannelsEnabled={true}
provider={
Object {
"ticker": "ETH",
"type": "ropsten",
}
}
Expand Down
29 changes: 23 additions & 6 deletions app/components/Views/PaymentChannel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import DefaultTabBar from 'react-native-scrollable-tab-view/DefaultTabBar';
import { connect } from 'react-redux';
import { strings } from '../../../../locales/i18n';
import Logger from '../../../util/Logger';
import { balanceToFiat, toBN } from '../../../util/number';
import { toBN, balanceToFiatNumber } from '../../../util/number';
import AssetCard from '../AssetCard';
import Engine from '../../../core/Engine';
import { toChecksumAddress } from 'ethereumjs-util';
Expand Down Expand Up @@ -244,7 +244,11 @@ class PaymentChannel extends PureComponent {
/**
/* Triggers global alert
*/
showAlert: PropTypes.func
showAlert: PropTypes.func,
/**
* Primary currency, either ETH or Fiat
*/
primaryCurrency: PropTypes.string
};

state = {
Expand Down Expand Up @@ -356,6 +360,9 @@ class PaymentChannel extends PureComponent {
) {
this.reinitialize();
}
if (prevProps.currentCurrency !== this.props.currentCurrency) {
this.getBalanceFiat(this.state.balance);
}
}

reinitialize = () => {
Expand Down Expand Up @@ -533,12 +540,20 @@ class PaymentChannel extends PureComponent {
const isDisabled = this.areButtonsDisabled();
const noFundsAndNoHistory = this.state.balance === '0.00' && !this.state.transactions.length;
const noFunds = this.state.balance === '0.00';
let mainBalance, secondaryBalance;
if (this.props.primaryCurrency === 'ETH') {
mainBalance = balance + ' ' + strings('unit.dai');
secondaryBalance = balanceFiat;
} else {
mainBalance = balanceFiat;
secondaryBalance = balance + ' ' + strings('unit.dai');
}
return (
<View style={styles.data}>
<View style={styles.assetCardWrapper}>
<AssetCard
balance={balance + ' ' + strings('unit.dai')}
balanceFiat={balanceFiat}
balance={mainBalance}
balanceFiat={secondaryBalance}
description={strings('payment_channel.asset_card_desc')}
/>
</View>
Expand Down Expand Up @@ -606,7 +621,8 @@ class PaymentChannel extends PureComponent {
}
}

const balanceFiat = exchangeRate && balanceToFiat(balance, conversionRate, exchangeRate, currentCurrency);
const balanceFiat =
exchangeRate && `${balanceToFiatNumber(balance, conversionRate, exchangeRate)} ${currentCurrency}`;
this.setState({ balanceFiat, exchangeRate });
};

Expand Down Expand Up @@ -782,7 +798,8 @@ const mapStateToProps = state => ({
transactions: state.engine.backgroundState.TransactionController.transactions,
internalTransactions: state.engine.backgroundState.TransactionController.internalTransactions,
provider: state.engine.backgroundState.NetworkController.provider,
paymentChannelsEnabled: state.settings.paymentChannelsEnabled
paymentChannelsEnabled: state.settings.paymentChannelsEnabled,
primaryCurrency: state.settings.primaryCurrency
});

const mapDispatchToProps = dispatch => ({
Expand Down
3 changes: 2 additions & 1 deletion app/components/Views/PaymentChannel/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ describe('PaymentChannel', () => {
backgroundState: {
NetworkController: {
provider: {
type: 'ropsten'
type: 'ropsten',
ticker: 'ETH'
}
},
TransactionController: {
Expand Down
3 changes: 2 additions & 1 deletion locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -827,7 +827,8 @@
"copy_to_clipboard": "Copy to Clipboard",
"qr_code": "QR Code",
"send_link": "Send Link",
"request_qr_code": "Payment Request QR Code"
"request_qr_code": "Payment Request QR Code",
"balance": "Balance"
},
"receive_request": {
"title": "Receive",
Expand Down
3 changes: 2 additions & 1 deletion locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -810,7 +810,8 @@
"copy_to_clipboard": "Copiar al Portapapeles",
"qr_code": "Código QR",
"send_link": "Enviar Enlace",
"request_qr_code": "Código QR de solicitud de pago"
"request_qr_code": "Código QR de solicitud de pago",
"balance": "Balance"
},
"receive_request": {
"title": "Recibir",
Expand Down