Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
13 changes: 13 additions & 0 deletions .yarn/patches/appwright-patch-685d6e06a0.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
diff --git a/dist/providers/browserstack/index.js b/dist/providers/browserstack/index.js
index f5b8ff4f50a96479149d3223ccb31a49aa2c948c..d88d10a97693aa4862e19deef12bb9ffd3fa8287 100644
--- a/dist/providers/browserstack/index.js
+++ b/dist/providers/browserstack/index.js
@@ -249,6 +249,8 @@ class BrowserStackDeviceProvider {
"bstack:options": {
debug: true,
networkProfile : '4g-lte-advanced-good',
+ gpsLocation: "22.3193,114.1694",
+ geoLocation: "HK",
interactiveDebugging: true,
selfHeal: true,
appProfiling: true,
24 changes: 23 additions & 1 deletion app/components/UI/Bridge/hooks/useInsufficientBalance/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,25 @@ const normalizeAmount = (value: string, decimals: number): string => {
return value;
};

export const formatEffectiveGasFee = (
effectiveGasFee: string,
decimals: number,
) => {
// Truncate to token.decimals to avoid parseUnits overflow
const decimalIndex = effectiveGasFee.indexOf('.');
return decimalIndex === -1
? effectiveGasFee
: effectiveGasFee.slice(0, decimalIndex + 1 + decimals);
};

export const transformEffectiveToAtomic = (
effectiveGasFee: string,
decimals: number,
) => {
const formattedFee = formatEffectiveGasFee(effectiveGasFee, decimals);
return parseUnits(formattedFee, decimals);
};

const useIsInsufficientBalance = ({
amount,
token,
Expand Down Expand Up @@ -89,7 +108,10 @@ const useIsInsufficientBalance = ({
: null;

if (effectiveGasFee) {
atomicGasFee = parseUnits(effectiveGasFee, token.decimals);
atomicGasFee = transformEffectiveToAtomic(
effectiveGasFee,
token.decimals,
);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import React from 'react';
import { renderHook } from '@testing-library/react-hooks';
import { Provider } from 'react-redux';
import { createStore, Store } from 'redux';
import useIsInsufficientBalance from './index';
import useIsInsufficientBalance, {
formatEffectiveGasFee,
transformEffectiveToAtomic,
} from './index';
import { BridgeToken } from '../../types';
import { BigNumber } from 'ethers';
import { CHAIN_IDS } from '@metamask/transaction-controller';
Expand Down Expand Up @@ -50,7 +53,7 @@ describe('useIsInsufficientBalance', () => {
chainId: CHAIN_IDS.MAINNET as `0x${string}`,
};

it('should return false when user has sufficient USDC balance for swap (gasless)', () => {
it('returns false when user has sufficient USDC balance for swap (gasless)', () => {
const store = createMockStore({
recommendedQuote: {
quote: {
Expand All @@ -72,7 +75,7 @@ describe('useIsInsufficientBalance', () => {
expect(result.current).toBe(false);
});

it('should return true when user has insufficient USDC balance', () => {
it('returns true when user has insufficient USDC balance', () => {
const store = createMockStore({
recommendedQuote: {
quote: {
Expand All @@ -94,7 +97,7 @@ describe('useIsInsufficientBalance', () => {
expect(result.current).toBe(true);
});

it('should return false for cross-chain USDC transaction with sufficient token balance (gas checked separately)', () => {
it('returns false for cross-chain USDC transaction with sufficient token balance (gas checked separately)', () => {
// For ERC-20 tokens, gas is checked in useHasSufficientGas, not here
const store = createMockStore({
recommendedQuote: {
Expand Down Expand Up @@ -133,7 +136,7 @@ describe('useIsInsufficientBalance', () => {
chainId: CHAIN_IDS.MAINNET as `0x${string}`,
};

it('should return false when user has sufficient ETH for gasless swap', () => {
it('returns false when user has sufficient ETH for gasless swap', () => {
const store = createMockStore({
recommendedQuote: {
quote: {
Expand All @@ -155,7 +158,7 @@ describe('useIsInsufficientBalance', () => {
expect(result.current).toBe(false);
});

it('should return false when user has sufficient ETH including gas for cross-chain', () => {
it('returns false when user has sufficient ETH including gas for cross-chain', () => {
const store = createMockStore({
recommendedQuote: {
quote: {
Expand Down Expand Up @@ -183,7 +186,7 @@ describe('useIsInsufficientBalance', () => {
expect(result.current).toBe(false);
});

it('should return true when ETH amount + gas exceeds balance for cross-chain', () => {
it('returns true when ETH amount + gas exceeds balance for cross-chain', () => {
const store = createMockStore({
recommendedQuote: {
quote: {
Expand Down Expand Up @@ -211,7 +214,7 @@ describe('useIsInsufficientBalance', () => {
expect(result.current).toBe(true);
});

it('should return true when user tries to send more ETH than balance (even without gas)', () => {
it('returns true when user tries to send more ETH than balance (even without gas)', () => {
const store = createMockStore({
recommendedQuote: {
quote: {
Expand All @@ -238,7 +241,7 @@ describe('useIsInsufficientBalance', () => {
expect(result.current).toBe(true);
});

it('should handle scientific notation in gas amounts', () => {
it('handles scientific notation in gas amounts', () => {
const store = createMockStore({
recommendedQuote: {
quote: {
Expand Down Expand Up @@ -267,7 +270,7 @@ describe('useIsInsufficientBalance', () => {
expect(result.current).toBe(false);
});

it('should return true when scientific notation gas causes insufficient balance', () => {
it('returns true when scientific notation gas causes insufficient balance', () => {
const store = createMockStore({
recommendedQuote: {
quote: {
Expand Down Expand Up @@ -304,7 +307,7 @@ describe('useIsInsufficientBalance', () => {
chainId: CHAIN_IDS.POLYGON as `0x${string}`,
};

it('should return false when user has sufficient MATIC including gas', () => {
it('returns false when user has sufficient MATIC including gas', () => {
const store = createMockStore({
recommendedQuote: {
quote: {
Expand Down Expand Up @@ -332,7 +335,7 @@ describe('useIsInsufficientBalance', () => {
expect(result.current).toBe(false);
});

it('should return true when MATIC amount + gas exceeds balance', () => {
it('returns true when MATIC amount + gas exceeds balance', () => {
const store = createMockStore({
recommendedQuote: {
quote: {
Expand Down Expand Up @@ -369,7 +372,7 @@ describe('useIsInsufficientBalance', () => {
chainId: SolScope.Mainnet,
};

it('should return false when user has sufficient SOL above rent exemption', () => {
it('returns false when user has sufficient SOL above rent exemption', () => {
const store = createMockStore({
recommendedQuote: {
quote: {
Expand All @@ -392,7 +395,7 @@ describe('useIsInsufficientBalance', () => {
expect(result.current).toBe(false);
});

it('should return true when SOL balance would drop below rent exemption', () => {
it('returns true when SOL balance would drop below rent exemption', () => {
const store = createMockStore({
recommendedQuote: {
quote: {
Expand Down Expand Up @@ -424,7 +427,7 @@ describe('useIsInsufficientBalance', () => {
chainId: CHAIN_IDS.MAINNET as `0x${string}`,
};

it('should return false when amount is undefined', () => {
it('returns false when amount is undefined', () => {
const store = createMockStore({
recommendedQuote: {
quote: {
Expand All @@ -446,7 +449,7 @@ describe('useIsInsufficientBalance', () => {
expect(result.current).toBe(false);
});

it('should return false when amount is just a decimal point', () => {
it('returns false when amount is just a decimal point', () => {
const store = createMockStore({
recommendedQuote: {
quote: {
Expand All @@ -468,7 +471,7 @@ describe('useIsInsufficientBalance', () => {
expect(result.current).toBe(false);
});

it('should return false when token is undefined', () => {
it('returns false when token is undefined', () => {
const store = createMockStore({
recommendedQuote: {
quote: {
Expand All @@ -490,7 +493,7 @@ describe('useIsInsufficientBalance', () => {
expect(result.current).toBe(false);
});

it('should return false when balance is undefined', () => {
it('returns false when balance is undefined', () => {
const store = createMockStore({
recommendedQuote: {
quote: {
Expand All @@ -512,7 +515,7 @@ describe('useIsInsufficientBalance', () => {
expect(result.current).toBe(false);
});

it('should still check balance when no quote is available', () => {
it('still checks balance when no quote is available', () => {
const store = createMockStore(null);

const { result } = renderHook(
Expand All @@ -530,7 +533,7 @@ describe('useIsInsufficientBalance', () => {
expect(result.current).toBe(true);
});

it('should handle zero balance correctly', () => {
it('handles zero balance correctly', () => {
const store = createMockStore({
recommendedQuote: {
quote: {
Expand All @@ -552,4 +555,56 @@ describe('useIsInsufficientBalance', () => {
expect(result.current).toBe(true);
});
});

describe('transformEffectiveToAtomic', () => {
it('transforms effective gas fee to atomic gas fee', () => {
const effectiveGasFee = '0.000000000000000001';
const decimals = 18;
const atomicGasFee = transformEffectiveToAtomic(
effectiveGasFee,
decimals,
);
expect(atomicGasFee.toString()).toBe('1');
});

it('transforms effective gas fee to atomic gas fee with decimals', () => {
const effectiveGasFee = '0.000001426955931521';
const decimals = 6;
const atomicGasFee = transformEffectiveToAtomic(
effectiveGasFee,
decimals,
);
expect(atomicGasFee.toString()).toBe('1');
});
});

describe('formatEffectiveGasFee', () => {
it('formats effective gas fee to string', () => {
const effectiveGasFee = '0.000000000000000001';
const decimals = 18;
const formattedGasFee = formatEffectiveGasFee(effectiveGasFee, decimals);
expect(formattedGasFee).toBe(effectiveGasFee);
});

it('formats effective gas fee to string for integer part > 0', () => {
const effectiveGasFee = '23.000000000000000001';
const decimals = 18;
const formattedGasFee = formatEffectiveGasFee(effectiveGasFee, decimals);
expect(formattedGasFee).toBe(effectiveGasFee);
});

it('formats effective gas fee to string when token decimals is less than effective gas fee decimals', () => {
const effectiveGasFee = '0.000005426955931521';
const decimals = 6;
const formattedGasFee = formatEffectiveGasFee(effectiveGasFee, decimals);
expect(formattedGasFee).toBe('0.000005');
});

it('formats effective gas fee to string when token decimals is more than effective gas fee decimals', () => {
const effectiveGasFee = '0.000005';
const decimals = 18;
const formattedGasFee = formatEffectiveGasFee(effectiveGasFee, decimals);
expect(formattedGasFee).toBe('0.000005');
});
});
});
20 changes: 14 additions & 6 deletions app/components/UI/Bridge/hooks/useSwapBridgeNavigation/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
getDefaultDestToken,
} from '../../utils/tokenUtils';
import { areAddressesEqual } from '../../../../../util/address';
import TrendingFeedSessionManager from '../../../Trending/services/TrendingFeedSessionManager';

export enum SwapBridgeNavigationLocation {
TabBar = 'TabBar',
Expand Down Expand Up @@ -175,14 +176,21 @@ export const useSwapBridgeNavigation = ({
? ActionLocation.NAVBAR
: ActionLocation.ASSET_DETAILS,
});
// Check if user is in an active trending session for analytics
const isFromTrending =
TrendingFeedSessionManager.getInstance().isFromTrending;

const swapEventProperties = {
location,
chain_id_source: getDecimalChainId(sourceToken.chainId),
token_symbol_source: sourceToken?.symbol,
token_address_source: sourceToken?.address,
from_trending: isFromTrending,
};

trackEvent(
createEventBuilder(MetaMetricsEvents.SWAP_BUTTON_CLICKED)
.addProperties({
location,
chain_id_source: getDecimalChainId(sourceToken.chainId),
token_symbol_source: sourceToken?.symbol,
token_address_source: sourceToken?.address,
})
.addProperties(swapEventProperties)
.build(),
);
trace({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ import {
usePerpsToasts,
usePerpsTrading,
} from '../../hooks';
import TrendingFeedSessionManager from '../../../Trending/services/TrendingFeedSessionManager';
import {
usePerpsLiveAccount,
usePerpsLivePrices,
Expand Down Expand Up @@ -162,6 +163,10 @@ interface PerpsOrderViewContentProps {
const PerpsOrderViewContentBase: React.FC<PerpsOrderViewContentProps> = ({
hideTPSL = false,
}) => {
// Auto-detect source based on trending session state
const source = TrendingFeedSessionManager.getInstance().isFromTrending
? 'trending'
: undefined;
const navigation = useNavigation<NavigationProp<PerpsNavigationParamList>>();
const { colors } = useTheme();
const insets = useSafeAreaInsets();
Expand Down Expand Up @@ -835,6 +840,7 @@ const PerpsOrderViewContentBase: React.FC<PerpsOrderViewContentProps> = ({
feeDiscountPercentage: feeResults.feeDiscountPercentage,
estimatedPoints: feeResults.estimatedPoints,
inputMethod: inputMethodRef.current,
source,
},
};

Expand Down Expand Up @@ -891,6 +897,7 @@ const PerpsOrderViewContentBase: React.FC<PerpsOrderViewContentProps> = ({
feeResults.metamaskFeeRate,
feeResults.feeDiscountPercentage,
feeResults.estimatedPoints,
source,
isButtonColorTestEnabled,
buttonColorVariant,
]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ export class TradingService {
params.price && {
[PerpsEventProperties.LIMIT_PRICE]: parseFloat(params.price),
}),
...(params.trackingData?.source && {
[PerpsEventProperties.SOURCE]: params.trackingData.source,
}),
});

// Add success-specific properties
Expand Down
3 changes: 3 additions & 0 deletions app/components/UI/Perps/controllers/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ export interface TrackingData {
// Close-specific (used for position close operations)
receivedAmount?: number; // Amount user receives after close (calculated by hooks)
realizedPnl?: number; // Realized P&L from close (calculated by hooks)

// Entry source for analytics (e.g., 'trending' for Trending page discovery)
source?: string;
}

// TP/SL-specific tracking data for analytics events
Expand Down
Loading
Loading