Skip to content

Commit

Permalink
Merge branch 'develop' of github.com:rainbow-me/rainbow into brody/sw…
Browse files Browse the repository at this point in the history
…ap-v2-e2e

* 'develop' of github.com:rainbow-me/rainbow:
  Fix weird issues with rounding  (#5822)
  Fix provider recursion bug, provider function types (#5829)
  bump braces (#5831)
  Add entry point for other networks (#5824)
  remove info icon on max transaction fee row as we don't have that in spec (#5827)
  [e2e] Add Malicious Dapp interaction test (#5764)
  reorg ens related calls (#5828)
  Performance: limit Sentry tracking, fix NFT hooks (#5819)
  fix wrong chainname (#5823)
  Disable flashbots toggle on appropriate chains (#5812)
  add type to SearchAsset type and add into type possibilities (#5820)
  fix fasterimage border radius android (#5816)
  more Safemath fixes (#5818)
  • Loading branch information
BrodyHughes committed Jun 11, 2024
2 parents b7918e9 + 2654e86 commit 3ac2ec2
Show file tree
Hide file tree
Showing 71 changed files with 839 additions and 637 deletions.
7 changes: 3 additions & 4 deletions e2e/4_discoverSheetFlow.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,12 @@ describe('Discover Screen Flow', () => {
});

it('Should navigate to the Points screen after swiping left', async () => {
await swipe('profile-screen', 'left', 'slow');
await swipe('profile-screen', 'left', 'fast');
await checkIfVisible('points-screen');
});

it('Should navigate back to Discover screen after swiping right twice', async () => {
await swipe('points-screen', 'right', 'slow');
await swipe('profile-screen', 'right', 'slow');
it('Should navigate back to Discover screen after tapping Discover icon', async () => {
await waitAndTap('tab-bar-icon-DiscoverScreen');
await checkIfVisible('discover-header');
});

Expand Down
56 changes: 56 additions & 0 deletions e2e/7_maliciousDappConnection.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import {
beforeAllcleanApp,
afterAllcleanApp,
importWalletFlow,
waitAndTap,
swipe,
checkIfVisible,
checkIfExistsByText,
typeText,
delayTime,
tapAtPoint,
checkIfExists,
} from './helpers';
import { WALLET_VARS } from './testVariables';

describe('Check malicious dapp warning', () => {
beforeAll(async () => {
await beforeAllcleanApp({ hardhat: false });
});

afterAll(async () => {
await afterAllcleanApp({ hardhat: false });
});

it('Should be able to watch a wallet and load the wallet screen', async () => {
await importWalletFlow(WALLET_VARS.SEED_WALLET.PK);
});

it('Should be able to navigate to the dapp browser', async () => {
await swipe('wallet-screen', 'left', 'fast');
await swipe('discover-sheet', 'left', 'fast');
await checkIfVisible('browser-screen');
});

it('Should be able to type on search input and go to malicious dapp', async () => {
await waitAndTap('browser-search-input');
await checkIfExistsByText('Find apps and more');
await typeText('browser-search-input', 'https://test-dap-welps.vercel.app/', true, false, true);
// Waiting for webpage to load
await delayTime('long');
});

it('Should attempt to connect to in browser dapp', async () => {
// Detox can't query elements within a WebView within our app
// Using tapAtPoint() to tap coordinates is a workaround for now

// Tapping connect button
await tapAtPoint('browser-screen', { x: 275, y: 80 });
// Waiting for rainbowkit sheet to load / animate in
await delayTime('medium');
// Tapping Rainbow button
await tapAtPoint('browser-screen', { x: 50, y: 325 });

await checkIfExists('malicious-dapp-warning');
});
});
17 changes: 12 additions & 5 deletions e2e/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { Wallet } from '@ethersproject/wallet';
import { expect, device, element, by, waitFor } from 'detox';
import { parseEther } from '@ethersproject/units';
import { AndroidElementAttributes, ElementAttributes, IosElementAttributes } from 'detox/detox';
import { WALLET_VARS } from './testVariables';
import { ethers } from 'ethers';

const TESTING_WALLET = '0x3Cb462CDC5F809aeD0558FBEe151eD5dC3D3f608';
Expand Down Expand Up @@ -44,15 +43,15 @@ export async function killHardhat() {
exec('kill $(lsof -t -i:8545)');
}

export async function importWalletFlow({ seedPhrase = true }: { seedPhrase: boolean }) {
export async function importWalletFlow(customSeed?: string) {
await checkIfVisible('welcome-screen');
await tap('already-have-wallet-button');
await checkIfExists('add-wallet-sheet');
await tap('restore-with-key-button');
await checkIfExists('import-sheet');
await clearField('import-sheet-input');
await device.disableSynchronization();
await typeText('import-sheet-input', seedPhrase ? process.env.TEST_SEEDS : WALLET_VARS.SEED_WALLET.PK, false);
await typeText('import-sheet-input', customSeed ? customSeed : process.env.TEST_SEEDS, false);
await checkIfElementHasString('import-sheet-button-label', 'Continue');
await tap('import-sheet-button');
await checkIfVisible('wallet-info-modal');
Expand All @@ -65,7 +64,7 @@ export async function importWalletFlow({ seedPhrase = true }: { seedPhrase: bool
await device.enableSynchronization();

// when using a secret wallet import times can take a while
await delayTime(seedPhrase ? 'very-long' : 'short');
await delayTime(customSeed ? 'medium' : 'very-long');
await checkIfVisible('wallet-screen');
}

Expand Down Expand Up @@ -148,7 +147,13 @@ export async function startIosSimulator() {
}
}

export async function typeText(elementId: string | RegExp, text: string | undefined, focus = true, syncOnAndroid = false) {
export async function typeText(
elementId: string | RegExp,
text: string | undefined,
focus = true,
syncOnAndroid = false,
hitEnterAfterText = false
) {
if (text === undefined) {
throw new Error(`Cannot type 'undefined' into element with id ${elementId}`);
}
Expand All @@ -161,13 +166,15 @@ export async function typeText(elementId: string | RegExp, text: string | undefi
await device.disableSynchronization();
}
await element(by.id(elementId)).typeText(text);
hitEnterAfterText && (await typeText(elementId, '\n'));
if (device.getPlatform() === 'android' && !syncOnAndroid) {
await device.enableSynchronization();
}
} catch (error) {
throw new Error(`Error typing "${text}" at element with id ${elementId}}: ${error}`);
}
}

export async function typeNumbers(elementId: string | RegExp, text: string, submitLabel: string | RegExp) {
try {
await element(by.id(elementId)).replaceText(text.replace('\n', ''));
Expand Down
3 changes: 3 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@ It needs to be an import statement because otherwise it doesn't load properly
likely because of typescript.
*/
import '@walletconnect/react-native-compat';
import { initSentry } from '@/logger/sentry';
import { analytics } from './src/analytics';
import { StartTime } from './src/performance/start-time';
import { PerformanceTracking } from './src/performance/tracking';
import { PerformanceMetrics } from './src/performance/tracking/types/PerformanceMetrics';

initSentry();

analytics.track('Started executing JavaScript bundle');
PerformanceTracking.logDirectly(PerformanceMetrics.loadJSBundle, Date.now() - StartTime.START_TIME);
PerformanceTracking.startMeasuring(PerformanceMetrics.loadRootAppComponent);
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,7 @@
"webpack-cli": "5.1.4"
},
"resolutions": {
"**/braces": "3.0.3",
"**/async": "2.6.4",
"**/zod": "3.22.3",
"**/file-type": "16.5.4",
Expand Down
15 changes: 5 additions & 10 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ import { InitialRouteContext } from '@/navigation/initialRoute';
import Routes from '@/navigation/routesNames';
import { Portal } from '@/react-native-cool-modals/Portal';
import { NotificationsHandler } from '@/notifications/NotificationsHandler';
import { initSentry, sentryRoutingInstrumentation } from '@/logger/sentry';
import { analyticsV2 } from '@/analytics';
import { getOrCreateDeviceId, securelyHashWalletAddress } from '@/analytics/utils';
import { logger, RainbowError } from '@/logger';
Expand All @@ -57,9 +56,10 @@ import { handleReviewPromptAction } from '@/utils/reviewAlert';
import { RemotePromoSheetProvider } from '@/components/remote-promo-sheet/RemotePromoSheetProvider';
import { RemoteCardProvider } from '@/components/cards/remote-cards';
import { initializeRemoteConfig } from '@/model/remoteConfig';
import { IS_DEV } from './env';
import { checkIdentifierOnLaunch } from './model/backup';

if (__DEV__) {
if (IS_DEV) {
reactNativeDisableYellowBox && LogBox.ignoreAllLogs();
(showNetworkRequests || showNetworkResponses) && monitorNetwork(showNetworkRequests, showNetworkResponses);
}
Expand Down Expand Up @@ -218,10 +218,6 @@ class OldApp extends Component {
updateBalancesAfter(isL2 ? 10000 : 5000, isL2, network);
};

handleSentryNavigationIntegration = () => {
sentryRoutingInstrumentation?.registerNavigationContainer(this.navigatorRef);
};

render() {
return (
<Portal>
Expand All @@ -230,7 +226,7 @@ class OldApp extends Component {
<RemotePromoSheetProvider isWalletReady={this.props.walletReady}>
<RemoteCardProvider>
<InitialRouteContext.Provider value={this.state.initialRoute}>
<RoutesComponent onReady={this.handleSentryNavigationIntegration} ref={this.handleNavigatorRef} />
<RoutesComponent ref={this.handleNavigatorRef} />
<PortalConsumer />
</InitialRouteContext.Provider>
</RemoteCardProvider>
Expand All @@ -257,9 +253,7 @@ function Root() {

React.useEffect(() => {
async function initializeApplication() {
await initSentry(); // must be set up immediately
await initializeRemoteConfig();
// must happen immediately, but after Sentry
await migrate();

const isReturningUser = ls.device.get(['isReturningUser']);
Expand Down Expand Up @@ -339,7 +333,7 @@ function Root() {
// init complete, load the rest of the app
setInitializing(false);
})
.catch(e => {
.catch(() => {
logger.error(new RainbowError(`initializeApplication failed`));

// for failure, continue to rest of the app for now
Expand Down Expand Up @@ -369,6 +363,7 @@ function Root() {
);
}

/** Wrapping Root allows Sentry to accurately track startup times */
const RootWithSentry = Sentry.wrap(Root);

const PlaygroundWithReduxStore = () => (
Expand Down
35 changes: 29 additions & 6 deletions src/__swaps__/safe-math/SafeMath.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,35 @@
// Utility function to remove the decimal point and keep track of the number of decimal places
const removeDecimalWorklet = (num: string): [bigint, number] => {
'worklet';
const parts = num.split('.');
const decimalPlaces = parts.length === 2 ? parts[1].length : 0;
const bigIntNum = BigInt(parts.join(''));
let decimalPlaces = 0;
let bigIntNum: bigint;

if (/[eE]/.test(num)) {
const [base, exponent] = num.split(/[eE]/);
const exp = Number(exponent);
const parts = base.split('.');
const baseDecimalPlaces = parts.length === 2 ? parts[1].length : 0;
const bigIntBase = BigInt(parts.join(''));

if (exp >= 0) {
decimalPlaces = baseDecimalPlaces - exp;
bigIntNum = bigIntBase * BigInt(10) ** BigInt(exp);
} else {
decimalPlaces = baseDecimalPlaces - exp;
bigIntNum = bigIntBase;
}
} else {
const parts = num.split('.');
decimalPlaces = parts.length === 2 ? parts[1].length : 0;
bigIntNum = BigInt(parts.join(''));
}

return [bigIntNum, decimalPlaces];
};

const isNumberStringWorklet = (value: string): boolean => {
'worklet';
return /^-?\d+(\.\d+)?$/.test(value);
return /^-?\d+(\.\d+)?([eE][-+]?\d+)?$/.test(value);
};

const isZeroWorklet = (value: string): boolean => {
Expand Down Expand Up @@ -43,7 +63,11 @@ const formatResultWorklet = (result: bigint): string => {
// Helper function to handle string and number input types
const toStringWorklet = (value: string | number): string => {
'worklet';
return typeof value === 'number' ? value.toString() : value;
const ret = typeof value === 'number' ? value.toString() : value;
if (/^\d+\.$/.test(ret)) {
return ret.slice(0, -1);
}
return ret;
};

// Converts a numeric string to a scaled integer string, preserving the specified decimal places
Expand Down Expand Up @@ -367,7 +391,6 @@ export function floorWorklet(num: string | number): string {
export function roundWorklet(num: string | number): string {
'worklet';
const numStr = toStringWorklet(num);

if (!isNumberStringWorklet(numStr)) {
throw new Error('Argument must be a numeric string or number');
}
Expand Down
5 changes: 4 additions & 1 deletion src/__swaps__/safe-math/__tests__/SafeMath.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,16 @@ const RESULTS = {
floor: '1243425',
toScaledInteger: '57464009350560633',
negativePow: '0.001',
negativeExp: '6.0895415516156',
};

const VALUE_A = '1243425.345';
const VALUE_B = '3819.24';
const VALUE_C = '2';
const VALUE_D = '1243425.745';
const VALUE_E = '0.057464009350560633';
const VALUE_F = '0.001';
const VALUE_F = '147887324';
const VALUE_G = '4.11769e-8';
const NEGATIVE_VALUE = '-2412.12';
const ZERO = '0';
const ONE = '1';
Expand Down Expand Up @@ -80,6 +82,7 @@ describe('SafeMath', () => {
expect(mulWorklet(VALUE_A, VALUE_B)).toBe(RESULTS.mul);
expect(mulWorklet(Number(VALUE_A), VALUE_B)).toBe(RESULTS.mul);
expect(mulWorklet(VALUE_A, Number(VALUE_B))).toBe(RESULTS.mul);
expect(mulWorklet(VALUE_F, VALUE_G)).toBe(RESULTS.negativeExp);
});

test('divWorklet', () => {
Expand Down
Loading

0 comments on commit 3ac2ec2

Please sign in to comment.