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

feat: smart tx small views #9448

Merged
merged 45 commits into from
May 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
fb22852
chore: commit all files in /utils for STX
infiniteflower Apr 29, 2024
c827465
chore: commit file for e2e selectors
infiniteflower Apr 29, 2024
b459da1
chore: commit images for STX
infiniteflower Apr 29, 2024
c180871
chore: commit STX updates to package.json and patches
infiniteflower Apr 29, 2024
4e10ca2
chore: commit yarn lock
infiniteflower Apr 29, 2024
91dc131
chore: commit jest.config.js to fix tests
infiniteflower Apr 29, 2024
b59ab30
chore: commit a constant to fix tests
infiniteflower Apr 29, 2024
9e1df32
chore: revert test file to fix failing test
infiniteflower Apr 29, 2024
063b3f1
chore: apply new changes from #9565
infiniteflower May 10, 2024
01c04d1
chore: remove unused files
infiniteflower May 10, 2024
0d8b348
chore: remove unused files
infiniteflower May 10, 2024
3b109fa
chore: remove unused file
infiniteflower May 10, 2024
b2877a6
chore: apply changes from #9565
infiniteflower May 11, 2024
8526be7
chore: apply changes from #9565
infiniteflower May 11, 2024
c74c281
fix: broken bitrise tests
infiniteflower May 11, 2024
99f69dd
Revert "fix: broken bitrise tests"
infiniteflower May 11, 2024
ae74cff
chore: revert app/util/transactions changes, move to #9448
infiniteflower May 11, 2024
bdcf262
Revert "chore: revert app/util/transactions changes, move to #9448"
infiniteflower May 11, 2024
e029bad
fix: broken tests
infiniteflower May 11, 2024
143c9f2
Update app/util/transactions/index.js
infiniteflower May 15, 2024
ce8091a
Update app/util/transactions/index.js
infiniteflower May 15, 2024
4c144b3
chore: bump min app version for STX opt in modal
infiniteflower May 15, 2024
fbd1449
Revert "chore: bump min app version for STX opt in modal"
infiniteflower May 15, 2024
8488bc6
chore: commit STX updates to package.json and patches
infiniteflower Apr 29, 2024
e453a74
chore: commit yarn lock
infiniteflower Apr 29, 2024
9b450a8
chore: commit all view files for STX
infiniteflower Apr 30, 2024
c402ed7
chore: commit all Engine files for STX
infiniteflower Apr 30, 2024
7c82c14
chore: commit all reducer and selector files for STX
infiniteflower Apr 30, 2024
0756f43
chore: commit pref controller and swaps controller patches for STX
infiniteflower Apr 30, 2024
20b522e
chore: commit test file initial state for STX
infiniteflower Apr 30, 2024
87189f7
chore: remove extra blank line in yarn.lock
infiniteflower May 2, 2024
38e2143
chore: update yarn.lock
infiniteflower May 2, 2024
ea6bdc4
chore: apply changes from #9565
infiniteflower May 11, 2024
bba846b
chore: apply changes from #9565
infiniteflower May 11, 2024
5e1453d
feat: add slice for smart transactions and related tests
infiniteflower May 15, 2024
151201b
chore: use redux slice to store STX opt in modal version seen
infiniteflower May 15, 2024
32800b3
fix: lint errors
infiniteflower May 15, 2024
703963c
Update app/components/Nav/Main/RootRPCMethodsUI.js
infiniteflower May 15, 2024
17ca6ab
chore: remove ts ignore
infiniteflower May 15, 2024
50d2c8a
chore: remove commented code
infiniteflower May 15, 2024
b83d444
chore: bump min app version for opt in
infiniteflower May 15, 2024
1c117ac
Merge branch 'main' into feat/smart-tx-small-views
infiniteflower May 16, 2024
aefbadd
chore: move colors out into a fn
infiniteflower May 16, 2024
9485370
Merge branch 'main' into feat/smart-tx-small-views
infiniteflower May 16, 2024
b0f9e3b
chore: use background state for TransactionController.swapsTransactions
infiniteflower May 16, 2024
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
5 changes: 5 additions & 0 deletions app/components/Nav/App/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ import generateUserSettingsAnalyticsMetaData from '../../../util/metrics/UserSet
import OnboardingSuccess from '../../Views/OnboardingSuccess';
import DefaultSettings from '../../Views/OnboardingSuccess/DefaultSettings';
import BasicFunctionalityModal from '../../UI/BasicFunctionality/BasicFunctionalityModal/BasicFunctionalityModal';
import SmartTransactionsOptInModal from '../../Views/SmartTransactionsOptInModal/SmartTranactionsOptInModal';

const clearStackNavigatorOptions = {
headerShown: false,
Expand Down Expand Up @@ -590,6 +591,10 @@ const App = ({ userLoggedIn }) => {
component={ModalMandatory}
/>
<Stack.Screen name={Routes.MODAL.WHATS_NEW} component={WhatsNewModal} />
<Stack.Screen
name={Routes.MODAL.SMART_TRANSACTIONS_OPT_IN}
component={SmartTransactionsOptInModal}
/>
<Stack.Screen
name={Routes.SHEET.ACCOUNT_SELECTOR}
component={AccountSelector}
Expand Down
61 changes: 50 additions & 11 deletions app/components/Nav/Main/RootRPCMethodsUI.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
getTokenAddressParam,
calcTokenAmount,
getTokenValueParamAsHex,
getIsSwapApproveOrSwapTransaction as isSwapTransaction,
getIsSwapApproveOrSwapTransaction,
} from '../../../util/transactions';
import { BN } from 'ethereumjs-util';
import Logger from '../../../util/Logger';
Expand Down Expand Up @@ -63,6 +63,9 @@ import { getLedgerKeyring } from '../../../core/Ledger/Ledger';
import { createLedgerTransactionModalNavDetails } from '../../UI/LedgerModals/LedgerTransactionModal';
import ExtendedKeyringTypes from '../../../constants/keyringTypes';
import { useMetrics } from '../../../components/hooks/useMetrics';
import { selectShouldUseSmartTransaction } from '../../../selectors/smartTransactionsController';
import { STX_NO_HASH_ERROR } from '../../../util/smart-transactions/smart-publish-hook';
import { getSmartTransactionMetricsProperties } from '../../../util/smart-transactions';

///: BEGIN:ONLY_INCLUDE_IF(snaps)
import InstallSnapApproval from '../../Approvals/InstallSnapApproval';
Expand All @@ -82,10 +85,11 @@ const RootRPCMethodsUI = (props) => {
};

const trackSwaps = useCallback(
async (event, transactionMeta) => {
async (event, transactionMeta, swapsTransactions) => {
try {
const { TransactionController } = Engine.context;
const newSwapsTransactions = props.swapsTransactions;
const { TransactionController, SmartTransactionsController } =
Engine.context;
const newSwapsTransactions = swapsTransactions;
const swapTransaction = newSwapsTransactions[transactionMeta.id];
const {
sentAt,
Expand Down Expand Up @@ -166,12 +170,20 @@ const RootRPCMethodsUI = (props) => {
delete newSwapsTransactions[transactionMeta.id].analytics;
delete newSwapsTransactions[transactionMeta.id].paramsForAnalytics;

const smartTransactionMetricsProperties =
getSmartTransactionMetricsProperties(
SmartTransactionsController,
transactionMeta,
);

const parameters = {
...analyticsParams,
time_to_mine: timeToMine,
estimated_vs_used_gasRatio: estimatedVsUsedGasRatio,
quote_vs_executionRatio: quoteVsExecutionRatio,
token_to_amount_received: tokenToAmountReceived.toString(),
is_smart_transaction: props.shouldUseSmartTransaction,
...smartTransactionMetricsProperties,
};

trackAnonymousEvent(event, parameters);
Expand All @@ -184,7 +196,7 @@ const RootRPCMethodsUI = (props) => {
},
[
props.selectedAddress,
props.swapsTransactions,
props.shouldUseSmartTransaction,
trackEvent,
trackAnonymousEvent,
],
Expand All @@ -193,6 +205,7 @@ const RootRPCMethodsUI = (props) => {
const autoSign = useCallback(
async (transactionMeta) => {
const { TransactionController, KeyringController } = Engine.context;
const swapsTransactions = props.swapsTransactions;
try {
TransactionController.hub.once(
`${transactionMeta.id}:finished`,
Expand All @@ -203,8 +216,12 @@ const RootRPCMethodsUI = (props) => {
assetType: transactionMeta.txParams.assetType,
});
} else {
if (props.swapsTransactions[transactionMeta.id]?.analytics) {
trackSwaps(MetaMetricsEvents.SWAP_FAILED, transactionMeta);
if (swapsTransactions[transactionMeta.id]?.analytics) {
trackSwaps(
MetaMetricsEvents.SWAP_FAILED,
transactionMeta,
swapsTransactions,
);
}
throw transactionMeta.error;
}
Expand All @@ -213,8 +230,15 @@ const RootRPCMethodsUI = (props) => {
TransactionController.hub.once(
`${transactionMeta.id}:confirmed`,
(transactionMeta) => {
if (props.swapsTransactions[transactionMeta.id]?.analytics) {
trackSwaps(MetaMetricsEvents.SWAP_COMPLETED, transactionMeta);
if (
swapsTransactions[transactionMeta.id]?.analytics &&
swapsTransactions[transactionMeta.id]?.paramsForAnalytics
) {
trackSwaps(
MetaMetricsEvents.SWAP_COMPLETED,
transactionMeta,
swapsTransactions,
);
}
},
);
Expand Down Expand Up @@ -242,7 +266,10 @@ const RootRPCMethodsUI = (props) => {
Engine.acceptPendingApproval(transactionMeta.id);
}
} catch (error) {
if (!error?.message.startsWith(KEYSTONE_TX_CANCELED)) {
if (
!error?.message.startsWith(KEYSTONE_TX_CANCELED) &&
!error?.message.startsWith(STX_NO_HASH_ERROR)
) {
Alert.alert(
strings('transactions.transaction_error'),
error && error.message,
Expand All @@ -264,7 +291,14 @@ const RootRPCMethodsUI = (props) => {
const to = transactionMeta.txParams.to?.toLowerCase();
const { data } = transactionMeta.txParams;

if (isSwapTransaction(data, transactionMeta.origin, to, props.chainId)) {
if (
getIsSwapApproveOrSwapTransaction(
data,
transactionMeta.origin,
to,
props.chainId,
)
) {
autoSign(transactionMeta);
} else {
const {
Expand Down Expand Up @@ -441,6 +475,10 @@ RootRPCMethodsUI.propTypes = {
* Chain id
*/
chainId: PropTypes.string,
/**
* If smart transactions should be used
*/
shouldUseSmartTransaction: PropTypes.bool,
};

const mapStateToProps = (state) => ({
Expand All @@ -450,6 +488,7 @@ const mapStateToProps = (state) => ({
swapsTransactions:
state.engine.backgroundState.TransactionController.swapsTransactions || {},
providerType: selectProviderType(state),
shouldUseSmartTransaction: selectShouldUseSmartTransaction(state),
});

const mapDispatchToProps = (dispatch) => ({
Expand Down
62 changes: 46 additions & 16 deletions app/components/UI/Notification/TransactionNotification/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ function TransactionNotification(props) {
onClose,
transactions,
animatedTimingStart,
smartTransactions,
} = props;

const [transactionDetails, setTransactionDetails] = useState(undefined);
Expand Down Expand Up @@ -265,13 +266,23 @@ function TransactionNotification(props) {
getTransactionInfo();
}, [
transactions,
smartTransactions,
currentNotification.transaction.id,
transactionAction,
props,
]);

useEffect(() => onCloseNotification(), [onCloseNotification]);

// Don't show submitted notification for STX b/c we only know when it's confirmed,
// o/w a submitted notification will show up after it's confirmed, then a confirmed notification will show up immediately after
if (tx.status === 'submitted') {
const smartTx = smartTransactions.find((stx) => stx.txHash === tx.hash);
if (smartTx) {
return null;
}
}

return (
<>
<Animated.View
Expand Down Expand Up @@ -372,6 +383,10 @@ TransactionNotification.propTypes = {
* An array that represents the user transactions on chain
*/
transactions: PropTypes.array,
/**
* An array that represents the user smart transactions on chain
*/
smartTransactions: PropTypes.array,

/**
* String of selected address
Expand Down Expand Up @@ -416,21 +431,36 @@ TransactionNotification.propTypes = {
primaryCurrency: PropTypes.string,
};

const mapStateToProps = (state) => ({
accounts: selectAccounts(state),
selectedAddress: selectSelectedAddress(state),
transactions: state.engine.backgroundState.TransactionController.transactions,
ticker: selectTicker(state),
chainId: selectChainId(state),
tokens: selectTokensByAddress(state),
collectibleContracts: collectibleContractsSelector(state),
contractExchangeRates: selectContractExchangeRates(state),
conversionRate: selectConversionRate(state),
currentCurrency: selectCurrentCurrency(state),
primaryCurrency: state.settings.primaryCurrency,
swapsTransactions:
state.engine.backgroundState.TransactionController.swapsTransactions || {},
swapsTokens: state.engine.backgroundState.SwapsController.tokens,
});
const mapStateToProps = (state) => {
const chainId = selectChainId(state);

const {
SmartTransactionsController,
TransactionController,
SwapsController,
} = state.engine.backgroundState;

const smartTransactions =
SmartTransactionsController?.smartTransactionsState?.smartTransactions?.[
chainId
] || [];

return {
accounts: selectAccounts(state),
selectedAddress: selectSelectedAddress(state),
transactions: TransactionController.transactions,
ticker: selectTicker(state),
chainId,
tokens: selectTokensByAddress(state),
collectibleContracts: collectibleContractsSelector(state),
contractExchangeRates: selectContractExchangeRates(state),
conversionRate: selectConversionRate(state),
currentCurrency: selectCurrentCurrency(state),
primaryCurrency: state.settings.primaryCurrency,
swapsTransactions: TransactionController.swapsTransactions || {},
swapsTokens: SwapsController.tokens,
smartTransactions,
};
};

export default connect(mapStateToProps)(TransactionNotification);
28 changes: 21 additions & 7 deletions app/components/UI/Swaps/QuotesView.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ import { useMetrics } from '../../../components/hooks/useMetrics';
import { addTransaction } from '../../../util/transaction-controller';
import trackErrorAsAnalytics from '../../../util/metrics/TrackError/trackErrorAsAnalytics';
import { selectGasFeeEstimates } from '../../../selectors/confirmTransaction';
import { selectShouldUseSmartTransaction } from '../../../selectors/smartTransactionsController';

const POLLING_INTERVAL = 30000;
const SLIPPAGE_BUCKETS = {
Expand Down Expand Up @@ -388,6 +389,7 @@ function SwapsQuotesView({
usedCustomGas,
setRecipient,
resetTransaction,
shouldUseSmartTransaction,
}) {
const navigation = useNavigation();
/* Get params from navigation */
Expand Down Expand Up @@ -926,11 +928,13 @@ function SwapsQuotesView({
origin: process.env.MM_FOX_CODE,
},
);

updateSwapsTransactions(
transactionMeta,
approvalTransactionMetaId,
newSwapsTransactions,
);

setRecipient(selectedAddress);
await addTokenToAssetsController(destinationToken);
await addTokenToAssetsController(sourceToken);
Expand Down Expand Up @@ -990,7 +994,7 @@ function SwapsQuotesView({
16,
).toString(10),
};
if (isHardwareAddress) {
if (isHardwareAddress || shouldUseSmartTransaction) {
TransactionController.hub.once(
`${transactionMeta.id}:confirmed`,
(transactionMeta) => {
Expand Down Expand Up @@ -1019,6 +1023,7 @@ function SwapsQuotesView({
selectedAddress,
setRecipient,
resetTransaction,
shouldUseSmartTransaction,
],
);

Expand All @@ -1032,6 +1037,7 @@ function SwapsQuotesView({
startSwapAnalytics(selectedQuote, selectedAddress);

const { TransactionController } = Engine.context;

const newSwapsTransactions =
TransactionController.state.swapsTransactions || {};
let approvalTransactionMetaId;
Expand All @@ -1050,12 +1056,17 @@ function SwapsQuotesView({
}
}

handleSwapTransaction(
TransactionController,
newSwapsTransactions,
approvalTransactionMetaId,
isHardwareAddress,
);
if (
!shouldUseSmartTransaction ||
(shouldUseSmartTransaction && !approvalTransaction)
) {
handleSwapTransaction(
TransactionController,
newSwapsTransactions,
approvalTransactionMetaId,
isHardwareAddress,
);
}

navigation.dangerouslyGetParent()?.pop();
}, [
Expand All @@ -1066,6 +1077,7 @@ function SwapsQuotesView({
handleApprovaltransaction,
handleSwapTransaction,
navigation,
shouldUseSmartTransaction,
]);

const onEditQuoteTransactionsGas = useCallback(() => {
Expand Down Expand Up @@ -2299,6 +2311,7 @@ SwapsQuotesView.propTypes = {
usedCustomGas: PropTypes.object,
setRecipient: PropTypes.func,
resetTransaction: PropTypes.func,
shouldUseSmartTransaction: PropTypes.bool,
};

const mapStateToProps = (state) => ({
Expand Down Expand Up @@ -2331,6 +2344,7 @@ const mapStateToProps = (state) => ({
usedCustomGas: state.engine.backgroundState.SwapsController.usedCustomGas,
primaryCurrency: state.settings.primaryCurrency,
swapsTokens: swapsTokensSelector(state),
shouldUseSmartTransaction: selectShouldUseSmartTransaction(state),
});

const mapDispatchToProps = (dispatch) => ({
Expand Down
Loading
Loading