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/swaps quotes view #2060

Merged
merged 82 commits into from
Jan 21, 2021
Merged
Show file tree
Hide file tree
Changes from 51 commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
17ff273
Squashed commit of the following:
wachunei Nov 17, 2020
812383c
Disable flag
wachunei Nov 23, 2020
90c83c7
Remove console.log
wachunei Nov 23, 2020
4b8f053
Fix linting
wachunei Nov 23, 2020
55105bf
bump and getch quotes
estebanmino Nov 25, 2020
a6194f9
bump
estebanmino Nov 25, 2020
2d861d1
bump
estebanmino Nov 26, 2020
1dd566e
fetchingcorrectly
estebanmino Nov 26, 2020
bf047df
fetchQuotesfetchQuotes
estebanmino Nov 26, 2020
103cd51
Use SwapsController state
wachunei Nov 26, 2020
6b09c1e
merge
estebanmino Nov 26, 2020
08b25a2
Add initial generic error view
wachunei Nov 27, 2020
258535f
bumpcontroller
estebanmino Nov 27, 2020
405b470
Add swaps app utils
wachunei Nov 30, 2020
8664890
Add ratio and values from top quote
wachunei Dec 1, 2020
511bd94
bump
estebanmino Dec 2, 2020
7485db9
bump
estebanmino Dec 3, 2020
33d0c45
bump
estebanmino Dec 3, 2020
74b1241
effect
estebanmino Dec 3, 2020
7e9b41e
Add gas price
wachunei Dec 4, 2020
a36dd9e
Remove console.log
wachunei Dec 4, 2020
5fd6f15
Add quotes modal and i18n
wachunei Dec 4, 2020
4d3822f
tradefees
estebanmino Dec 10, 2020
fd0cbd9
bump
estebanmino Dec 10, 2020
a5949c9
tradefees
estebanmino Dec 10, 2020
62cc4d9
orderedtradesfees
estebanmino Dec 10, 2020
13c476f
bump
estebanmino Dec 10, 2020
433053a
bumpcontrolker
estebanmino Dec 11, 2020
7177108
merge
estebanmino Dec 11, 2020
87238c7
snaps
estebanmino Dec 11, 2020
04070b2
walletaddress
estebanmino Dec 13, 2020
c769675
bump
estebanmino Dec 13, 2020
025bbab
bump
estebanmino Dec 13, 2020
1f56ceb
quotevalues
estebanmino Dec 14, 2020
7bc81e5
Order quotes by overall quote value
wachunei Dec 14, 2020
34859d6
Add enable asset text row
wachunei Dec 14, 2020
8b1f057
bump
estebanmino Dec 15, 2020
f7a3820
bump
estebanmino Dec 15, 2020
17b579e
500
estebanmino Dec 15, 2020
44f1f0f
Swaps amount view: use max for tokens (#2052)
wachunei Dec 15, 2020
87e57cc
Add slider button component (#2046)
flamingyawn Dec 15, 2020
4d3712e
Add slider buttons and useBalance
wachunei Dec 15, 2020
2aebafc
detecting
estebanmino Dec 15, 2020
60bcd80
autohide
estebanmino Dec 15, 2020
e01a883
bump
estebanmino Dec 16, 2020
62f54cd
REVERTTHISVALIDATION
estebanmino Dec 16, 2020
130a081
Add Alert component (#2061)
wachunei Dec 15, 2020
0d3848d
Add balance alert to quotes view
wachunei Dec 16, 2020
8e1a316
fixsendto
estebanmino Dec 17, 2020
b36c1f8
networkfix
estebanmino Dec 17, 2020
0b33f32
Fix use max handler usecallback deps
wachunei Dec 27, 2020
c92680c
Add Slippage Slider Component (#2068)
tlip Jan 5, 2021
c1e434f
controllers
estebanmino Jan 5, 2021
e1444a2
circle
estebanmino Jan 5, 2021
2ea60ab
circlerevert
estebanmino Jan 5, 2021
e2b4250
9
estebanmino Jan 5, 2021
2970ec6
bumpcontrollers
estebanmino Jan 6, 2021
285322d
CURRENT_PROJECT_VERSION
estebanmino Jan 6, 2021
e8dafe0
Refactor slider button
wachunei Jan 12, 2021
654412d
Add visual feedback
wachunei Jan 12, 2021
3ff5a9c
Adjust token symbol text colors
wachunei Jan 12, 2021
d4d470d
Update ios/MetaMask.xcodeproj/project.pbxproj
estebanmino Jan 12, 2021
fa9876b
Update ios/MetaMask.xcodeproj/project.pbxproj
estebanmino Jan 12, 2021
3e4119a
Fix SliderButton infinite effect
wachunei Jan 12, 2021
fee85ef
Update ios/MetaMask.xcodeproj/project.pbxproj
estebanmino Jan 12, 2021
8a77664
Update ios/MetaMask.xcodeproj/project.pbxproj
estebanmino Jan 12, 2021
63262a9
gasprice
estebanmino Jan 13, 2021
7f4a72b
merge
estebanmino Jan 13, 2021
8730a10
561
estebanmino Jan 13, 2021
6df1ee4
Make onComplete optional
wachunei Jan 12, 2021
e319764
averagegas
estebanmino Jan 13, 2021
9b9067f
Merge branch 'feature/swaps-quotes-view' of github.com:MetaMask/metam…
estebanmino Jan 13, 2021
836f495
42
estebanmino Jan 13, 2021
27bb1bc
Add touchable ratio switcher
wachunei Jan 17, 2021
40afcaf
Add default 3% slippage constant
wachunei Jan 17, 2021
ac88c7e
Add fee variable to fee modal
wachunei Jan 17, 2021
b79c7e3
Add hitSlop area to modal close buttons
wachunei Jan 17, 2021
31b74f4
Add quotes overview string
wachunei Jan 17, 2021
30e5f40
Add error views styling
wachunei Jan 17, 2021
746140a
merge
estebanmino Jan 21, 2021
4d66436
merge
estebanmino Jan 21, 2021
03bbfa7
networkupdated
estebanmino Jan 21, 2021
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
81 changes: 81 additions & 0 deletions app/components/Base/Alert.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import React, { useMemo } from 'react';
import PropTypes from 'prop-types';
import { View, StyleSheet, TouchableOpacity } from 'react-native';
import { colors } from '../../styles/common';
import Text from './Text';

const styles = StyleSheet.create({
base: {
paddingHorizontal: 12,
paddingVertical: 12,
borderWidth: 1,
borderRadius: 4,
flexDirection: 'row'
},
baseSmall: {
paddingVertical: 8
},
info: {
backgroundColor: colors.blue100,
borderColor: colors.blue
},
warning: {
backgroundColor: colors.yellow100,
borderColor: colors.yellow
},
error: {
backgroundColor: colors.red000,
borderColor: colors.red
},
textInfo: { color: colors.blue },
textWarning: { color: colors.yellow700 },
textError: { color: colors.red },
textIconStyle: { marginRight: 12 },
iconWrapper: {
alignItems: 'center'
}
});

function getStyles(type) {
switch (type) {
case 'warning': {
return [styles.warning, styles.textWarning];
}
case 'error': {
return [styles.error, styles.textError];
}
case 'info':
default: {
return [styles.info, styles.textInfo];
}
}
}

function Alert({ type = 'info', small, renderIcon, style, onPress, children, ...props }) {
const [wrapperStyle, textStyle] = useMemo(() => getStyles(type), [type]);

const Wrapper = onPress ? TouchableOpacity : View;
return (
<Wrapper style={[styles.base, small && styles.baseSmall, wrapperStyle, style]} onPress={onPress} {...props}>
{renderIcon && typeof renderIcon === 'function' && <View style={styles.iconWrapper}>{renderIcon()}</View>}
{typeof children === 'function' ? (
children(textStyle)
) : (
<Text small={small} style={[textStyle, !!renderIcon && styles.textIconStyle]}>
{children}
</Text>
)}
</Wrapper>
);
}

Alert.propTypes = {
type: PropTypes.oneOf(['info', 'warning', 'error']),
style: PropTypes.object,
small: PropTypes.bool,
renderIcon: PropTypes.func,
onPress: PropTypes.func,
children: PropTypes.oneOfType([PropTypes.node, PropTypes.func])
};

export default Alert;
22 changes: 18 additions & 4 deletions app/components/Base/hooks/useModalHandler.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
import { useState } from 'react';
import { useCallback, useState } from 'react';

/**
* @typedef {Boolean} isVisible boolean value that represent wether the modal is visible or not
* @typedef {Function} toggleModal function that toggles the isVisible boolean value
* @typedef {Function} showModal function that sets isVisible boolean to true
* @typedef {Function} hideModal function that sets isVisible boolean to false
* @typedef {[isVisible, toggleModal, showModal, hideModal]} Handlers
*/

/**
* Hook to handle modal visibility state
* @param {Boolean} initialState Initial state of the modal, if true modal will be visible
* @return {Handlers} Handlers `[isVisible, toggleModal, showModal, hideModal]`
*/
function useModalHandler(initialState = false) {
const [isVisible, setVisible] = useState(initialState);

const showModal = () => setVisible(true);
const hideModal = () => setVisible(true);
const toggleModal = () => setVisible(!isVisible);
const showModal = useCallback(() => setVisible(true), []);
const hideModal = useCallback(() => setVisible(false), []);
const toggleModal = useCallback(() => setVisible(visible => !visible), []);

return [isVisible, toggleModal, showModal, hideModal];
}
Expand Down
4 changes: 3 additions & 1 deletion app/components/Nav/Main/MainNavigator.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import PaymentMethodApplePay from '../../UI/FiatOrders/PaymentMethodApplePay';
import TransakWebView from '../../UI/FiatOrders/TransakWebView';
import ActivityView from '../../Views/ActivityView';
import SwapsAmountView from '../../UI/Swaps';
import SwapsQuotesView from '../../UI/Swaps/QuotesView';

const styles = StyleSheet.create({
headerLogo: {
Expand Down Expand Up @@ -275,7 +276,8 @@ export default createStackNavigator(
},
Swaps: {
screen: createStackNavigator({
SwapsAmountView: { screen: SwapsAmountView }
SwapsAmountView: { screen: SwapsAmountView },
SwapsQuotesView: { screen: SwapsQuotesView }
})
},
SetPasswordFlow: {
Expand Down
2 changes: 2 additions & 0 deletions app/components/Nav/Main/__snapshots__/index.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ exports[`Main should render correctly 1`] = `
"Swaps": Object {
"childRouters": Object {
"SwapsAmountView": null,
"SwapsQuotesView": null,
},
"getActionCreators": [Function],
"getActionForPathAndParams": [Function],
Expand Down Expand Up @@ -585,6 +586,7 @@ exports[`Main should render correctly 1`] = `
"Swaps": Object {
"childRouters": Object {
"SwapsAmountView": null,
"SwapsQuotesView": null,
},
"getActionCreators": [Function],
"getActionForPathAndParams": [Function],
Expand Down
44 changes: 42 additions & 2 deletions app/components/Nav/Main/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ import {
getMethodData,
TOKEN_METHOD_TRANSFER,
decodeTransferData,
APPROVE_FUNCTION_SIGNATURE
APPROVE_FUNCTION_SIGNATURE,
decodeApproveData
} from '../../../util/transactions';
import { BN, isValidAddress } from 'ethereumjs-util';
import { isENS, safeToChecksumAddress } from '../../../util/address';
Expand All @@ -61,6 +62,7 @@ import ProtectYourWalletModal from '../../UI/ProtectYourWalletModal';
import MainNavigator from './MainNavigator';
import PaymentChannelApproval from '../../UI/PaymentChannelApproval';
import SkipAccountSecurityModal from '../../UI/SkipAccountSecurityModal';
import { swapsUtils } from '@estebanmino/controllers';

const styles = StyleSheet.create({
flex: {
Expand Down Expand Up @@ -194,14 +196,51 @@ const Main = props => {
[props.navigation, props.transactions]
);

const autoSign = useCallback(
async transactionMeta => {
const { TransactionController } = Engine.context;
try {
TransactionController.hub.once(`${transactionMeta.id}:finished`, transactionMeta => {
if (transactionMeta.status === 'submitted') {
props.navigation.pop();
NotificationManager.watchSubmittedTransaction({
...transactionMeta,
assetType: transactionMeta.transaction.assetType
});
} else {
throw transactionMeta.error;
}
});
await TransactionController.approveTransaction(transactionMeta.id);
} catch (error) {
Alert.alert(strings('transactions.transaction_error'), error && error.message, [
{ text: strings('navigation.ok') }
]);
Logger.error(error, 'error while trying to send transaction (Main)');
}
},
[props.navigation]
);

const onUnapprovedTransaction = useCallback(
async transactionMeta => {
if (transactionMeta.origin === TransactionTypes.MMM) return;

const to = safeToChecksumAddress(transactionMeta.transaction.to);
const networkId = Networks[props.providerType].networkId;
const { data } = transactionMeta.transaction;

// if approval data includes metaswap contract
// if destination address is metaswap contract

if (
to === safeToChecksumAddress(swapsUtils.SWAPS_CONTRACT_ADDRESS) ||
(data &&
data.substr(0, 10) === APPROVE_FUNCTION_SIGNATURE &&
decodeApproveData(data).spenderAddress === swapsUtils.SWAPS_CONTRACT_ADDRESS)
) {
autoSign(transactionMeta);
} else if (
props.paymentChannelsEnabled &&
AppConstants.CONNEXT.SUPPORTED_NETWORKS.includes(props.providerType) &&
transactionMeta.transaction.data &&
Expand Down Expand Up @@ -279,7 +318,8 @@ const Main = props => {
setEtherTransaction,
setTransactionObject,
toggleApproveModal,
toggleDappTransactionModal
toggleDappTransactionModal,
autoSign
]
);

Expand Down
25 changes: 25 additions & 0 deletions app/components/UI/Navbar/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -902,3 +902,28 @@ export function getSwapsAmountNavbar(navigation) {
)
};
}
export function getSwapsQuotesNavbar(navigation) {
const title = navigation.getParam('title', 'Swaps');
const rightAction = navigation.dismiss;

return {
headerTitle: <NavbarTitle title={title} disableNetwork translate={false} />,
headerLeft: Device.isAndroid() ? (
// eslint-disable-next-line react/jsx-no-bind
<TouchableOpacity onPress={() => navigation.pop()} style={styles.backButton}>
<IonicIcon name={'md-arrow-back'} size={24} style={styles.backIcon} />
</TouchableOpacity>
) : (
// eslint-disable-next-line react/jsx-no-bind
<TouchableOpacity onPress={() => navigation.pop()} style={styles.closeButton}>
<Text style={styles.closeButtonText}>{strings('navigation.back')}</Text>
</TouchableOpacity>
),
headerRight: (
// eslint-disable-next-line react/jsx-no-bind
<TouchableOpacity onPress={rightAction} style={styles.closeButton}>
<Text style={styles.closeButtonText}>{strings('navigation.cancel')}</Text>
</TouchableOpacity>
)
};
}
Loading