10 |
11 | @interface RCT_EXTERN_MODULE(RNArgon2, NSObject)
12 |
13 | RCT_EXTERN_METHOD(argon2: (NSString *)password salt:(NSString *)salt config:(NSDictionary *)config resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | import './shim';
2 | import './services/msw/init';
3 | import { AppRegistry, Text } from 'react-native';
4 | import '@walletconnect/react-native-compat';
5 | import { name as appName } from './app.json';
6 | import './src/notifications/NotificationsConfig';
7 | import App from './src/App';
8 |
9 | if (Text.defaultProps == null) Text.defaultProps = {};
10 |
11 | Text.defaultProps.allowFontScaling = false;
12 |
13 | AppRegistry.registerComponent(appName, () => App);
14 |
--------------------------------------------------------------------------------
/src/constants/styleGuide/fonts.mock.js:
--------------------------------------------------------------------------------
1 | export default {
2 | family: {
3 | heading: 'PTMono-Regular',
4 | context: 'PTMono-Regular',
5 | contextBold: 'PTMono-Regular',
6 | contextSemiBold: 'PTMono-Regular',
7 | recoveryPhrase: 'PTMono-Regular',
8 | recoveryPhraseText: 'PTMono-Regular',
9 | },
10 | size: {
11 | h1: 26,
12 | h2: 24,
13 | h3: 22,
14 | h4: 20,
15 | base: 16,
16 | small: 13,
17 | input: 14,
18 | },
19 | };
20 |
--------------------------------------------------------------------------------
/src/modules/SendToken/mocks/index.js:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line import/no-extraneous-dependencies
2 | import { rest } from 'msw';
3 |
4 | import { API_VERSION } from 'utilities/api/constants';
5 | import { mockSendTokenResponse } from '../__fixtures__';
6 |
7 | export const sendTokenMockHandler = rest.post(
8 | `*/api/${API_VERSION}/transactions`,
9 | (_, res, ctx) => {
10 | return res(ctx.delay(20), ctx.status(201), ctx.json(mockSendTokenResponse));
11 | }
12 | );
13 |
--------------------------------------------------------------------------------
/src/components/shared/ObjectViewer/ObjectViewer.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ObjectNode from './ObjectNode';
3 | import objectType from './utils/ObjectViewer.utils';
4 |
5 | const ObjectViewer = ({ data, style }) => {
6 | const nodeType = objectType(data);
7 |
8 | switch (nodeType) {
9 | case 'Iterable':
10 | return ;
11 | default:
12 | return null;
13 | }
14 | };
15 |
16 | export default ObjectViewer;
17 |
--------------------------------------------------------------------------------
/services/msw/init.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/no-extraneous-dependencies */
2 | import { MSWServer } from './MSWServer';
3 |
4 | if (process.env.MOCK_SERVICE_API_ENABLED) {
5 | require('react-native-url-polyfill/auto');
6 |
7 | // eslint-disable-next-line @typescript-eslint/no-var-requires
8 | const nativeMsw = require('msw/native');
9 |
10 | const mswDevServer = new MSWServer('dev', nativeMsw.setupServer);
11 |
12 | mswDevServer.init({ onUnhandledRequest: 'bypass' });
13 | }
14 |
--------------------------------------------------------------------------------
/src/components/screens/terms/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View } from 'react-native';
3 | import { WebView } from 'react-native-webview';
4 | import URLs from 'constants/URLs';
5 |
6 | const Terms = () => (
7 |
8 |
13 |
14 | );
15 |
16 | export default Terms;
17 |
--------------------------------------------------------------------------------
/patches/react-native-os+1.2.6.patch:
--------------------------------------------------------------------------------
1 | diff --git a/node_modules/react-native-os/android/build.gradle b/node_modules/react-native-os/android/build.gradle
2 | index 7055b60..784681d 100644
3 | --- a/node_modules/react-native-os/android/build.gradle
4 | +++ b/node_modules/react-native-os/android/build.gradle
5 | @@ -44,5 +44,5 @@ repositories {
6 | }
7 |
8 | dependencies {
9 | - compile 'com.facebook.react:react-native:+'
10 | + implementation 'com.facebook.react:react-native:+'
11 | }
12 |
--------------------------------------------------------------------------------
/android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
--------------------------------------------------------------------------------
/src/components/shared/Swipeable/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 |
3 | const styles = StyleSheet.create({
4 | leftAction: {
5 | flex: 1,
6 | backgroundColor: '#497AFC',
7 | justifyContent: 'center',
8 | },
9 | actionText: {
10 | color: 'white',
11 | fontSize: 14,
12 | textAlign: 'center',
13 | },
14 | rightAction: {
15 | alignItems: 'center',
16 | flex: 1,
17 | justifyContent: 'center',
18 | },
19 | });
20 |
21 | export default styles;
22 |
--------------------------------------------------------------------------------
/ios/Lisk/Images.xcassets/quick_action_send.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images": [
3 | {
4 | "filename": "Send.png",
5 | "idiom": "universal",
6 | "scale": "1x"
7 | },
8 | {
9 | "filename": "Send@2x.png",
10 | "idiom": "universal",
11 | "scale": "2x"
12 | },
13 | {
14 | "filename": "Send@3x.png",
15 | "idiom": "universal",
16 | "scale": "3x"
17 | }
18 | ],
19 | "info": {
20 | "author": "xcode",
21 | "version": 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/components/screens/PrivacyPolicy/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View } from 'react-native';
3 | import { WebView } from 'react-native-webview';
4 | import URLs from 'constants/URLs';
5 |
6 | export default function PrivacyPolicy() {
7 | return (
8 |
9 |
14 |
15 | );
16 | }
17 |
--------------------------------------------------------------------------------
/ios/.xcode.env:
--------------------------------------------------------------------------------
1 | # This `.xcode.env` file is versioned and is used to source the environment
2 | # used when running script phases inside Xcode.
3 | # To customize your local environment, you can create an `.xcode.env.local`
4 | # file that is not versioned.
5 |
6 | # NODE_BINARY variable contains the PATH to the node executable.
7 | #
8 | # Customize the NODE_BINARY variable here.
9 | # For example, to use nvm with brew, add the following line
10 | # . "$(brew --prefix nvm)/nvm.sh" --no-use
11 | export NODE_BINARY=$(command -v node)
12 |
--------------------------------------------------------------------------------
/ios/Lisk/Images.xcassets/quick_action_discreet.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images": [
3 | {
4 | "filename": "discreet.png",
5 | "idiom": "universal",
6 | "scale": "1x"
7 | },
8 | {
9 | "filename": "discreet-1.png",
10 | "idiom": "universal",
11 | "scale": "2x"
12 | },
13 | {
14 | "filename": "discreet-2.png",
15 | "idiom": "universal",
16 | "scale": "3x"
17 | }
18 | ],
19 | "info": {
20 | "author": "xcode",
21 | "version": 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/ios/Lisk/Images.xcassets/quick_action_request.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images": [
3 | {
4 | "filename": "Request.png",
5 | "idiom": "universal",
6 | "scale": "1x"
7 | },
8 | {
9 | "filename": "Request@2x.png",
10 | "idiom": "universal",
11 | "scale": "2x"
12 | },
13 | {
14 | "filename": "Request@3x.png",
15 | "idiom": "universal",
16 | "scale": "3x"
17 | }
18 | ],
19 | "info": {
20 | "author": "xcode",
21 | "version": 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/components/shared/Stepper/styles.js:
--------------------------------------------------------------------------------
1 | import { colors, themes } from 'constants/styleGuide';
2 |
3 | export default () => ({
4 | common: {
5 | flex: {
6 | flex: 1,
7 | },
8 | container: {
9 | flexDirection: 'row',
10 | alignItems: 'center',
11 | paddingRight: 20,
12 | },
13 | },
14 | [themes.light]: {
15 | step: {
16 | color: colors.light.black,
17 | },
18 | },
19 | [themes.dark]: {
20 | step: {
21 | color: colors.dark.white,
22 | },
23 | },
24 | });
25 |
--------------------------------------------------------------------------------
/src/modules/Accounts/components/TokensScreen/styles.js:
--------------------------------------------------------------------------------
1 | import { colors, themes, boxes } from 'constants/styleGuide';
2 |
3 | export default {
4 | common: {
5 | container: {
6 | flex: 1,
7 | },
8 | tokenListContainer: {
9 | padding: boxes.boxPadding,
10 | },
11 | },
12 | [themes.light]: {
13 | container: {
14 | backgroundColor: colors.light.white,
15 | },
16 | },
17 | [themes.dark]: {
18 | container: {
19 | backgroundColor: colors.dark.mainBg,
20 | },
21 | },
22 | };
23 |
--------------------------------------------------------------------------------
/src/modules/Auth/mocks/index.js:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line import/no-extraneous-dependencies
2 | import { rest } from 'msw';
3 |
4 | import { API_VERSION } from 'utilities/api/constants';
5 | import { mockAuth } from '../__fixtures__';
6 |
7 | export const getAuthMockHandler = rest.get(`*/api/${API_VERSION}/auth`, async (req, res, ctx) => {
8 | const address = req.url.searchParams.get('address');
9 |
10 | const response = { data: mockAuth, meta: { address } };
11 |
12 | return res(ctx.delay(20), ctx.json(response));
13 | });
14 |
--------------------------------------------------------------------------------
/ios/Lisk/Images.xcassets/SplashIcon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images": [
3 | {
4 | "filename": "lisk-full-white.png",
5 | "idiom": "universal",
6 | "scale": "1x"
7 | },
8 | {
9 | "filename": "lisk-full-white@2x.png",
10 | "idiom": "universal",
11 | "scale": "2x"
12 | },
13 | {
14 | "filename": "lisk-full-white@3x.png",
15 | "idiom": "universal",
16 | "scale": "3x"
17 | }
18 | ],
19 | "info": {
20 | "author": "xcode",
21 | "version": 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/components/shared/Slider/components/SliderPagination.styles.js:
--------------------------------------------------------------------------------
1 | export default function getSliderPaginationStyles() {
2 | return {
3 | common: {
4 | container: {
5 | position: 'absolute',
6 | bottom: 0,
7 | flexDirection: 'row',
8 | width: '100%',
9 | alignItems: 'center',
10 | justifyContent: 'center',
11 | },
12 | dot: {
13 | width: 12,
14 | height: 8,
15 | borderRadius: 6,
16 | marginHorizontal: 3,
17 | },
18 | },
19 | };
20 | }
21 |
--------------------------------------------------------------------------------
/ios/Lisk/Images.xcassets/LiskTypographyIcon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images": [
3 | {
4 | "filename": "liskLogoWhite@1x.png",
5 | "idiom": "universal",
6 | "scale": "1x"
7 | },
8 | {
9 | "filename": "liskLogoWhite@2x.png",
10 | "idiom": "universal",
11 | "scale": "2x"
12 | },
13 | {
14 | "filename": "liskLogoWhite@3x.png",
15 | "idiom": "universal",
16 | "scale": "3x"
17 | }
18 | ],
19 | "info": {
20 | "author": "xcode",
21 | "version": 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/navigation/navigation.linking.js:
--------------------------------------------------------------------------------
1 | import { getPathFromState } from '@react-navigation/core';
2 |
3 | import { getNavigationStateFromPath } from './navigation.utils';
4 |
5 | const navigationLinkingConfig = {
6 | screens: {
7 | Send: 'wallet',
8 | NotFound: '*',
9 | Error: 'error',
10 | },
11 | };
12 |
13 | const navigationLinking = {
14 | prefixes: ['lisk://'],
15 | config: navigationLinkingConfig,
16 | getStateFromPath: getNavigationStateFromPath,
17 | getPathFromState,
18 | };
19 |
20 | export default navigationLinking;
21 |
--------------------------------------------------------------------------------
/android/app/src/main/res/layout/launch_screen.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
14 |
15 |
--------------------------------------------------------------------------------
/lsk.config.js:
--------------------------------------------------------------------------------
1 | const isTestnet = process.env.NETWORK === 'testnet';
2 |
3 | export default {
4 | isTestnet,
5 | serviceURL: 'https://service.lisk.com/api',
6 | testnetURL: 'http://165.227.246.146:9901/api',
7 | networkID: '4c09e6a781fc4c7bdb936ee815de8f94190f8a7519becd9de2081832be309a99',
8 | testnetNetworkID: '15f0dacc1060e91818224a94286b13aa04279c640bd5d6f193182031d133df7c',
9 | requestOptions: {
10 | method: 'GET',
11 | headers: {
12 | Accept: 'application/json',
13 | 'Content-Type': 'application/json',
14 | },
15 | },
16 | };
17 |
--------------------------------------------------------------------------------
/src/modules/Accounts/hooks/useCurrentAccount.js:
--------------------------------------------------------------------------------
1 | import { useSelector, useDispatch } from 'react-redux';
2 | import { setCurrentAccount } from '../store/actions';
3 | import { selectCurrentAccount } from '../store/selectors';
4 |
5 | // eslint-disable-next-line
6 | export function useCurrentAccount() {
7 | const dispatch = useDispatch();
8 | const setAccount = (accountSchema) => {
9 | dispatch(setCurrentAccount(accountSchema));
10 | };
11 | const currentAccount = useSelector(selectCurrentAccount);
12 |
13 | return [currentAccount, setAccount];
14 | }
15 |
--------------------------------------------------------------------------------
/e2e/utils/testConstants.js:
--------------------------------------------------------------------------------
1 | export default {
2 | secretRecoveryPhrase:
3 | 'devote mouse hair cereal maximum trigger puppy blossom adult sort ticket neither',
4 | sideChainRecoveryPhrase:
5 | 'where glow borrow found path hero produce gasp entry street recycle rich prepare carry almost parrot maze circle nuclear smile unveil captain assist together',
6 | address: 'lskv6v53emsaen6cwbbk226wusdpa6ojdonunka4x',
7 | newAddress: 'lskujedwe2nxoeehxwpztuateojsjfv6oge2ktefe',
8 | emptyAccount: '',
9 | password: 'Password1!',
10 | accountName: 'lisker',
11 | };
12 |
--------------------------------------------------------------------------------
/src/modules/Settings/components/BackupRecoveryPhrase/BackupRecoveryPhrase.styles.js:
--------------------------------------------------------------------------------
1 | import { themes, colors, boxes } from 'constants/styleGuide';
2 |
3 | export default () => ({
4 | common: {
5 | container: {
6 | flex: 1,
7 | },
8 | decryptRecoveryPhrase: {
9 | padding: boxes.boxPadding,
10 | },
11 | },
12 | [themes.light]: {
13 | container: {
14 | backgroundColor: colors.light.white,
15 | },
16 | },
17 | [themes.dark]: {
18 | container: {
19 | backgroundColor: colors.dark.mainBg,
20 | },
21 | },
22 | });
23 |
--------------------------------------------------------------------------------
/src/store/index.js:
--------------------------------------------------------------------------------
1 | import { createStore, combineReducers, applyMiddleware } from 'redux';
2 | import { composeWithDevTools } from 'redux-devtools-extension';
3 | import { persistStore } from 'redux-persist';
4 | import * as reducers from './reducers';
5 | import middleWares from './middlewares';
6 |
7 | export * from './selectors';
8 |
9 | const rootReducer = combineReducers(reducers);
10 | const store = createStore(rootReducer, composeWithDevTools(applyMiddleware(...middleWares)));
11 | export const persistedStore = persistStore(store);
12 |
13 | export default store;
14 |
--------------------------------------------------------------------------------
/patches/react-native-app-settings+2.0.1.patch:
--------------------------------------------------------------------------------
1 | diff --git a/node_modules/react-native-app-settings/android/build.gradle b/node_modules/react-native-app-settings/android/build.gradle
2 | index 849e79a..f87bfa7 100644
3 | --- a/node_modules/react-native-app-settings/android/build.gradle
4 | +++ b/node_modules/react-native-app-settings/android/build.gradle
5 | @@ -31,6 +31,6 @@ repositories {
6 | }
7 |
8 | dependencies {
9 | - compile 'com.facebook.react:react-native:+'
10 | + implementation 'com.facebook.react:react-native:+'
11 | }
12 |
13 | \ No newline at end of file
14 |
--------------------------------------------------------------------------------
/patches/react-native-blur-overlay+1.0.7.patch:
--------------------------------------------------------------------------------
1 | diff --git a/node_modules/react-native-blur-overlay/android/build.gradle b/node_modules/react-native-blur-overlay/android/build.gradle
2 | index 8c6e8e8..f9aad7c 100644
3 | --- a/node_modules/react-native-blur-overlay/android/build.gradle
4 | +++ b/node_modules/react-native-blur-overlay/android/build.gradle
5 | @@ -31,6 +31,5 @@ repositories {
6 | }
7 |
8 | dependencies {
9 | - compile 'com.facebook.react:react-native:+'
10 | + implementation 'com.facebook.react:react-native:+'
11 | }
12 | -
13 | \ No newline at end of file
14 |
--------------------------------------------------------------------------------
/src/modules/Auth/utils/documentPicker.js:
--------------------------------------------------------------------------------
1 | import DocumentPicker from 'react-native-document-picker';
2 | import RNFS from 'react-native-fs';
3 |
4 | export const selectEncryptedFile = async (onError) => {
5 | try {
6 | const file = await DocumentPicker.pickSingle({
7 | type: DocumentPicker.types.allFiles,
8 | });
9 | if (file.type !== 'application/json') {
10 | throw new Error('Invalid file type');
11 | }
12 | const encryptedData = await RNFS.readFile(file.uri);
13 | return encryptedData;
14 | } catch (error) {
15 | return onError();
16 | }
17 | };
18 |
--------------------------------------------------------------------------------
/src/modules/Auth/utils/getKeyFromArgon.js:
--------------------------------------------------------------------------------
1 | import { NativeModules } from 'react-native';
2 |
3 | const { RNArgon2 } = NativeModules;
4 |
5 | export const getKeyFromPasswordWithArgon2 = async (options) => {
6 | const { parallelism, password, iterations, memory, hashLength } = options;
7 | const salt = options.salt.toString('hex');
8 |
9 | const result = await RNArgon2.argon2(password, salt, {
10 | iterations,
11 | memory,
12 | parallelism,
13 | hashLength,
14 | mode: 'argon2id',
15 | });
16 | const key = Buffer.from(result.rawHash, 'hex');
17 | return key;
18 | };
19 |
--------------------------------------------------------------------------------
/libs/wcm/hooks/useEvents.js:
--------------------------------------------------------------------------------
1 | import { useContext } from 'react';
2 | import ConnectionContext from '../context/connectionContext';
3 |
4 | export const useEvents = () => {
5 | const { events, setEvents } = useContext(ConnectionContext);
6 |
7 | const pushEvent = (event) => {
8 | setEvents((prevEvents) => [...prevEvents, event]);
9 | };
10 |
11 | const removeEvent = (event) => {
12 | const newEvents = events.filter((e) => e.name !== event.name);
13 | setEvents(newEvents);
14 | };
15 |
16 | return {
17 | events,
18 | removeEvent,
19 | pushEvent,
20 | };
21 | };
22 |
--------------------------------------------------------------------------------
/src/components/navigation/NavigationSafeAreaView/styles.js:
--------------------------------------------------------------------------------
1 | import { themes, colors } from 'constants/styleGuide';
2 |
3 | export default function getNavigationSafeAreaViewStyles(tabBarHeight) {
4 | return {
5 | common: {
6 | container: {
7 | flex: 1,
8 | paddingBottom: tabBarHeight,
9 | },
10 | },
11 | [themes.light]: {
12 | container: {
13 | backgroundColor: colors.light.white,
14 | },
15 | },
16 | [themes.dark]: {
17 | container: {
18 | backgroundColor: colors.dark.mainBg,
19 | },
20 | },
21 | };
22 | }
23 |
--------------------------------------------------------------------------------
/src/components/screens/NotFoundScreen/NotFoundScreen.styles.js:
--------------------------------------------------------------------------------
1 | import { themes, colors } from 'constants/styleGuide';
2 | export default function getNotFoundStyles() {
3 | return {
4 | common: {
5 | container: {
6 | flex: 1,
7 | },
8 | illustration: {
9 | marginBottom: 8,
10 | },
11 | },
12 | [themes.light]: {
13 | container: {
14 | backgroundColor: colors.light.white,
15 | },
16 | },
17 | [themes.dark]: {
18 | container: {
19 | backgroundColor: colors.dark.black,
20 | },
21 | },
22 | };
23 | }
24 |
--------------------------------------------------------------------------------
/src/modules/Accounts/components/AccountHome/AccountHome.styles.js:
--------------------------------------------------------------------------------
1 | import { boxes } from 'constants/styleGuide';
2 |
3 | export default () => ({
4 | common: {
5 | flex: {
6 | flex: 1,
7 | },
8 | body: {
9 | padding: boxes.boxPadding,
10 | },
11 | topContainer: {
12 | marginLeft: 20,
13 | marginRight: 60,
14 | marginTop: 10,
15 | },
16 | discreteContainer: {
17 | marginRight: 10,
18 | },
19 | row: {
20 | flexDirection: 'row',
21 | },
22 | alignItemsCenter: {
23 | alignItems: 'center',
24 | },
25 | },
26 | });
27 |
--------------------------------------------------------------------------------
/src/modules/SendToken/hooks/useValidateFeeBalance.js:
--------------------------------------------------------------------------------
1 | import { useAccountTokenBalancesQuery } from '../../Accounts/api/useAccountTokenBalancesQuery';
2 |
3 | export const useValidateFeeBalance = (address, customFeeTokenId) => {
4 | const tokenBalances = useAccountTokenBalancesQuery(address);
5 |
6 | const foundTokenBalance = tokenBalances.data?.data?.some(
7 | (tokenBalance) =>
8 | tokenBalance?.tokenID === customFeeTokenId &&
9 | BigInt(tokenBalance?.availableBalance || 0) > BigInt(0)
10 | );
11 |
12 | return {
13 | hasSufficientBalanceForFee: !!foundTokenBalance,
14 | };
15 | };
16 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ['module:metro-react-native-babel-preset'],
3 | plugins: [
4 | '@babel/plugin-transform-react-jsx-source',
5 | ['@babel/plugin-proposal-decorators', { legacy: true }],
6 | 'transform-class-properties',
7 | '@babel/plugin-proposal-optional-chaining',
8 | '@babel/plugin-proposal-nullish-coalescing-operator',
9 | [
10 | 'module-resolver',
11 | {
12 | root: ['./src'],
13 | alias: {
14 | locales: './locales',
15 | },
16 | },
17 | ],
18 | 'react-native-reanimated/plugin',
19 | ],
20 | };
21 |
--------------------------------------------------------------------------------
/src/components/shared/DiscreteModeComponent/styles.js:
--------------------------------------------------------------------------------
1 | export default () => ({
2 | common: {
3 | container: {
4 | width: '100%',
5 | textAlign: 'right',
6 | justifyContent: 'flex-end',
7 | position: 'relative',
8 | maxHeight: 20,
9 | },
10 | blurSmall: {
11 | width: 140,
12 | height: 26,
13 | marginRight: -15,
14 | },
15 | blurMedium: {
16 | width: 140,
17 | height: 26,
18 | marginRight: -10,
19 | },
20 | blurBig: {
21 | width: 140,
22 | height: 26,
23 | marginRight: -10,
24 | },
25 | },
26 | });
27 |
--------------------------------------------------------------------------------
/src/utilities/api/APIClient.test.js:
--------------------------------------------------------------------------------
1 | import client from './APIClient';
2 |
3 | jest.useRealTimers();
4 |
5 | describe('APIClient', () => {
6 | it.skip('should work', (done) => {
7 | client.socket.on('hello', (arg) => {
8 | expect(arg).toBe('world');
9 | done();
10 | });
11 | client.socket.emit('hello', 'world');
12 | });
13 |
14 | it.skip('should work (with ack)', (done) => {
15 | client.socket.on('hi', (cb) => {
16 | cb('hola');
17 | });
18 | client.socket.emit('hi', (arg) => {
19 | expect(arg).toBe('hola');
20 | done();
21 | });
22 | });
23 | });
24 |
--------------------------------------------------------------------------------
/patches/react-native-tcp+4.0.0.patch:
--------------------------------------------------------------------------------
1 | diff --git a/node_modules/react-native-tcp/android/build.gradle b/node_modules/react-native-tcp/android/build.gradle
2 | index c582eb7..5785289 100644
3 | --- a/node_modules/react-native-tcp/android/build.gradle
4 | +++ b/node_modules/react-native-tcp/android/build.gradle
5 | @@ -44,6 +44,6 @@ repositories {
6 | }
7 |
8 | dependencies {
9 | - compile 'com.facebook.react:react-native:+'
10 | - compile 'com.koushikdutta.async:androidasync:2.1.6'
11 | + implementation 'com.facebook.react:react-native:+'
12 | + implementation 'com.koushikdutta.async:androidasync:2.1.6'
13 | }
14 |
--------------------------------------------------------------------------------
/src/components/shared/Checkbox/styles.js:
--------------------------------------------------------------------------------
1 | import { colors } from 'constants/styleGuide';
2 |
3 | export default {
4 | common: {
5 | container: {
6 | flexDirection: 'row',
7 | alignItems: 'center',
8 | marginVertical: 5,
9 | },
10 | checkbox: {
11 | alignItems: 'center',
12 | justifyContent: 'center',
13 | borderWidth: 1,
14 | borderColor: colors.light.smoothGray,
15 | height: 20,
16 | width: 20,
17 | borderRadius: 4,
18 | marginRight: 10,
19 | },
20 | active: {
21 | borderColor: colors.light.ultramarineBlue,
22 | },
23 | },
24 | };
25 |
--------------------------------------------------------------------------------
/src/modules/Accounts/components/EditAccountScreen/styles.js:
--------------------------------------------------------------------------------
1 | import { colors, themes, boxes } from 'constants/styleGuide';
2 |
3 | export default function getEditAccountScreenStyles() {
4 | return {
5 | common: {
6 | container: {
7 | flex: 1,
8 | },
9 | formContainer: {
10 | padding: boxes.boxPadding,
11 | },
12 | },
13 | [themes.light]: {
14 | container: {
15 | backgroundColor: colors.dark.white,
16 | },
17 | },
18 | [themes.dark]: {
19 | container: {
20 | backgroundColor: colors.dark.black,
21 | },
22 | },
23 | };
24 | }
25 |
--------------------------------------------------------------------------------
/src/modules/Auth/utils/decryptAccount.js:
--------------------------------------------------------------------------------
1 | import { cryptography } from '@liskhq/lisk-client';
2 | import { getKeyFromPasswordWithArgon2 } from './getKeyFromArgon';
3 |
4 | export const decryptAccount = async (crypto, password) => {
5 | try {
6 | const { encrypt } = cryptography;
7 | const plainText = await encrypt.decryptMessageWithPassword(crypto, password, 'utf-8', {
8 | getKey: getKeyFromPasswordWithArgon2,
9 | });
10 | const { recoveryPhrase, privateKey } = JSON.parse(plainText);
11 | return { recoveryPhrase, privateKey };
12 | } catch (error) {
13 | throw new Error(error);
14 | }
15 | };
16 |
--------------------------------------------------------------------------------
/src/modules/Accounts/components/DeleteAccountScreen/styles.js:
--------------------------------------------------------------------------------
1 | import { colors, themes, boxes } from 'constants/styleGuide';
2 |
3 | export default function getDeleteAccountScreenStyles() {
4 | return {
5 | common: {
6 | container: {
7 | flex: 1,
8 | },
9 | formContainer: {
10 | padding: boxes.boxPadding,
11 | },
12 | },
13 | [themes.light]: {
14 | container: {
15 | backgroundColor: colors.dark.white,
16 | },
17 | },
18 | [themes.dark]: {
19 | container: {
20 | backgroundColor: colors.dark.black,
21 | },
22 | },
23 | };
24 | }
25 |
--------------------------------------------------------------------------------
/src/modules/Accounts/components/TokenList/components/TokenListSkeleton.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View } from 'react-native';
3 |
4 | import TokenRowSkeleton from '../../TokenRow/components/TokenRowSkeleton';
5 |
6 | /**
7 | * Skeleton UI placeholder for TokenList loading state.
8 | */
9 | export default function TokenListSkeleton() {
10 | const skeletonsCount = 2;
11 |
12 | return (
13 |
14 | {[...new Array(skeletonsCount)].map((_, index) => (
15 |
16 | ))}
17 |
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/src/modules/BlockchainApplication/hooks/useExternalApplicationConnectedAccounts.js:
--------------------------------------------------------------------------------
1 | import { useAccounts } from 'modules/Accounts/hooks/useAccounts';
2 |
3 | export function useExternalApplicationConnectedAccounts(namespaces) {
4 | const { accounts } = useAccounts();
5 |
6 | const connectionAccountsPubKeys = namespaces?.lisk.accounts.map((account) => {
7 | const parts = account.split(':');
8 | return parts[parts.length - 1];
9 | });
10 |
11 | const connectionAccounts = accounts.filter((account) =>
12 | connectionAccountsPubKeys.includes(account.metadata.pubkey)
13 | );
14 |
15 | return connectionAccounts;
16 | }
17 |
--------------------------------------------------------------------------------
/src/navigation/navigation.constants.js:
--------------------------------------------------------------------------------
1 | import { TOKEN_TRANSFER_VALIDATION_SCHEMA } from 'modules/Transactions/utils/constants';
2 |
3 | export const WHITE_LISTED_DEEP_LINKS = [
4 | {
5 | pathRegex: /^\/\/wallet\/?$/,
6 | validationSchema: TOKEN_TRANSFER_VALIDATION_SCHEMA,
7 | paramsTransformer: (queryParams) => {
8 | let result = queryParams;
9 |
10 | if (!queryParams.amount) {
11 | result = { ...result, amount: '0' };
12 | }
13 |
14 | if (!queryParams.reference) {
15 | result = { ...result, reference: '' };
16 | }
17 |
18 | return result;
19 | },
20 | },
21 | ];
22 |
--------------------------------------------------------------------------------
/src/components/shared/headerTitle/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Animated } from 'react-native';
3 | import { translate } from 'react-i18next';
4 | import withTheme from 'components/shared/withTheme';
5 | import getStyles from './styles';
6 |
7 | const HeaderTitle = ({ styles, t, children, ...rest }) => (
8 |
15 | {t(children)}
16 |
17 | );
18 |
19 | export default withTheme(translate()(HeaderTitle), getStyles());
20 |
--------------------------------------------------------------------------------
/src/hooks/useDebounce.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from 'react';
2 |
3 | /**
4 | * Sets a debounced value to value (passed in) after the specified delay.
5 | * @param value - Value to debounce.
6 | * @param delay - Timeout to delay the value setup.
7 | */
8 | export function useDebounce(value, delay) {
9 | const [debouncedValue, setDebouncedValue] = useState(value);
10 |
11 | useEffect(() => {
12 | const handler = setTimeout(() => {
13 | setDebouncedValue(value);
14 | }, delay);
15 |
16 | return () => {
17 | clearTimeout(handler);
18 | };
19 | }, [value, delay]);
20 |
21 | return debouncedValue;
22 | }
23 |
--------------------------------------------------------------------------------
/src/modules/Accounts/components/AccountDetailsScreen/AccountDetailsScreen.styles.js:
--------------------------------------------------------------------------------
1 | import { themes, colors, boxes } from 'constants/styleGuide';
2 |
3 | export default function getAccountDetailsScreenStyles() {
4 | return {
5 | common: {
6 | flex: {
7 | flex: 1,
8 | },
9 | container: {
10 | padding: boxes.boxPadding,
11 | },
12 | },
13 | [themes.light]: {
14 | container: {
15 | backgroundColor: colors.light.white,
16 | },
17 | },
18 | [themes.dark]: {
19 | container: {
20 | backgroundColor: colors.dark.mainBg,
21 | },
22 | },
23 | };
24 | }
25 |
--------------------------------------------------------------------------------
/src/modules/SendToken/components/SendTokenSkeleton/SendTokenSkeleton.styles.js:
--------------------------------------------------------------------------------
1 | import { boxes } from 'constants/styleGuide';
2 |
3 | export function getSendTokenSkeletonStyles() {
4 | return {
5 | common: {
6 | container: {
7 | paddingLeft: boxes.boxPadding,
8 | paddingRight: boxes.boxPadding,
9 | },
10 | progressBarContainer: {
11 | width: '100%',
12 | marginBottom: 40,
13 | },
14 | fieldLabelContainer: {
15 | marginBottom: 8,
16 | },
17 | fieldInputContainer: {
18 | width: '100%',
19 | marginBottom: 24,
20 | },
21 | },
22 | };
23 | }
24 |
--------------------------------------------------------------------------------
/src/components/shared/headerTitle/styles.js:
--------------------------------------------------------------------------------
1 | import { fonts, themes, colors } from 'constants/styleGuide';
2 | import { deviceType } from 'utilities/device';
3 |
4 | export default () => ({
5 | common: {
6 | main: {
7 | flex: 1,
8 | fontSize: 16,
9 | textAlign: 'center',
10 | marginHorizontal: 16,
11 | marginTop: deviceType() === 'iOSx' ? -10 : -5,
12 | fontFamily: fonts.family.heading,
13 | },
14 | },
15 | [themes.light]: {
16 | main: {
17 | color: colors.light.black,
18 | },
19 | },
20 | [themes.dark]: {
21 | main: {
22 | color: colors.dark.white,
23 | },
24 | },
25 | });
26 |
--------------------------------------------------------------------------------
/src/modules/BlockchainApplication/api/useApplicationsFullDataQuery.js:
--------------------------------------------------------------------------------
1 | import { useApplicationsMetaQuery } from './useApplicationsMetaQuery';
2 | import { transformApplicationsMetaQueryResult } from '../utils';
3 |
4 | /**
5 | * Fetches off-chain and on-chain applications data and merge them together.
6 | * @returns {Object} Available blockchain applications on and off-chain data.
7 | */
8 | export function useApplicationsFullDataQuery({ config: customConfig = {}, options = {} } = {}) {
9 | return useApplicationsMetaQuery({
10 | config: { transformResult: transformApplicationsMetaQueryResult, ...customConfig },
11 | options,
12 | });
13 | }
14 |
--------------------------------------------------------------------------------
/src/modules/Auth/components/MigrateToL2Screen/styles.js:
--------------------------------------------------------------------------------
1 | import { colors, themes, boxes } from 'constants/styleGuide';
2 |
3 | export default function getAccountsManagerScreenStyles() {
4 | return {
5 | common: {
6 | container: {
7 | flex: 1,
8 | padding: boxes.boxPadding,
9 | },
10 | migrateToL2Card: {
11 | marginBottom: 16,
12 | },
13 | },
14 | [themes.light]: {
15 | container: {
16 | backgroundColor: colors.dark.white,
17 | },
18 | },
19 | [themes.dark]: {
20 | container: {
21 | backgroundColor: colors.dark.black,
22 | },
23 | },
24 | };
25 | }
26 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
13 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/components/shared/Stepper/StepProgress.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View } from 'react-native';
3 | import { B, P } from '../toolBox/typography';
4 | import withTheme from '../withTheme';
5 | import getStyles from './styles';
6 |
7 | const StepProgress = ({ styles, currentIndex, length }) => {
8 | return (
9 |
10 | Step
11 | {currentIndex}
12 | /
13 | {length}
14 |
15 | );
16 | };
17 |
18 | export default withTheme(StepProgress, getStyles());
19 |
--------------------------------------------------------------------------------
/src/modules/Auth/components/DecryptRecoveryPhraseScreen/DecryptRecoveryPhraseScreen.styles.js:
--------------------------------------------------------------------------------
1 | import { colors, themes, boxes } from 'constants/styleGuide';
2 |
3 | export default function getDecryptRecoveryPhraseScreenStyles() {
4 | return {
5 | common: {
6 | container: {
7 | flex: 1,
8 | },
9 | form: {
10 | padding: boxes.boxPadding,
11 | },
12 | },
13 | [themes.light]: {
14 | container: {
15 | backgroundColor: colors.dark.white,
16 | },
17 | },
18 |
19 | [themes.dark]: {
20 | container: {
21 | backgroundColor: colors.dark.black,
22 | },
23 | },
24 | };
25 | }
26 |
--------------------------------------------------------------------------------
/src/modules/Transactions/components/TransactionTimestamp/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import moment from 'moment';
3 |
4 | import FormattedDate from 'components/shared/formattedDate';
5 | import { P } from 'components/shared/toolBox/typography';
6 |
7 | export default function TransactionTimestamp({
8 | timestamp,
9 | styles,
10 | format = 'MMM D, YYYY LTS',
11 | transformer = moment.unix,
12 | }) {
13 | return (
14 |
20 | {timestamp}
21 |
22 | );
23 | }
24 |
--------------------------------------------------------------------------------
/libs/wcm/constants/lifeCycle.js:
--------------------------------------------------------------------------------
1 | export const STATUS = {
2 | SUCCESS: 'SUCCESS',
3 | FAILURE: 'FAILURE',
4 | };
5 |
6 | export const ACTIONS = {
7 | APPROVE: 'APPROVE',
8 | REJECT: 'REJECT',
9 | };
10 |
11 | export const EVENTS = {
12 | SESSION_PROPOSAL: 'session_proposal',
13 | SESSION_REQUEST: 'session_request',
14 | SESSION_PING: 'session_ping',
15 | SESSION_EVENT: 'session_event',
16 | SESSION_UPDATE: 'session_update',
17 | SESSION_DELETE: 'session_delete',
18 | };
19 |
20 | export const ERROR_CASES = {
21 | USER_DISCONNECTED: 'USER_DISCONNECTED',
22 | INVALID_METHOD: 'INVALID_METHOD',
23 | USER_REJECTED_METHODS: 'USER_REJECTED_METHODS',
24 | };
25 |
--------------------------------------------------------------------------------
/src/modules/Auth/components/AccountsManagerScreen/styles.js:
--------------------------------------------------------------------------------
1 | import { colors, themes, boxes } from 'constants/styleGuide';
2 |
3 | export default function getAccountsManagerScreenStyles() {
4 | return {
5 | common: {
6 | container: {
7 | flex: 1,
8 | padding: boxes.boxPadding,
9 | },
10 | headerLogoContainer: {
11 | marginVertical: 40,
12 | },
13 | },
14 | [themes.light]: {
15 | container: {
16 | backgroundColor: colors.dark.white,
17 | },
18 | },
19 |
20 | [themes.dark]: {
21 | container: {
22 | backgroundColor: colors.dark.black,
23 | },
24 | },
25 | };
26 | }
27 |
--------------------------------------------------------------------------------
/src/assets/animations/LiskLogoAnimation.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Lottie from 'lottie-react-native';
3 |
4 | export default function LiskLogoAnimation({ variant = 'blue', style, ...props }) {
5 | let src;
6 |
7 | switch (variant) {
8 | case 'blue':
9 | src = require('assets/animations/lisk-logo-animation-blue.json');
10 | break;
11 |
12 | case 'white':
13 | src = require('assets/animations/lisk-logo-animation-white.json');
14 | break;
15 |
16 | default:
17 | break;
18 | }
19 |
20 | if (!src) {
21 | return null;
22 | }
23 |
24 | return ;
25 | }
26 |
--------------------------------------------------------------------------------
/src/assets/svgs/CircleSvg.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Svg, Path } from 'react-native-svg';
3 |
4 | import colors from 'constants/styleGuide/colors';
5 |
6 | export default function CircleSvg({
7 | color = colors.light.blueGray,
8 | height = 24,
9 | width = 24,
10 | style,
11 | }) {
12 | return (
13 |
21 | );
22 | }
23 |
--------------------------------------------------------------------------------
/src/modules/BlockchainApplication/components/AddApplicationScreen/AddApplicationScreen.styles.js:
--------------------------------------------------------------------------------
1 | import { themes, colors } from 'constants/styleGuide';
2 |
3 | export default function getAddApplicationStyles() {
4 | return {
5 | common: {
6 | wrapper: {
7 | flex: 1,
8 | },
9 | applicationsListContainer: {
10 | paddingLeft: 16,
11 | paddingRight: 16,
12 | },
13 | },
14 | [themes.light]: {
15 | wrapper: {
16 | backgroundColor: colors.light.white,
17 | },
18 | },
19 |
20 | [themes.dark]: {
21 | wrapper: {
22 | backgroundColor: colors.dark.mainBg,
23 | },
24 | },
25 | };
26 | }
27 |
--------------------------------------------------------------------------------
/src/assets/svgs/MoonSvg.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Svg, Path } from 'react-native-svg';
3 |
4 | export default ({ color, style }) => (
5 |
12 | );
13 |
--------------------------------------------------------------------------------
/src/modules/BlockchainApplication/__fixtures__/mockApplications.js:
--------------------------------------------------------------------------------
1 | import { mockDefaultApplication } from './mockDefaultApplication';
2 |
3 | export const mockApplications = [
4 | mockDefaultApplication,
5 | ...[...new Array(100)].map((_, index) => ({
6 | chainName: `app_mainchain_${index}`,
7 | chainID: index.toString(16).padStart(8, '0'), // 8-digit hex representation
8 | status: 'active',
9 | address: 'lskguo9kqnea2zsfo3a6qppozsxsg92nuuma3p7ad',
10 | lastCertificateHeight: 1460,
11 | lastUpdated: 1689782730,
12 | escrow: [
13 | {
14 | tokenID: '0400000000000000',
15 | amount: '100010000000',
16 | },
17 | ],
18 | })),
19 | ];
20 |
--------------------------------------------------------------------------------
/src/components/shared/ObjectViewer/ObjectViewer.styles.js:
--------------------------------------------------------------------------------
1 | import { themes, colors, fonts } from 'constants/styleGuide';
2 |
3 | export default function getStyles() {
4 | return {
5 | common: {
6 | container: { flexDirection: 'row', flex: 1, padding: 5, marginLeft: 10 },
7 | text: {
8 | fontFamily: fonts.family.context,
9 | fontSize: fonts.size.small,
10 | },
11 | flex: {
12 | flex: 1,
13 | },
14 | },
15 | [themes.light]: {
16 | text: {
17 | color: colors.light.zodiacBlue,
18 | },
19 | },
20 | [themes.dark]: {
21 | text: {
22 | color: colors.dark.white,
23 | },
24 | },
25 | };
26 | }
27 |
--------------------------------------------------------------------------------
/src/modules/Auth/utils/recoveryPhrase.test.js:
--------------------------------------------------------------------------------
1 | import { toSecureRecoveryPhraseString } from './recoveryPhrase';
2 |
3 | describe('toSecureRecoveryPhraseString', () => {
4 | it('should return a secured recovery phrase', () => {
5 | const input = 'attract squeeze option inflict dynamic';
6 | const expectedOutput = '****** ****** ****** ****** ******';
7 | expect(toSecureRecoveryPhraseString(input)).toBe(expectedOutput);
8 | });
9 |
10 | it('should handle an empty string', () => {
11 | expect(toSecureRecoveryPhraseString('')).toBe('');
12 | });
13 |
14 | it('should handle a single word', () => {
15 | expect(toSecureRecoveryPhraseString('singleword')).toBe('******');
16 | });
17 | });
18 |
--------------------------------------------------------------------------------
/services/msw/handlers.js:
--------------------------------------------------------------------------------
1 | import * as authHandlers from 'modules/Auth/mocks';
2 | import * as sendTokenHandlers from 'modules/SendToken/mocks';
3 | import * as transactionHandlers from 'modules/Transactions/mocks';
4 | import * as applicationsHandlers from 'modules/BlockchainApplication/mocks';
5 | import * as accountHandlers from 'modules/Accounts/mocks';
6 | import * as networkHandlers from 'modules/Network/mocks';
7 | import * as generalApiHandlers from 'utilities/api/mocks';
8 |
9 | export const mswHandlers = {
10 | ...sendTokenHandlers,
11 | ...transactionHandlers,
12 | ...generalApiHandlers,
13 | ...applicationsHandlers,
14 | ...networkHandlers,
15 | ...accountHandlers,
16 | ...authHandlers,
17 | };
18 |
--------------------------------------------------------------------------------
/src/components/screens/LoadingFallbackScreen/LoadingFallbackScreen.styles.js:
--------------------------------------------------------------------------------
1 | import { colors, boxes } from 'constants/styleGuide';
2 |
3 | export function getLoadingFallbackScreenStyles() {
4 | return {
5 | common: {
6 | container: {
7 | flex: 1,
8 | backgroundColor: colors.light.ultramarineBlue,
9 | paddingLeft: boxes.boxPadding,
10 | paddingRight: boxes.boxPadding,
11 | alignItems: 'center',
12 | justifyContent: 'center',
13 | },
14 | animationContainer: {
15 | position: 'absolute',
16 | bottom: 40,
17 | },
18 | animation: {
19 | width: 80,
20 | height: 80,
21 | },
22 | },
23 | };
24 | }
25 |
--------------------------------------------------------------------------------
/libs/wcm/utils/connectionCreator.js:
--------------------------------------------------------------------------------
1 | import SignClient from '@walletconnect/sign-client';
2 | import { to } from 'await-to-js';
3 |
4 | import pkg from '../../../package.json';
5 |
6 | export async function createSignClient(icon) {
7 | const [error, result] = await to(
8 | SignClient.init({
9 | projectId: process.env.PROJECT_ID,
10 | metadata: {
11 | name: pkg.name,
12 | description: pkg.description,
13 | url: pkg.homepage,
14 | icons: [icon],
15 | },
16 | })
17 | );
18 |
19 | if (error) {
20 | throw error;
21 | }
22 |
23 | if (!result) {
24 | throw new Error('Not able to setup WalletConnect client.');
25 | }
26 |
27 | return result;
28 | }
29 |
--------------------------------------------------------------------------------
/src/components/shared/Tabs/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View } from 'react-native';
3 |
4 | import { useTheme } from 'contexts/ThemeContext';
5 |
6 | import { TabsContext } from './hooks';
7 | import { Tab, TabsPanel } from './components';
8 | import { getTabsStyles } from './styles';
9 |
10 | export default function Tabs({ value, onClick, children }) {
11 | const { styles } = useTheme({
12 | styles: getTabsStyles(),
13 | });
14 |
15 | return (
16 |
17 | {children}
18 |
19 | );
20 | }
21 |
22 | Tabs.Tab = Tab;
23 | Tabs.Panel = TabsPanel;
24 |
--------------------------------------------------------------------------------
/src/modules/Auth/components/AuthType/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View, Text, TouchableOpacity } from 'react-native';
3 | import withTheme from 'components/shared/withTheme';
4 | import getStyles from './styles';
5 |
6 | const AuthTypeItem = ({ illustration, label, styles, onPress, testID }) => (
7 |
12 | {illustration}
13 |
14 | {label}
15 |
16 |
17 | );
18 |
19 | export default withTheme(AuthTypeItem, getStyles());
20 |
--------------------------------------------------------------------------------
/src/modules/Transactions/components/TransactionList/components/TransactionListSkeleton.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View } from 'react-native';
3 |
4 | import TransactionRowSkeleton from '../../TransactionRow/components/TransactionRowSkeleton';
5 |
6 | /**
7 | * Skeleton UI placeholder for TransactionList loading state.
8 | */
9 | export default function TransactionListSkeleton() {
10 | const skeletonsCount = 3;
11 |
12 | return (
13 |
14 | {[...new Array(skeletonsCount)].map((_, index) => (
15 |
19 | ))}
20 |
21 | );
22 | }
23 |
--------------------------------------------------------------------------------
/src/modules/BlockchainApplication/api/useApplicationStatsQuery.js:
--------------------------------------------------------------------------------
1 | import { useCustomQuery } from 'utilities/api/hooks/useCustomQuery';
2 | import { GET_APPLICATION_STATS } from 'utilities/api/queries';
3 | import { API_URL } from 'utilities/api/constants';
4 | import { useQueryKeys } from 'utilities/api/hooks/useQueryKeys';
5 | import liskAPIClient from 'utilities/api/LiskAPIClient';
6 |
7 | export function useApplicationStatsQuery() {
8 | const config = {
9 | url: `${API_URL}/blockchain/apps/statistics`,
10 | method: 'GET',
11 | };
12 |
13 | const keys = useQueryKeys([GET_APPLICATION_STATS, config]);
14 |
15 | return useCustomQuery({
16 | keys,
17 | config,
18 | client: liskAPIClient,
19 | });
20 | }
21 |
--------------------------------------------------------------------------------
/src/modules/Accounts/hooks/useEncryptAccount.js:
--------------------------------------------------------------------------------
1 | import { encryptAccount as encryptAccountUtils } from 'modules/Auth/utils';
2 | import { defaultDerivationPath } from '../../Auth/constants/recoveryPhrase.constants';
3 |
4 | export function useEncryptAccount(useDerivationPath) {
5 | const encryptAccount = ({ recoveryPhrase, password, name, derivationPath }) =>
6 | encryptAccountUtils({
7 | recoveryPhrase,
8 | password,
9 | name,
10 | enableCustomDerivationPath: useDerivationPath,
11 | // Use default derivation path if derivationPath is not passed
12 | derivationPath: useDerivationPath && !derivationPath ? defaultDerivationPath : derivationPath,
13 | });
14 | return { encryptAccount };
15 | }
16 |
--------------------------------------------------------------------------------
/src/components/shared/EmptyState/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View } from 'react-native';
3 |
4 | import { useTheme } from 'contexts/ThemeContext';
5 | import EmptyIllustrationSvg from 'assets/svgs/EmptyIllustrationSvg';
6 | import { P } from 'components/shared/toolBox/typography';
7 |
8 | import getEmptyStateStyles from './styles';
9 |
10 | export default function EmptyState({ message, style = {} }) {
11 | const { styles } = useTheme({ styles: getEmptyStateStyles() });
12 |
13 | return (
14 |
15 |
16 | {message}
17 |
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/src/hooks/useCopyToClipboard.js:
--------------------------------------------------------------------------------
1 | import { useEffect, useRef, useState } from 'react';
2 |
3 | import { setValueToClipboard } from 'utilities/clipboard.utils';
4 |
5 | export function useCopyToClipboard(value, { autoCleanup = false } = {}) {
6 | const [copied, setCopied] = useState(false);
7 |
8 | const timeout = useRef();
9 |
10 | const handleCopy = () => {
11 | setValueToClipboard(value);
12 |
13 | setCopied(true);
14 |
15 | timeout.current = setTimeout(() => {
16 | setCopied(false);
17 |
18 | if (autoCleanup) {
19 | setValueToClipboard('');
20 | }
21 | }, 10000);
22 | };
23 |
24 | useEffect(() => () => clearTimeout(timeout.current), []);
25 |
26 | return [copied, handleCopy];
27 | }
28 |
--------------------------------------------------------------------------------
/src/modules/Accounts/api/useLegacyAccount.js:
--------------------------------------------------------------------------------
1 | import { useQuery } from '@tanstack/react-query';
2 | import { useCurrentAccount } from '../hooks/useCurrentAccount';
3 |
4 | async function fetchLegacyAccount(address) {
5 | const response = await fetch(`https://legacy.lisk.com/accounts/${address}.json`);
6 | const data = await response.json();
7 | return data;
8 | }
9 |
10 | export default function useLegacyAccount(options = {}) {
11 | const [currentAccount] = useCurrentAccount();
12 | const address = currentAccount.metadata.address;
13 |
14 | const query = useQuery({
15 | queryKey: ['GET_ACCOUNT_BALANCE_LEGACY', address],
16 | queryFn: () => fetchLegacyAccount(address),
17 | ...options,
18 | });
19 |
20 | return query;
21 | }
22 |
--------------------------------------------------------------------------------
/src/modules/Transactions/components/TransactionsHistory/styles.js:
--------------------------------------------------------------------------------
1 | import { themes, colors, boxes } from 'constants/styleGuide';
2 |
3 | export default function getTransactionsHistoryStyles() {
4 | return {
5 | common: {
6 | container: {
7 | flex: 1,
8 | },
9 | header: {
10 | marginBottom: 24,
11 | },
12 | listContainer: {
13 | paddingLeft: boxes.boxPadding,
14 | paddingRight: boxes.boxPadding,
15 | },
16 | },
17 | [themes.light]: {
18 | container: {
19 | backgroundColor: colors.light.white,
20 | },
21 | },
22 | [themes.dark]: {
23 | container: {
24 | backgroundColor: colors.dark.mainBg,
25 | },
26 | },
27 | };
28 | }
29 |
--------------------------------------------------------------------------------
/src/assets/svgs/ExternalLinkSvg.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Svg, Path } from 'react-native-svg';
3 |
4 | import colors from '../../constants/styleGuide/colors';
5 |
6 | export default function ExternalLinkSvg({ size = 1, color = colors.dark.ultramarineBlue, style }) {
7 | return (
8 |
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/src/components/navigation/NavigationSafeAreaView/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useBottomTabBarHeight } from '@react-navigation/bottom-tabs';
3 | import { SafeAreaView } from 'react-native-safe-area-context';
4 |
5 | import { useTheme } from 'contexts/ThemeContext';
6 |
7 | import getNavigationSafeAreaViewStyles from './styles';
8 |
9 | export default function NavigationSafeAreaView({ children, style }) {
10 | const tabBarHeight = useBottomTabBarHeight();
11 |
12 | const { styles } = useTheme({
13 | styles: getNavigationSafeAreaViewStyles(tabBarHeight),
14 | });
15 |
16 | return (
17 |
18 | {children}
19 |
20 | );
21 | }
22 |
--------------------------------------------------------------------------------
/src/hooks/useRegisterAndroidModules.js:
--------------------------------------------------------------------------------
1 | import { useEffect } from 'react';
2 | import { NativeModules, Platform } from 'react-native';
3 |
4 | const { AppOpsManagerModule, ProviderInstaller } = NativeModules;
5 |
6 | /**
7 | * Registers native modules for android OS
8 | * Performs data auditing for monitoring user's private data access on the app.
9 | * Registers ProviderInstaller module which provides a secure library for network
10 | * connections that can be updated independently of the Android OS
11 | */
12 | export function useRegisterAndroidModules() {
13 | useEffect(() => {
14 | if (Platform.OS === 'android') {
15 | AppOpsManagerModule.startWatching();
16 | ProviderInstaller.installIfNeeded();
17 | }
18 | }, []);
19 | }
20 |
--------------------------------------------------------------------------------
/src/notifications/NotificationsConfig.js:
--------------------------------------------------------------------------------
1 | import { Platform } from 'react-native';
2 | import PushNotification from 'react-native-push-notification';
3 | import PushNotificationIOS from '@react-native-community/push-notification-ios';
4 |
5 | PushNotification.configure({
6 | onRegister: function (token) {
7 | console.log('Registered for push notifications:', token);
8 | },
9 |
10 | onNotification: function (notification) {
11 | notification.finish(PushNotificationIOS.FetchResult.NoData);
12 | },
13 |
14 | permissions: {
15 | alert: true,
16 | badge: true,
17 | sound: true,
18 | },
19 |
20 | popInitialNotification: true,
21 | requestPermissions: Platform.OS === 'ios',
22 | });
23 |
24 | export default PushNotification;
25 |
--------------------------------------------------------------------------------
/src/assets/svgs/StatsSvg.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Svg, Path } from 'react-native-svg';
3 |
4 | export default function StatsSvg({ width, height, style }) {
5 | return (
6 |
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/src/utilities/api/hooks/useInvokeQuery.test.js:
--------------------------------------------------------------------------------
1 | import { renderHook } from '@testing-library/react-hooks';
2 |
3 | import { queryWrapper } from 'tests/queryWrapper';
4 | import { mockInvokeQuery } from '../__fixtures__';
5 | import { useInvokeQuery } from './useInvokeQuery';
6 |
7 | jest.useRealTimers();
8 |
9 | describe('useInvokeQuery hook', () => {
10 | it('fetch data correctly', async () => {
11 | const { result, waitFor } = renderHook(() => useInvokeQuery({}), { wrapper: queryWrapper });
12 |
13 | expect(result.current.isLoading).toBeTruthy();
14 |
15 | await waitFor(() => result.current.isFetched);
16 |
17 | expect(result.current.isSuccess).toBeTruthy();
18 | expect(result.current.data).toEqual(mockInvokeQuery);
19 | });
20 | });
21 |
--------------------------------------------------------------------------------
/metro.config.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/no-extraneous-dependencies */
2 | /**
3 | * Metro configuration for React Native
4 | * https://github.com/facebook/react-native
5 | *
6 | * @format
7 | */
8 |
9 | const defaultSourceExts = require('metro-config/src/defaults/defaults').sourceExts;
10 |
11 | const env = require('./env.json');
12 |
13 | console.log('env.APP_MODE', env.APP_MODE);
14 |
15 | module.exports = {
16 | resolver: {
17 | sourceExts: env.APP_MODE === 'mocked' ? ['mock.js', ...defaultSourceExts] : defaultSourceExts,
18 | },
19 | transformer: {
20 | getTransformOptions: async () => ({
21 | transform: {
22 | experimentalImportSupport: false,
23 | inlineRequires: false,
24 | },
25 | }),
26 | },
27 | };
28 |
--------------------------------------------------------------------------------
/src/modules/BlockchainApplication/components/ManageApplication/styles.js:
--------------------------------------------------------------------------------
1 | import { colors, themes, boxes } from 'constants/styleGuide';
2 |
3 | export default {
4 | common: {
5 | container: {
6 | flex: 1,
7 | },
8 | title: {
9 | textAlign: 'center',
10 | marginBottom: 16,
11 | },
12 | footer: {
13 | paddingTop: boxes.boxPadding,
14 | },
15 | },
16 | [themes.light]: {
17 | container: {
18 | backgroundColor: colors.dark.white,
19 | },
20 | title: {
21 | color: colors.light.zodiacBlue,
22 | },
23 | },
24 | [themes.dark]: {
25 | container: {
26 | backgroundColor: colors.dark.black,
27 | },
28 | title: {
29 | color: colors.dark.white,
30 | },
31 | },
32 | };
33 |
--------------------------------------------------------------------------------
/src/tests/queryWrapper.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { MutationCache, QueryCache, QueryClient, QueryClientProvider } from '@tanstack/react-query';
3 | import { addCleanup } from '@testing-library/react-hooks';
4 |
5 | export function queryWrapper({ children }) {
6 | const mutationCache = new MutationCache();
7 |
8 | const queryCache = new QueryCache();
9 |
10 | const queryClient = new QueryClient({
11 | queryCache,
12 | mutationCache,
13 | defaultOptions: {
14 | queries: {
15 | retry: false,
16 | },
17 | },
18 | });
19 |
20 | addCleanup(() => {
21 | mutationCache.clear();
22 | queryCache.clear();
23 | });
24 |
25 | return {children};
26 | }
27 |
--------------------------------------------------------------------------------
/src/components/shared/Picker/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import { useModal } from 'hooks/useModal';
4 | import { PickerContext } from './hooks';
5 | import { PickerItem, PickerLabel, usePickerMenu, PickerToggle } from './components';
6 |
7 | export default function Picker({ children, value, error }) {
8 | const modal = useModal();
9 |
10 | return (
11 |
19 | {children}
20 |
21 | );
22 | }
23 |
24 | Picker.usePickerMenu = usePickerMenu;
25 | Picker.Item = PickerItem;
26 | Picker.Label = PickerLabel;
27 | Picker.Toggle = PickerToggle;
28 |
--------------------------------------------------------------------------------
/src/utilities/api/hooks/useInvokeQuery.js:
--------------------------------------------------------------------------------
1 | import { API_VERSION } from '../constants';
2 | import { INVOKE_QUERY } from '../queries';
3 | import { useCustomQuery } from './useCustomQuery';
4 |
5 | /**
6 | * Query that acts as proxy to call direct invoke methods to blockchain application client.
7 | * @param {object} params.config - Query custom configs.
8 | * @param {string} params.options - Query custom options.
9 | */
10 | export function useInvokeQuery({ config: customConfig = {}, options }) {
11 | const config = {
12 | url: `/api/${API_VERSION}/invoke`,
13 | method: 'POST',
14 | event: 'post.invoke',
15 | ...customConfig,
16 | };
17 | return useCustomQuery({
18 | keys: [INVOKE_QUERY, config, options],
19 | config,
20 | options,
21 | });
22 | }
23 |
--------------------------------------------------------------------------------
/src/components/shared/Logo/Logo.styles.js:
--------------------------------------------------------------------------------
1 | import { colors } from 'constants/styleGuide';
2 |
3 | export default function getLogoStyles(size) {
4 | return {
5 | common: {
6 | image: {
7 | borderRadius: 50,
8 | width: size,
9 | height: size,
10 | borderWidth: 1,
11 | borderColor: colors.light.platinumGray,
12 | },
13 | initialsContainer: {
14 | width: size,
15 | height: size,
16 | borderRadius: 50,
17 | backgroundColor: colors.light.silverGrey,
18 | justifyContent: 'center',
19 | alignItems: 'center',
20 | },
21 | initials: {
22 | color: colors.light.zodiacBlue,
23 | fontSize: size / 2.5,
24 | fontWeight: 'bold',
25 | },
26 | },
27 | };
28 | }
29 |
--------------------------------------------------------------------------------
/src/components/shared/fadeInView/index.js:
--------------------------------------------------------------------------------
1 | import React, { useRef } from 'react';
2 | import { Animated } from 'react-native';
3 |
4 | const FadeInView = (props) => {
5 | const fadeAnim = useRef(new Animated.Value(0)).current; // Initial value for opacity: 0
6 |
7 | React.useEffect(() => {
8 | Animated.timing(fadeAnim, {
9 | toValue: 1,
10 | duration: 1000,
11 | useNativeDriver: false,
12 | }).start();
13 | }, [fadeAnim]);
14 |
15 | return (
16 |
24 | {props.children}
25 |
26 | );
27 | };
28 |
29 | export default FadeInView;
30 |
--------------------------------------------------------------------------------
/src/constants/styleGuide/fonts.js:
--------------------------------------------------------------------------------
1 | const commercialFontFamily = {
2 | heading: 'Gilroy-Bold',
3 | context: 'BasierCircle-Regular',
4 | contextBold: 'BasierCircle-Bold',
5 | contextSemiBold: 'BasierCircle-SemiBold',
6 | };
7 |
8 | const freeFontFamily = {
9 | heading: 'OpenSans-Bold',
10 | context: 'OpenSans-Regular',
11 | contextBold: 'OpenSans-Bold',
12 | contextSemiBold: 'OpenSans-SemiBold',
13 | };
14 |
15 | export default {
16 | family: {
17 | ...(process.env.USE_COMMERCIAL_FONTS ? commercialFontFamily : freeFontFamily),
18 | recoveryPhrase: 'Dots-Regular',
19 | recoveryPhraseText: 'PTMono-Regular',
20 | },
21 | size: {
22 | h1: 26,
23 | h2: 24,
24 | h3: 22,
25 | h4: 20,
26 | base: 16,
27 | small: 13,
28 | input: 14,
29 | },
30 | };
31 |
--------------------------------------------------------------------------------
/android/app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
8 |
10 |
12 |
14 |
15 |
16 |
18 |
20 |
22 |
24 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/modules/Accounts/components/TokenRow/components/TokenRowSkeleton.styles.js:
--------------------------------------------------------------------------------
1 | import { colors, themes } from 'constants/styleGuide';
2 |
3 | export default function getTokenRowSkeletonStyles() {
4 | return {
5 | common: {
6 | container: {
7 | flexDirection: 'row',
8 | justifyContent: 'space-between',
9 | borderWidth: 1,
10 | borderRadius: 8,
11 | padding: 16,
12 | },
13 | row: {
14 | flexDirection: 'row',
15 | alignItems: 'center',
16 | },
17 | },
18 | [themes.light]: {
19 | container: {
20 | borderColor: colors.light.platinumGray,
21 | },
22 | },
23 | [themes.dark]: {
24 | container: {
25 | borderColor: colors.dark.textInputBg,
26 | },
27 | },
28 | };
29 | }
30 |
--------------------------------------------------------------------------------
/src/modules/Settings/components/HarmfulAppRow/styles.js:
--------------------------------------------------------------------------------
1 | import { themes, colors, fonts } from 'constants/styleGuide';
2 |
3 | export default () => ({
4 | common: {
5 | row: {
6 | flexDirection: 'row',
7 | alignItems: 'center',
8 | marginBottom: 20,
9 | },
10 | packageName: {
11 | fontSize: fonts.size.base,
12 | fontFamily: fonts.family.context,
13 | flex: 1,
14 | },
15 | appLogo: {
16 | height: 35,
17 | width: 35,
18 | borderRadius: 20,
19 | marginRight: 10,
20 | },
21 | },
22 |
23 | [themes.light]: {
24 | packageName: {
25 | color: colors.light.maastrichtBlue,
26 | },
27 | },
28 |
29 | [themes.dark]: {
30 | packageName: {
31 | color: colors.dark.platinum,
32 | },
33 | },
34 | });
35 |
--------------------------------------------------------------------------------
/patches/jest-circus+29.5.0.patch:
--------------------------------------------------------------------------------
1 | diff --git a/node_modules/jest-circus/build/utils.js b/node_modules/jest-circus/build/utils.js
2 | index 755741b..2022adb 100644
3 | --- a/node_modules/jest-circus/build/utils.js
4 | +++ b/node_modules/jest-circus/build/utils.js
5 | @@ -320,12 +320,12 @@ const callAsyncCircusFn = (testOrHook, testContext, {isHook, timeout}) => {
6 | completed = true;
7 | // If timeout is not cleared/unrefed the node process won't exit until
8 | // it's resolved.
9 | - timeoutID.unref?.();
10 | + timeoutID?.unref?.();
11 | clearTimeout(timeoutID);
12 | })
13 | .catch(error => {
14 | completed = true;
15 | - timeoutID.unref?.();
16 | + timeoutID?.unref?.();
17 | clearTimeout(timeoutID);
18 | throw error;
19 | });
20 |
--------------------------------------------------------------------------------
/src/components/shared/Fab/utils/touchable.js:
--------------------------------------------------------------------------------
1 | import { Platform, TouchableOpacity, TouchableNativeFeedback } from 'react-native';
2 |
3 | import { shadeColor } from './color';
4 |
5 | export function getTouchableComponent(useNativeFeedback = true) {
6 | if (useNativeFeedback === true && Platform.OS === 'android') {
7 | return TouchableNativeFeedback;
8 | }
9 | return TouchableOpacity;
10 | }
11 |
12 | export function getRippleProps(color, useNativeFeedback = true) {
13 | // less than API 21 don't support Ripple
14 | if (useNativeFeedback === true && Platform.OS === 'android' && Platform.Version >= 21) {
15 | return {
16 | // eslint-disable-next-line new-cap
17 | background: TouchableNativeFeedback.Ripple(shadeColor(color, -30), true),
18 | };
19 | }
20 | return {};
21 | }
22 |
--------------------------------------------------------------------------------
/src/modules/Transactions/__fixtures__/mockTokensMeta.js:
--------------------------------------------------------------------------------
1 | export const mockDefaultTokenMeta = {
2 | chainID: '00000001',
3 | chainName: 'Lisk',
4 | tokenID: '0400000000000000',
5 | description: 'Default token for the entire Lisk ecosystem',
6 | logo: {
7 | png: 'https://lisk-qa.ams3.digitaloceanspaces.com/Artboard%201%20copy%2019.png',
8 | svg: 'https://lisk-qa.ams3.digitaloceanspaces.com/Logo-20.svg',
9 | },
10 | symbol: 'LSK',
11 | displayDenom: 'lsk',
12 | baseDenom: 'beddows',
13 | denomUnits: [
14 | {
15 | denom: 'beddows',
16 | decimals: 0,
17 | aliases: ['Beddows'],
18 | },
19 | {
20 | denom: 'lsk',
21 | decimals: 8,
22 | aliases: ['Lisk'],
23 | },
24 | ],
25 | };
26 |
27 | export const mockTokensMeta = [mockDefaultTokenMeta];
28 |
--------------------------------------------------------------------------------
/src/modules/Transactions/utils/helpers.test.js:
--------------------------------------------------------------------------------
1 | import { computeNonce } from './helpers';
2 |
3 | describe('Transaction module helpers', () => {
4 | describe('computeNonce', () => {
5 | it('returns the authNonce if transactionPool is empty', () => {
6 | const authNonce = '123456';
7 | const transactionPool = [];
8 | const result = computeNonce(authNonce, transactionPool);
9 | expect(result).toEqual(authNonce);
10 | });
11 |
12 | it('returns the maximum nonce from the transactionPool', () => {
13 | const authNonce = '123456';
14 | const transactionPool = [{ nonce: '123450' }, { nonce: '123454' }, { nonce: '123455' }];
15 | const result = computeNonce(authNonce, transactionPool);
16 | expect(result).toEqual('123455');
17 | });
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/android/app/src/release/java/com/lisk/ReactNativeFlipper.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) Meta Platforms, Inc. and affiliates.
3 | *
4 | * This source code is licensed under the MIT license found in the LICENSE file in the root
5 | * directory of this source tree.
6 | */
7 | package io.lisk.mobile;
8 |
9 | import android.content.Context;
10 | import com.facebook.react.ReactInstanceManager;
11 |
12 | /**
13 | * Class responsible of loading Flipper inside your React Native application. This is the release
14 | * flavor of it so it's empty as we don't want to load Flipper.
15 | */
16 | public class ReactNativeFlipper {
17 | public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
18 | // Do nothing as we don't want to initialize Flipper on Release.
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/modules/Accounts/store/actions/account.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable max-lines */
2 | import actionTypes from '../../actionTypes';
3 |
4 | /**
5 | * Trigger this action to log out of the account
6 | * while already logged in
7 | *
8 | * @returns {Object} - Action object
9 | */
10 | export const setCurrentAccount = (encryptedAccount) => ({
11 | type: actionTypes.setCurrentAccount,
12 | encryptedAccount,
13 | });
14 |
15 | export const addAccount = (encryptedAccount) => ({
16 | type: actionTypes.addAccount,
17 | encryptedAccount,
18 | });
19 |
20 | export const updateAccount = (address, accountData) => ({
21 | type: actionTypes.updateAccount,
22 | address,
23 | accountData,
24 | });
25 |
26 | export const deleteAccount = (address) => ({
27 | type: actionTypes.deleteAccount,
28 | address,
29 | });
30 |
--------------------------------------------------------------------------------
/src/utilities/qrCode.js:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line import/prefer-default-export
2 | export const decodeLaunchUrl = (data) => {
3 | const recipientReg = /\?recipient=([^&]+)&/;
4 | const amountReg = /amount=(\d+)\.?(\d+)?/;
5 | const referenceReg = /reference=.*$/;
6 | const liskProtocolReg = /^[l|L]isk:\/\//;
7 |
8 | if (liskProtocolReg.test(data) && recipientReg.test(data)) {
9 | const address = data.match(recipientReg)[1];
10 | const amount = data.match(amountReg) ? data.match(amountReg)[0].replace('amount=', '') : '';
11 | const reference = data.match(referenceReg)
12 | ? window.decodeURIComponent(data.match(referenceReg)[0].replace('reference=', ''))
13 | : '';
14 |
15 | return { address, amount, reference };
16 | }
17 |
18 | return { address: data || '' };
19 | };
20 |
--------------------------------------------------------------------------------
/src/modules/BlockchainApplication/components/ApplicationManagerModal/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Stepper from 'components/shared/Stepper';
3 | import { useModal } from 'hooks/useModal';
4 |
5 | import ManageApplication from '../ManageApplication';
6 | import DeleteApplication from '../DeleteApplication';
7 | import DeleteApplicationSuccess from '../DeleteApplicationSuccess';
8 |
9 | export default function ApplicationManagerModal({ navigation }) {
10 | const modal = useModal();
11 | const closeModal = () => modal.toggle(false);
12 |
13 | return (
14 |
15 |
16 |
17 |
18 |
19 | );
20 | }
21 |
--------------------------------------------------------------------------------
/android/app/src/main/java/com/lisk/SensitiveClipboardPackage.java:
--------------------------------------------------------------------------------
1 | package io.lisk.mobile;
2 |
3 | import com.facebook.react.ReactPackage;
4 | import com.facebook.react.bridge.NativeModule;
5 | import com.facebook.react.bridge.ReactApplicationContext;
6 | import com.facebook.react.uimanager.ViewManager;
7 | import java.util.Arrays;
8 | import java.util.Collections;
9 | import java.util.List;
10 |
11 | public class SensitiveClipboardPackage implements ReactPackage {
12 |
13 | @Override
14 | public List createNativeModules(ReactApplicationContext reactContext) {
15 | return Arrays.asList(new SensitiveClipboardModule(reactContext));
16 | }
17 |
18 | @Override
19 | public List createViewManagers(ReactApplicationContext reactContext) {
20 | return Collections.emptyList();
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/android/app/src/main/java/com/lisk/VerifyAppsPackage.java:
--------------------------------------------------------------------------------
1 | package io.lisk.mobile;
2 |
3 | import com.facebook.react.ReactPackage;
4 | import com.facebook.react.bridge.NativeModule;
5 | import com.facebook.react.bridge.ReactApplicationContext;
6 | import com.facebook.react.uimanager.ViewManager;
7 |
8 | import java.util.Collections;
9 | import java.util.List;
10 | import java.util.Arrays;
11 |
12 | public class VerifyAppsPackage implements ReactPackage {
13 |
14 | @Override
15 | public List createNativeModules(ReactApplicationContext reactContext) {
16 | return Arrays.asList(new VerifyAppsModule(reactContext));
17 | }
18 |
19 | @Override
20 | public List createViewManagers(ReactApplicationContext reactContext) {
21 | return Collections.emptyList();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/components/shared/Logo/Logo.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View, Image } from 'react-native';
3 |
4 | import { useTheme } from 'contexts/ThemeContext';
5 | import { P } from 'components/shared/toolBox/typography';
6 | import { getInitials } from 'utilities/helpers';
7 |
8 | import getStyles from './Logo.styles';
9 |
10 | export default function Logo({ uri, name, size = 40, style }) {
11 | const { styles } = useTheme({ styles: getStyles(size) });
12 |
13 | if (uri) {
14 | return ;
15 | }
16 |
17 | if (name) {
18 | const initials = getInitials(name);
19 |
20 | return (
21 |
22 | {initials}
23 |
24 | );
25 | }
26 |
27 | return null;
28 | }
29 |
--------------------------------------------------------------------------------
/ios/LiskTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/modules/SendToken/components/SummaryStep/styles.js:
--------------------------------------------------------------------------------
1 | import { themes, colors, boxes } from 'constants/styleGuide';
2 |
3 | export default function getSendTokenSummaryStepStyles() {
4 | return {
5 | common: {
6 | container: {
7 | flex: 1,
8 | padding: boxes.boxPadding,
9 | },
10 | footer: {
11 | flexDirection: 'row',
12 | alignItems: 'center',
13 | justifyContent: 'center',
14 | padding: boxes.boxPadding,
15 | },
16 | buttonMarginVertical: {
17 | marginVertical: 16,
18 | },
19 | },
20 | [themes.light]: {
21 | container: {
22 | backgroundColor: colors.light.white,
23 | },
24 | },
25 | [themes.dark]: {
26 | container: {
27 | backgroundColor: colors.dark.mainBg,
28 | },
29 | },
30 | };
31 | }
32 |
--------------------------------------------------------------------------------
/src/modules/Transactions/components/TransactionRow/components/TransactionStatus.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import CircleCrossedSvg from 'assets/svgs/CircleCrossedSvg';
4 | import CheckSvg from 'assets/svgs/CheckSvg';
5 | import SandClockSvg from 'assets/svgs/SandClockSvg';
6 |
7 | export function TransactionStatus({ transaction }) {
8 | let children = null;
9 |
10 | const props = { height: 14, width: 14 };
11 |
12 | switch (transaction.executionStatus) {
13 | case 'successful':
14 | children = ;
15 | break;
16 |
17 | case 'pending':
18 | children = ;
19 | break;
20 |
21 | case 'failed':
22 | children = ;
23 | break;
24 |
25 | default:
26 | break;
27 | }
28 |
29 | return children;
30 | }
31 |
--------------------------------------------------------------------------------
/ios/Lisk-tvOSTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/modules/Auth/hooks/usePasswordForm.js:
--------------------------------------------------------------------------------
1 | import { useForm, useController } from 'react-hook-form';
2 | import * as yup from 'yup';
3 | import { yupResolver } from '@hookform/resolvers/yup';
4 |
5 | import { passwordValidationRegex } from 'modules/Auth/validators';
6 |
7 | const validationSchema = yup
8 | .object()
9 | .shape({
10 | password: yup.string().required('Password must have a value.').matches(passwordValidationRegex),
11 | })
12 | .required();
13 |
14 | export function usePasswordForm(props = {}) {
15 | const form = useForm({
16 | defaultValues: {
17 | password: '',
18 | },
19 | resolver: yupResolver(validationSchema),
20 | ...props,
21 | });
22 |
23 | const controller = useController({
24 | name: 'password',
25 | control: form.control,
26 | });
27 |
28 | return [form, controller];
29 | }
30 |
--------------------------------------------------------------------------------
/src/components/shared/Checkbox/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View } from 'react-native';
3 | import { TouchableOpacity } from 'react-native-gesture-handler';
4 | import { useTheme } from 'contexts/ThemeContext';
5 | import CheckSvg from 'assets/svgs/CheckSvg';
6 | import checkboxStyles from './styles';
7 |
8 | export default function Checkbox({ children, selected, onPress, style, ...props }) {
9 | const { styles } = useTheme({ styles: checkboxStyles });
10 | return (
11 |
12 |
13 | {selected && }
14 |
15 |
16 | {children}
17 |
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/src/components/shared/DataRenderer/styles.js:
--------------------------------------------------------------------------------
1 | import { themes, colors, fonts } from 'constants/styleGuide';
2 |
3 | export default function getDataRendererStyles() {
4 | return {
5 | common: {
6 | text: {
7 | fontFamily: fonts.family.context,
8 | fontSize: fonts.size.base,
9 | },
10 | errorText: {
11 | fontFamily: fonts.family.context,
12 | fontSize: fonts.size.base,
13 | },
14 | },
15 | [themes.light]: {
16 | text: {
17 | color: colors.light.zodiacBlue,
18 | },
19 | errorText: {
20 | color: colors.light.burntSieanna,
21 | },
22 | },
23 | [themes.dark]: {
24 | text: {
25 | color: colors.light.whiteSmoke,
26 | },
27 | errorText: {
28 | color: colors.light.burntSieanna,
29 | },
30 | },
31 | };
32 | }
33 |
--------------------------------------------------------------------------------
/src/components/screens/IntroScreen/IntroScreen.styles.js:
--------------------------------------------------------------------------------
1 | import { themes, colors, boxes } from 'constants/styleGuide';
2 |
3 | export default function getIntroScreenStyles() {
4 | return {
5 | common: {
6 | container: {
7 | flex: 1,
8 | justifyContent: 'space-between',
9 | },
10 | footer: {
11 | flexDirection: 'row',
12 | alignItems: 'flex-end',
13 | padding: boxes.boxPadding,
14 | height: 152,
15 | },
16 | lastSlideFooter: {
17 | padding: boxes.boxPadding,
18 | height: 152,
19 | },
20 | },
21 | [themes.light]: {
22 | container: {
23 | backgroundColor: colors.light.white,
24 | },
25 | },
26 | [themes.dark]: {
27 | container: {
28 | backgroundColor: colors.dark.mainBg,
29 | },
30 | },
31 | };
32 | }
33 |
--------------------------------------------------------------------------------
/src/assets/svgs/LinkSvg.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Svg, Path } from 'react-native-svg';
3 |
4 | export default () => (
5 |
25 | );
26 |
--------------------------------------------------------------------------------
/src/components/shared/Fab/FloatingItem/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import { colors, fonts } from 'constants/styleGuide';
3 |
4 | export default StyleSheet.create({
5 | container: {
6 | elevation: 0,
7 | flex: 1,
8 | flexDirection: 'column',
9 | },
10 | actionContainer: {
11 | elevation: 0,
12 | flex: 1,
13 | flexDirection: 'row',
14 | alignItems: 'center',
15 | paddingLeft: 0,
16 | paddingRight: 0,
17 | },
18 | textContainer: {
19 | paddingHorizontal: 8,
20 | borderRadius: 4,
21 | height: 22,
22 | },
23 | text: {
24 | fontSize: 15,
25 | fontFamily: fonts.family.contextBold,
26 | color: colors.light.white,
27 | },
28 | button: {
29 | alignItems: 'center',
30 | justifyContent: 'center',
31 | backgroundColor: colors.light.ultramarineBlue,
32 | },
33 | });
34 |
--------------------------------------------------------------------------------
/src/hooks/useTimeoutMonitor.js:
--------------------------------------------------------------------------------
1 | import { useRef, useEffect, useCallback } from 'react';
2 |
3 | export function useTimeoutMonitor(maxTime, onTimeout) {
4 | const timerRef = useRef(null);
5 |
6 | const initialize = useCallback(() => {
7 | if (timerRef.current) {
8 | clearTimeout(timerRef.current);
9 | }
10 |
11 | timerRef.current = setTimeout(() => {
12 | if (onTimeout && typeof onTimeout === 'function') {
13 | onTimeout();
14 | }
15 | }, maxTime);
16 | }, [maxTime, onTimeout]);
17 |
18 | const destroy = useCallback(() => {
19 | if (timerRef.current) {
20 | clearTimeout(timerRef.current);
21 | }
22 | }, []);
23 |
24 | useEffect(() => {
25 | return () => {
26 | if (timerRef.current) clearTimeout(timerRef.current);
27 | };
28 | }, []);
29 |
30 | return { initialize, destroy };
31 | }
32 |
--------------------------------------------------------------------------------
/src/modules/BlockchainApplication/components/ApplicationList/components/ApplicationListSkeleton.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View } from 'react-native';
3 |
4 | import ApplicationRowSkeleton from '../../ApplicationRow/components/ApplicationRowSkeleton';
5 |
6 | /**
7 | * Skeleton UI placeholder for ApplicationList loading state.
8 | * @param {React.CSSProperties} style - Custom styles to add to the main component
9 | * container (optional).
10 | */
11 | export default function ApplicationListSkeleton({ style }) {
12 | const skeletonsCount = 5;
13 |
14 | return (
15 |
16 | {[...new Array(skeletonsCount)].map((_, index) => (
17 |
21 | ))}
22 |
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/src/assets/svgs/InfoRoundSvg.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Svg, Path, Circle } from 'react-native-svg';
3 |
4 | export default ({ color, size = 20, style }) => (
5 |
19 | );
20 |
--------------------------------------------------------------------------------
/src/constants/regex.js:
--------------------------------------------------------------------------------
1 | export default {
2 | amount: /^\d+(?:[.,]\d{1,8})?$/,
3 | publicKey: /^[a-f0-9]{64}$/i,
4 | address: /^lsk[a-z0-9]{0,38}$/,
5 | legacyAddress: /^[1-9]\d{0,19}L$/,
6 | username: /^[a-z0-9!@$&_.]{3,20}$/,
7 | delegateName: /^[a-z0-9!@$&_.]{3,20}$/,
8 | transactionId: /^[0-9a-z]{64}/,
9 | blockId: /^[0-9a-z]{64}/,
10 | blockHeight: /^[0-9]+$/,
11 | truncate: {
12 | small: /^(.{6})(.+)?(.{5})$/,
13 | medium:
14 | /\b((bc|tb)(0([ac-hj-np-z02-9]{39}|[ac-hj-np-z02-9]{59})|1[ac-hj-np-z02-9]{8,87})|([13]|[mn2])[a-km-zA-HJ-NP-Z1-9]{25,39})\b/,
15 | },
16 | lskAddressTrunk: /^(.{6})(.+)?(.{5})$/,
17 | publicKeyTrunk: /^(.{6})(.+)?(.{5})$/,
18 | delegateSpecialChars: /[a-z0-9!@$&_.]+/g,
19 | htmlElements: /<(\w+).*?>([\s\S]*?)<\/\1>(.*)/,
20 | releaseSummary: /([\s\S]*?)<\/h4>/i,
21 | searchbar: /^(.{9})(.+)$/,
22 | };
23 |
--------------------------------------------------------------------------------
/android/app/src/main/java/com/lisk/ScopedStoragePackage.java:
--------------------------------------------------------------------------------
1 | package io.lisk.mobile;
2 |
3 | import com.facebook.react.ReactPackage;
4 | import com.facebook.react.bridge.NativeModule;
5 | import com.facebook.react.bridge.ReactApplicationContext;
6 | import com.facebook.react.uimanager.ViewManager;
7 |
8 | import java.util.Arrays;
9 | import java.util.Collections;
10 | import java.util.List;
11 |
12 | public class ScopedStoragePackage implements ReactPackage {
13 |
14 | @Override
15 | public List createViewManagers(ReactApplicationContext reactContext) {
16 | return Collections.emptyList();
17 | }
18 |
19 | @Override
20 | public List createNativeModules(ReactApplicationContext reactContext) {
21 | return Arrays.asList(
22 | new ScopedStorageModule(reactContext)
23 | );
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/env.example.json:
--------------------------------------------------------------------------------
1 | {
2 | "RECOVERY_PHRASE": "A RECOVERY PHRASE FOR DEV PURPOSES",
3 | "NETWORK": "NETWORK IN USE",
4 | "SERVICE_API_BASE_URL": "SERVICE HTTP API BASE URL",
5 | "SERVICE_WS_BASE_URL": "SERVICE WEB SOCKETS API BASE URL",
6 | "SERVICE_API_VERSION": "v3",
7 | "PROJECT_ID": "WALLET CONNECT PROJECT ID",
8 | "RELAY_URL": "WALLET CONNECT RELAY URL",
9 | "MOCK_SERVICE_API_ENABLED": "FLAG THAT INDICATES IF SERVICE API MOCKING IS OR NOT ENABLED",
10 | "MOCKED_SERVICE_ENDPOINTS": "NAMES OF SERVICE ENDPOINTS TO MOCK, SEPARATED BY ';'. SHOULD FOLLOW THE DEFINED NOMENCLATURE. EXAMPLE: 'getApplications;getApplicationsMeta'",
11 | "APP_MODE": "USE 'mocked' FOR END TO END TESTS TO ENABLE PREDICTING RESULTS OF SOME SYSTEM AND APP FUNCTIONS",
12 | "USE_COMMERCIAL_FONTS": "USED TO DECIDE IF THE LISK MOBILE SHOULD USE COMMERCIAL FONTS OR FREE FONTS"
13 | }
--------------------------------------------------------------------------------
/src/components/shared/EmptyState/styles.js:
--------------------------------------------------------------------------------
1 | import { themes, colors } from 'constants/styleGuide';
2 |
3 | export default function getEmptyStateStyles() {
4 | return {
5 | common: {
6 | container: {
7 | alignItems: 'center',
8 | justifyContent: 'center',
9 | padding: 10,
10 | },
11 | messageText: {
12 | marginTop: 10,
13 | fontSize: 14,
14 | textAlign: 'center',
15 | },
16 | },
17 | [themes.light]: {
18 | container: {
19 | backgroundColor: colors.light.white,
20 | },
21 | messageText: {
22 | color: colors.light.slateGray,
23 | },
24 | },
25 | [themes.dark]: {
26 | container: {
27 | backgroundColor: colors.dark.mainBg,
28 | },
29 | messageText: {
30 | color: colors.dark.slateGray,
31 | },
32 | },
33 | };
34 | }
35 |
--------------------------------------------------------------------------------
/src/modules/Bookmark/components/List.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import InfiniteScrollList from 'components/shared/InfiniteScrollList';
4 | import { validateAddress } from 'utilities/validators';
5 | import withTheme from 'components/shared/withTheme';
6 | import { DraggableItem, Item } from './Item';
7 | import getStyles from './styles';
8 |
9 | const List = ({ list, onPress, draggable, Component }) => {
10 | const Element = Component || (draggable ? DraggableItem : Item);
11 |
12 | return (
13 | (
16 |
22 | )}
23 | />
24 | );
25 | };
26 |
27 | export default withTheme(List, getStyles());
28 |
--------------------------------------------------------------------------------
/.husky/_/husky.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 | if [ -z "$husky_skip_init" ]; then
3 | debug () {
4 | if [ "$HUSKY_DEBUG" = "1" ]; then
5 | echo "husky (debug) - $1"
6 | fi
7 | }
8 |
9 | readonly hook_name="$(basename -- "$0")"
10 | debug "starting $hook_name..."
11 |
12 | if [ "$HUSKY" = "0" ]; then
13 | debug "HUSKY env variable is set to 0, skipping hook"
14 | exit 0
15 | fi
16 |
17 | if [ -f ~/.huskyrc ]; then
18 | debug "sourcing ~/.huskyrc"
19 | . ~/.huskyrc
20 | fi
21 |
22 | readonly husky_skip_init=1
23 | export husky_skip_init
24 | sh -e "$0" "$@"
25 | exitCode="$?"
26 |
27 | if [ $exitCode != 0 ]; then
28 | echo "husky - $hook_name hook exited with code $exitCode (error)"
29 | fi
30 |
31 | if [ $exitCode = 127 ]; then
32 | echo "husky - command not found in PATH=$PATH"
33 | fi
34 |
35 | exit $exitCode
36 | fi
37 |
--------------------------------------------------------------------------------
/src/modules/BlockchainApplication/components/ApplicationRow/components/ApplicationRowSkeleton.styles.js:
--------------------------------------------------------------------------------
1 | import { themes, colors } from 'constants/styleGuide';
2 |
3 | export default function getApplicationRowSkeletonStyles() {
4 | return {
5 | common: {
6 | container: {
7 | flexDirection: 'row',
8 | justifyContent: 'space-between',
9 | alignItems: 'center',
10 | paddingTop: 16,
11 | paddingBottom: 16,
12 | borderBottomWidth: 1,
13 | },
14 | row: {
15 | flexDirection: 'row',
16 | alignItems: 'center',
17 | },
18 | },
19 | [themes.light]: {
20 | container: {
21 | borderBottomColor: colors.light.platinumGray,
22 | },
23 | },
24 |
25 | [themes.dark]: {
26 | container: {
27 | borderBottomColor: colors.dark.volcanicSand,
28 | },
29 | },
30 | };
31 | }
32 |
--------------------------------------------------------------------------------
/android/app/src/main/java/com/lisk/ExactAlarmPackage.java:
--------------------------------------------------------------------------------
1 | package io.lisk.mobile;
2 |
3 | import com.facebook.react.ReactPackage;
4 | import com.facebook.react.bridge.NativeModule;
5 | import com.facebook.react.bridge.ReactApplicationContext;
6 | import com.facebook.react.uimanager.ViewManager;
7 |
8 | import java.util.ArrayList;
9 | import java.util.Collections;
10 | import java.util.List;
11 |
12 | public class ExactAlarmPackage implements ReactPackage {
13 | @Override
14 | public List createViewManagers(ReactApplicationContext reactContext) {
15 | return Collections.emptyList();
16 | }
17 |
18 | @Override
19 | public List createNativeModules(ReactApplicationContext reactContext) {
20 | List modules = new ArrayList<>();
21 | modules.add(new ExactAlarmModule(reactContext));
22 | return modules;
23 | }
24 | }
--------------------------------------------------------------------------------
/src/components/shared/Scanner/CameraAccessAlert.js:
--------------------------------------------------------------------------------
1 | import { useEffect } from 'react';
2 | import { Alert } from 'react-native';
3 | import OpenAppSettings from 'react-native-app-settings';
4 | import i18next from 'i18next';
5 |
6 | export default function CameraAccessAlert({ type, close }) {
7 | const handleOpenSettingsPress = () => OpenAppSettings.open();
8 |
9 | useEffect(() => {
10 | if (type === 'noAuth') {
11 | Alert.alert(
12 | i18next.t('scanner.cameraAccessTitle'),
13 | i18next.t('scanner.cameraAccessDescription'),
14 | [
15 | {
16 | text: i18next.t('commons.buttons.cancel'),
17 | onPress: close,
18 | style: 'cancel',
19 | },
20 | { text: i18next.t('settings.title'), onPress: handleOpenSettingsPress },
21 | ]
22 | );
23 | }
24 | }, [close, type]);
25 |
26 | return null;
27 | }
28 |
--------------------------------------------------------------------------------
/android/app/src/main/java/com/lisk/AppOpsManagerModulePackage.java:
--------------------------------------------------------------------------------
1 | package io.lisk.mobile;
2 |
3 | import com.facebook.react.ReactPackage;
4 | import com.facebook.react.bridge.NativeModule;
5 | import com.facebook.react.bridge.ReactApplicationContext;
6 | import com.facebook.react.uimanager.ViewManager;
7 | import java.util.ArrayList;
8 | import java.util.Collections;
9 | import java.util.List;
10 |
11 | public class AppOpsManagerModulePackage implements ReactPackage {
12 |
13 | @Override
14 | public List createViewManagers(ReactApplicationContext reactContext) {
15 | return Collections.emptyList();
16 | }
17 |
18 | @Override
19 | public List createNativeModules(ReactApplicationContext reactContext) {
20 | List modules = new ArrayList<>();
21 |
22 | modules.add(new AppOpsManagerModule(reactContext));
23 |
24 | return modules;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/android/app/src/main/java/com/lisk/ProviderInstallerPackage.java:
--------------------------------------------------------------------------------
1 | package io.lisk.mobile;
2 |
3 | import com.facebook.react.ReactPackage;
4 | import com.facebook.react.bridge.NativeModule;
5 | import com.facebook.react.bridge.ReactApplicationContext;
6 | import com.facebook.react.uimanager.ViewManager;
7 | import java.util.ArrayList;
8 | import java.util.Collections;
9 | import java.util.List;
10 |
11 | public class ProviderInstallerPackage implements ReactPackage {
12 |
13 | @Override
14 | public List createViewManagers(ReactApplicationContext reactContext) {
15 | return Collections.emptyList();
16 | }
17 |
18 | @Override
19 | public List createNativeModules(ReactApplicationContext reactContext) {
20 | List modules = new ArrayList<>();
21 |
22 | modules.add(new ProviderInstallerModule(reactContext));
23 |
24 | return modules;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/modules/Accounts/components/AccountDetails/AccountDetails.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View } from 'react-native';
3 |
4 | import { useTheme } from 'contexts/ThemeContext';
5 | import AccountCard from '../AccountCard/AccountCard';
6 | import getAccountDetailsStyles from './AccountDetails.styles';
7 | import MigrateToL2Card from '../MigrateToL2Card/MigrateToL2Card';
8 |
9 | /**
10 | * Renders a account detailed information (personal data, tokens and transactions) given an address.
11 | * @param {Object} account - Account to which render its information.
12 | */
13 | export default function AccountDetails({ account }) {
14 | const { styles } = useTheme({ styles: getAccountDetailsStyles() });
15 |
16 | return (
17 |
18 |
19 |
20 |
21 | );
22 | }
23 |
--------------------------------------------------------------------------------
/src/modules/Network/api/useNetworkStatusQuery.test.js:
--------------------------------------------------------------------------------
1 | import { renderHook } from '@testing-library/react-hooks';
2 |
3 | import { mockNetworkStatus } from '../__fixtures__';
4 | import { useNetworkStatusQuery } from './useNetworkStatusQuery';
5 | import { applicationsWrapper } from '../../../tests/applicationsWrapper';
6 |
7 | jest.useRealTimers();
8 |
9 | describe('useNetworkStatusQuery hook', () => {
10 | const wrapper = ({ children }) => applicationsWrapper({ children });
11 |
12 | it('fetches data correctly', async () => {
13 | const { result, waitFor } = renderHook(() => useNetworkStatusQuery(), {
14 | wrapper,
15 | });
16 |
17 | expect(result.current.isLoading).toBeTruthy();
18 |
19 | await waitFor(() => result.current.isFetched);
20 |
21 | expect(result.current.isSuccess).toBeTruthy();
22 |
23 | expect(result.current.data).toEqual(mockNetworkStatus);
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/src/utilities/qrCode.test.js:
--------------------------------------------------------------------------------
1 | import * as qrCode from './qrCode';
2 |
3 | describe('QR Code Helper', () => {
4 | it('decodes QR data that contains URL', () => {
5 | const data = 'lisk://wallet?recipient=1L&amount=1&reference=test';
6 | expect(qrCode.decodeLaunchUrl(data)).toEqual({
7 | address: '1L',
8 | amount: '1',
9 | reference: 'test',
10 | });
11 | });
12 |
13 | it('decodes QR data that contains URL and reference with space', () => {
14 | const data = 'lisk://wallet?recipient=1L&amount=1&reference=test%20mobile';
15 | expect(qrCode.decodeLaunchUrl(data)).toEqual({
16 | address: '1L',
17 | amount: '1',
18 | reference: 'test mobile',
19 | });
20 | });
21 |
22 | it('decodes QR data just address', () => {
23 | const data = '1L';
24 | expect(qrCode.decodeLaunchUrl(data)).toEqual({
25 | address: data,
26 | });
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/patches/@react-native-community+cli-platform-ios+6.0.0.patch:
--------------------------------------------------------------------------------
1 | diff --git a/node_modules/@react-native-community/cli-platform-ios/native_modules.rb b/node_modules/@react-native-community/cli-platform-ios/native_modules.rb
2 | index 1b6eece..18744c7 100644
3 | --- a/node_modules/@react-native-community/cli-platform-ios/native_modules.rb
4 | +++ b/node_modules/@react-native-community/cli-platform-ios/native_modules.rb
5 | @@ -43,6 +43,15 @@ def use_native_modules!(config = nil)
6 | found_pods = []
7 |
8 | packages.each do |package_name, package|
9 | +
10 | + # PATCH TO DISABLE CONFLICTING MODULES (duplicate symbols)
11 | + puts ">> package_name #{package_name}"
12 | +
13 | + next if %w(
14 | + react-native-udp
15 | + react-native-tcp
16 | + ).include?(package_name)
17 | +
18 | next unless package_config = package["platforms"]["ios"]
19 |
20 | podspec_path = package_config["podspecPath"]
21 |
--------------------------------------------------------------------------------
/src/modules/Auth/components/RecoveryPhraseSecurityAdviceCard/RecoveryPhraseSecurityAdviceCard.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View } from 'react-native';
3 | import i18next from 'i18next';
4 |
5 | import { useTheme } from 'contexts/ThemeContext';
6 | import { P } from 'components/shared/toolBox/typography';
7 |
8 | import { getRecoveryPhraseSecurityAdviceCardStyles } from './RecoveryPhraseSecurityAdviceCard.styles';
9 |
10 | export default function RecoveryPhraseSecurityAdviceCard({ style }) {
11 | const { styles } = useTheme({
12 | styles: getRecoveryPhraseSecurityAdviceCardStyles(),
13 | });
14 |
15 | return (
16 |
17 |
18 | {i18next.t('commons.recoveryPhrase.writeDownInstructions')}
19 |
20 |
21 | );
22 | }
23 |
--------------------------------------------------------------------------------
/libs/wcm/utils/error.js:
--------------------------------------------------------------------------------
1 | export const PARSE_ERROR = 'PARSE_ERROR';
2 | export const INVALID_REQUEST = 'INVALID_REQUEST';
3 | export const METHOD_NOT_FOUND = 'METHOD_NOT_FOUND';
4 | export const INVALID_PARAMS = 'INVALID_PARAMS';
5 | export const INTERNAL_ERROR = 'INTERNAL_ERROR';
6 | export const SERVER_ERROR = 'SERVER_ERROR';
7 |
8 | export const RESERVED_ERROR_CODES = [-32700, -32600, -32601, -32602, -32603];
9 | export const SERVER_ERROR_CODE_RANGE = [-32000, -32099];
10 |
11 | export const STANDARD_ERROR_MAP = {
12 | [PARSE_ERROR]: { code: -32700, message: 'Parse error' },
13 | [INVALID_REQUEST]: { code: -32600, message: 'Invalid Request' },
14 | [METHOD_NOT_FOUND]: { code: -32601, message: 'Method not found' },
15 | [INVALID_PARAMS]: { code: -32602, message: 'Invalid params' },
16 | [INTERNAL_ERROR]: { code: -32603, message: 'Internal error' },
17 | [SERVER_ERROR]: { code: -32000, message: 'Server error' },
18 | };
19 |
--------------------------------------------------------------------------------
/src/assets/svgs/CaretSvg.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Svg, Path } from 'react-native-svg';
3 |
4 | export default function CaretSvg({
5 | direction = 'right',
6 | color = 'currentColor',
7 | height = 20,
8 | width = 20,
9 | style,
10 | }) {
11 | let d;
12 |
13 | switch (direction) {
14 | case 'right':
15 | d = 'M6.5 4L13.5 10L6.5 16';
16 | break;
17 | case 'down':
18 | d = 'M4 6.5L10 13.5L16 6.5';
19 | break;
20 |
21 | case 'left':
22 | d = 'M13.5 4L6.5 10L13.5 16';
23 | break;
24 |
25 | case 'up':
26 | d = 'M16 13.5L10 6.5L4 13.5';
27 | break;
28 |
29 | default:
30 | break;
31 | }
32 |
33 | return (
34 |
37 | );
38 | }
39 |
--------------------------------------------------------------------------------
/src/modules/Transactions/api/useFeesQuery.js:
--------------------------------------------------------------------------------
1 | import { API_URL } from 'utilities/api/constants';
2 | import { GET_FEES_QUERY } from 'utilities/api/queries';
3 | import { useCustomQuery } from 'utilities/api/hooks/useCustomQuery';
4 | import { useQueryKeys } from 'utilities/api/hooks/useQueryKeys';
5 |
6 | /**
7 | * Requests fee estimates of a network.
8 | * @param {Object} config - Custom configurations for the query.
9 | * @param {Object} options - Custom options for the query.
10 | * @returns - The fee estimate per byte used for transaction fee calculation.
11 | */
12 | export function useFeesQuery({ config: customConfig = {}, options = {} } = {}) {
13 | const config = {
14 | url: `${API_URL}/fees`,
15 | method: 'GET',
16 | event: 'get.fees',
17 | ...customConfig,
18 | };
19 |
20 | const keys = useQueryKeys([GET_FEES_QUERY, config]);
21 |
22 | return useCustomQuery({ config, options, keys });
23 | }
24 |
--------------------------------------------------------------------------------
/src/components/shared/Skeleton/Skeleton.styles.js:
--------------------------------------------------------------------------------
1 | import { themes, colors } from 'constants/styleGuide';
2 |
3 | export function getSkeletonStyles({ width, height, variant }) {
4 | return {
5 | common: {
6 | container: {
7 | width,
8 | height: variant === 'circle' ? width : height,
9 | overflow: 'hidden',
10 | },
11 | animation: {
12 | position: 'absolute',
13 | top: 0,
14 | bottom: 0,
15 | right: 0,
16 | left: 0,
17 | },
18 | rectangleContainer: {
19 | borderRadius: 4,
20 | },
21 | circleContainer: {
22 | borderRadius: 50,
23 | },
24 | },
25 | [themes.light]: {
26 | container: {
27 | backgroundColor: colors.light.platinumGray,
28 | },
29 | },
30 | [themes.dark]: {
31 | container: {
32 | backgroundColor: colors.dark.textInputBg,
33 | },
34 | },
35 | };
36 | }
37 |
--------------------------------------------------------------------------------
/src/assets/svgs/ProgressSvg.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Svg, Path, Rect } from 'react-native-svg';
3 |
4 | export default ({ color, size = 1 }) => (
5 |
24 | );
25 |
--------------------------------------------------------------------------------
/src/hooks/useScreenshotPrevent.test.js:
--------------------------------------------------------------------------------
1 | import { renderHook } from '@testing-library/react-hooks';
2 | import RNScreenshotPrevent from 'react-native-screenshot-prevent';
3 |
4 | import useScreenshotPrevent from './useScreenshotPrevent';
5 |
6 | jest.mock('react-native-screenshot-prevent', () => ({
7 | enabled: jest.fn(),
8 | }));
9 |
10 | describe('useScreenshotPrevent hook', () => {
11 | it('should be defined', () => {
12 | expect(useScreenshotPrevent).toBeDefined();
13 | });
14 |
15 | it('enables/disables properly the functionality when mounting/unmounting', () => {
16 | const { unmount } = renderHook(() => useScreenshotPrevent());
17 |
18 | expect(RNScreenshotPrevent.enabled).toBeCalledTimes(1);
19 | expect(RNScreenshotPrevent.enabled).toBeCalledWith(true);
20 |
21 | unmount();
22 |
23 | expect(RNScreenshotPrevent.enabled).toBeCalledTimes(2);
24 | expect(RNScreenshotPrevent.enabled).toBeCalledWith(false);
25 | });
26 | });
27 |
--------------------------------------------------------------------------------
/src/modules/BlockchainApplication/components/DeleteApplicationSuccess/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import i18next from 'i18next';
3 |
4 | import ResultScreen from 'components/screens/ResultScreen';
5 | import { useTheme } from 'contexts/ThemeContext';
6 |
7 | import getStyles from './styles';
8 |
9 | export default function DeleteApplicationSuccess({ finalCallback, sharedData: { application } }) {
10 | const { styles } = useTheme({ styles: getStyles() });
11 |
12 | return (
13 |
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/android/app/src/main/java/com/lisk/RNArgon2Package.java:
--------------------------------------------------------------------------------
1 | package io.lisk.mobile;
2 |
3 | import com.facebook.react.ReactPackage;
4 | import com.facebook.react.bridge.JavaScriptModule;
5 | import com.facebook.react.bridge.NativeModule;
6 | import com.facebook.react.bridge.ReactApplicationContext;
7 | import com.facebook.react.uimanager.ViewManager;
8 |
9 | import java.util.ArrayList;
10 | import java.util.Collections;
11 | import java.util.List;
12 |
13 | public class RNArgon2Package implements ReactPackage {
14 | @Override
15 | public List createNativeModules(ReactApplicationContext reactContext) {
16 | List modules = new ArrayList<>();
17 |
18 | modules.add(new RNArgon2Module(reactContext));
19 | return modules;
20 | }
21 |
22 | @Override
23 | public List createViewManagers(ReactApplicationContext reactApplicationContext) {
24 | return Collections.emptyList();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/scripts/setupJestAfterEnv.js:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line import/no-extraneous-dependencies
2 | import { setupServer } from 'msw/node';
3 |
4 | import { MSWServer } from '../services/msw/MSWServer';
5 | import apiClient from '../src/utilities/api/APIClient';
6 | import liskAPIClient from '../src/utilities/api/LiskAPIClient';
7 |
8 | const mswTestServer = new MSWServer('test', setupServer);
9 |
10 | // Establish API mocking before all tests.
11 | beforeAll(() => {
12 | mswTestServer.init({ onUnhandledRequest: 'error' });
13 |
14 | apiClient.create({ ws: 'wss://localhost', http: 'http://localhost' });
15 | liskAPIClient.create({ ws: 'wss://localhost', http: 'http://localhost' });
16 | });
17 |
18 | // Reset any request handlers that we may add during the tests,
19 | // so they don't affect other tests.
20 | afterEach(() => mswTestServer.server.resetHandlers());
21 |
22 | // Clean up after the tests are finished.
23 | afterAll(() => mswTestServer.server.close());
24 |
--------------------------------------------------------------------------------
/src/assets/svgs/BookmarkSvg.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Svg, Path } from 'react-native-svg';
3 |
4 | export default () => (
5 |
13 | );
14 |
--------------------------------------------------------------------------------
/src/modules/BlockchainApplication/components/ApplicationsStats/components/ApplicationsStatsSkeleton.js:
--------------------------------------------------------------------------------
1 | import { View } from 'react-native';
2 | import React from 'react';
3 |
4 | import Skeleton from 'components/shared/Skeleton/Skeleton';
5 |
6 | /**
7 | * Skeleton UI placeholder for ApplicationsStats loading state.
8 | */
9 | export default function ApplicationsStatsSkeleton() {
10 | return (
11 |
12 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/src/modules/RequestToken/components/RequestTokenSelectField.styles.js:
--------------------------------------------------------------------------------
1 | import { themes, colors } from 'constants/styleGuide';
2 |
3 | export default function getRequestTokenSelectFieldStyles() {
4 | return {
5 | common: {
6 | row: {
7 | flexDirection: 'row',
8 | alignItems: 'center',
9 | justifyContent: 'center',
10 | },
11 | logo: {
12 | height: 24,
13 | width: 24,
14 | borderRadius: 16,
15 | marginLeft: 8,
16 | },
17 | primaryText: {
18 | color: colors.light.ultramarineBlue,
19 | },
20 | text: {
21 | fontSize: 16,
22 | },
23 | skeleton: {
24 | marginBottom: 16,
25 | },
26 | },
27 | [themes.light]: {
28 | text: {
29 | color: colors.light.zodiacBlue,
30 | },
31 | },
32 | [themes.dark]: {
33 | text: {
34 | color: colors.light.whiteSmoke,
35 | },
36 | },
37 | };
38 | }
39 |
--------------------------------------------------------------------------------
/src/assets/svgs/CurrencySvg.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Svg, Path } from 'react-native-svg';
3 |
4 | export default ({ color, style }) => (
5 |
20 | );
21 |
--------------------------------------------------------------------------------
/src/components/shared/DownloadFile/styles.js:
--------------------------------------------------------------------------------
1 | import { colors, themes, fonts } from 'constants/styleGuide';
2 |
3 | export default function getDeleteAccountFormStyles() {
4 | return {
5 | common: {
6 | container: {
7 | width: '100%',
8 | },
9 | row: {
10 | flexDirection: 'row',
11 | alignItems: 'center',
12 | justifyContent: 'center',
13 | },
14 | filenameContainer: {
15 | marginTop: 16,
16 | },
17 | text: {
18 | fontFamily: fonts.family.heading,
19 | fontSize: fonts.size.small,
20 | marginLeft: 8,
21 | maxWidth: 320,
22 | },
23 | downloadFileIcon: {
24 | marginLeft: 6,
25 | },
26 | },
27 | [themes.light]: {
28 | text: {
29 | color: colors.light.zodiacBlue,
30 | },
31 | },
32 |
33 | [themes.dark]: {
34 | text: {
35 | color: colors.light.white,
36 | },
37 | },
38 | };
39 | }
40 |
--------------------------------------------------------------------------------
/src/components/shared/toolBox/icon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { createIconSetFromIcoMoon } from 'react-native-vector-icons';
3 | import iconsConfig from 'assets/fonts/icons/selection.json';
4 |
5 | const Icomoon = createIconSetFromIcoMoon(iconsConfig);
6 |
7 | /**
8 | * Creates icon from Icomoon selection
9 | * in order to show an icon, the icon should exist in the font file
10 | *
11 | * @param {Object} props
12 | * @param {String} props.color - A valid Hex color code
13 | * @param {String} props.name - An icon name existing in our icons list
14 | * @param {Number} props.size - THe size of the icon in pixels, defaults to 35
15 | * @param {Object} props.style - styles from stylesheet
16 | * @param {Function} props.onPress - onPress event handler function
17 | */
18 | const Icon = ({ name, size, color, style, onPress }) => (
19 |
20 | );
21 |
22 | export default Icon;
23 |
--------------------------------------------------------------------------------
/src/navigation/components/TabBarIcon/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import { colors } from 'constants/styleGuide';
4 | import ApplicationsSvg from 'assets/svgs/ApplicationsSvg';
5 | import HomeSvg from 'assets/svgs/HomeSvg';
6 | import BookmarksSvg from 'assets/svgs/BookmarksSvg';
7 | import SettingsSvg from 'assets/svgs/SettingsSvg';
8 |
9 | export default function TabBarIcon({ name, focused, size = 24 }) {
10 | const props = {
11 | height: size,
12 | width: size,
13 | color: colors.light.white,
14 | variant: focused ? 'fill' : 'outline',
15 | };
16 |
17 | switch (name) {
18 | case 'AccountHome':
19 | return ;
20 |
21 | case 'Applications':
22 | return ;
23 |
24 | case 'Bookmarks':
25 | return ;
26 |
27 | case 'Settings':
28 | return ;
29 |
30 | default:
31 | return null;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/modules/Settings/components/HarmfulAppDetails/styles.js:
--------------------------------------------------------------------------------
1 | import { themes, colors, fonts } from 'constants/styleGuide';
2 |
3 | export default () => ({
4 | common: {
5 | row: {
6 | alignItems: 'center',
7 | marginBottom: 20,
8 | },
9 | packageName: {
10 | fontSize: fonts.size.base,
11 | fontFamily: fonts.family.context,
12 | textAlign: 'center',
13 | },
14 | description: {
15 | fontSize: fonts.size.base,
16 | fontFamily: fonts.family.context,
17 | textAlign: 'center',
18 | },
19 | appLogo: {
20 | height: 40,
21 | width: 40,
22 | borderRadius: 20,
23 | marginBottom: 10,
24 | },
25 | buttonContainer: {
26 | borderWidth: 0,
27 | },
28 | },
29 |
30 | [themes.light]: {
31 | text: {
32 | color: colors.light.maastrichtBlue,
33 | },
34 | },
35 |
36 | [themes.dark]: {
37 | text: {
38 | color: colors.dark.platinum,
39 | },
40 | },
41 | });
42 |
--------------------------------------------------------------------------------
/src/assets/svgs/CheckSvg.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Svg, Path } from 'react-native-svg';
3 |
4 | import colors from 'constants/styleGuide/colors';
5 |
6 | export default function CheckSvg({
7 | color = colors.light.ultramarineBlue,
8 | height = 9,
9 | width = 12,
10 | style,
11 | strokeWidth = 0,
12 | }) {
13 | return (
14 |
24 | );
25 | }
26 |
--------------------------------------------------------------------------------
/src/assets/svgs/WarningFilledSvg.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Svg, Path } from 'react-native-svg';
3 | import { themes, colors } from 'constants/styleGuide';
4 |
5 | export default ({ theme }) => (
6 |
14 | );
15 |
--------------------------------------------------------------------------------
/src/modules/Auth/components/DecryptRecoveryPhraseScreen/DecryptRecoveryPhraseScreen.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useNavigation, useRoute } from '@react-navigation/native';
3 | import { SafeAreaView } from 'react-native';
4 |
5 | import { useTheme } from 'contexts/ThemeContext';
6 | import DecryptRecoveryPhrase from '../DecryptRecoveryPhrase/DecryptRecoveryPhrase';
7 |
8 | import getStyles from './DecryptRecoveryPhraseScreen.styles';
9 |
10 | /**
11 | * Renders an decrypt recoveryPhrase screen details screen given an encryptedData.
12 | */
13 | export default function DecryptRecoveryPhraseScreen() {
14 | const navigation = useNavigation();
15 | const route = useRoute();
16 |
17 | const { styles } = useTheme({ styles: getStyles() });
18 |
19 | return (
20 |
21 |
22 |
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/src/modules/Auth/components/RecoveryPhraseScreen/RecoveryPhraseScreen.styles.js:
--------------------------------------------------------------------------------
1 | import { colors, themes, boxes, fonts } from 'constants/styleGuide';
2 |
3 | export default () => ({
4 | common: {
5 | wrapper: {
6 | flex: 1,
7 | },
8 | container: {
9 | flex: 1,
10 | paddingLeft: boxes.boxPadding,
11 | paddingRight: boxes.boxPadding,
12 | paddingBottom: boxes.boxPadding,
13 | },
14 | description: {
15 | fontFamily: fonts.family.context,
16 | fontSize: fonts.size.input,
17 | marginTop: 8,
18 | marginBottom: 16,
19 | },
20 | },
21 | [themes.light]: {
22 | wrapper: {
23 | backgroundColor: colors.dark.white,
24 | },
25 | description: {
26 | color: colors.light.smoothGray,
27 | },
28 | },
29 |
30 | [themes.dark]: {
31 | wrapper: {
32 | backgroundColor: colors.dark.black,
33 | },
34 | description: {
35 | color: colors.dark.mountainMist,
36 | },
37 | },
38 | });
39 |
--------------------------------------------------------------------------------
/src/components/shared/HeaderLogo/HeaderLogo.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View } from 'react-native';
3 |
4 | import { useTheme } from 'contexts/ThemeContext';
5 | import LiskMobileLogoSvg from 'assets/svgs/LiskMobileLogoSvg';
6 |
7 | import { getHeaderLogoStyles } from './HeaderLogo.styles';
8 |
9 | /**
10 | * Renders Lisk logo and project description in a single header component.
11 | * @param {Object} style - Custom styles for internal components (optional).
12 | * @param {React.CSSProperties} style.container - Custom styles for component main container.
13 | * @param {React.CSSProperties} style.logo - Custom styles for the logo.
14 | * @param {React.CSSProperties} style.title - Custom styles for the title.
15 | */
16 | export default function HeaderLogo({ style }) {
17 | const { styles } = useTheme({ styles: getHeaderLogoStyles() });
18 |
19 | return (
20 |
21 |
22 |
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/src/modules/Auth/api/useAuthQuery.test.js:
--------------------------------------------------------------------------------
1 | import { renderHook } from '@testing-library/react-hooks';
2 | import { applicationsWrapper } from '../../../tests/applicationsWrapper';
3 | import { mockSavedAccounts } from '../../Accounts/__fixtures__';
4 |
5 | import { mockAuth } from '../__fixtures__';
6 |
7 | import { useAuthQuery } from './useAuthQuery';
8 |
9 | jest.useRealTimers();
10 |
11 | describe('useAuthQuery hook', () => {
12 | const address = mockSavedAccounts[0].metadata.address;
13 |
14 | const wrapper = ({ children }) => applicationsWrapper({ children });
15 |
16 | it('fetches data correctly', async () => {
17 | const { result, waitFor } = renderHook(() => useAuthQuery(address), {
18 | wrapper,
19 | });
20 |
21 | expect(result.current.isLoading).toBeTruthy();
22 |
23 | await waitFor(() => result.current.isFetched);
24 |
25 | expect(result.current.isSuccess).toBeTruthy();
26 |
27 | expect(result.current.data.data).toEqual(mockAuth);
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/src/modules/BlockchainApplication/components/ApplicationsExplorer/styles.js:
--------------------------------------------------------------------------------
1 | import { themes, colors } from 'constants/styleGuide';
2 |
3 | export default function getBlockchainApplicationsExplorerStyles() {
4 | return {
5 | common: {
6 | header: {
7 | marginBottom: 24,
8 | },
9 | flex: {
10 | flex: 1,
11 | },
12 | body: {
13 | flex: 1,
14 | paddingLeft: 16,
15 | paddingRight: 16,
16 | },
17 | message: {
18 | padding: 20,
19 | },
20 | bridgeModal: {
21 | height: 350,
22 | },
23 | statsModalCloseButton: {
24 | position: 'absolute',
25 | right: 12,
26 | top: 24,
27 | zIndex: 1,
28 | },
29 | },
30 | [themes.light]: {
31 | message: {
32 | color: colors.light.zodiacBlue,
33 | },
34 | },
35 |
36 | [themes.dark]: {
37 | message: {
38 | color: colors.dark.white,
39 | },
40 | },
41 | };
42 | }
43 |
--------------------------------------------------------------------------------
/src/modules/Auth/components/CreateAccountButton/CreateAccountButton.styles.js:
--------------------------------------------------------------------------------
1 | import { colors, themes } from 'constants/styleGuide';
2 |
3 | export default function getCreateAccountStyles() {
4 | return {
5 | common: {
6 | container: {
7 | width: '100%',
8 | justifyContent: 'center',
9 | flexDirection: 'row',
10 | },
11 | question: {
12 | color: colors.light.slateGray,
13 | textAlign: 'center',
14 | marginRight: 4,
15 | marginBottom: 5,
16 | },
17 | link: {
18 | textAlign: 'center',
19 | },
20 | },
21 | [themes.light]: {
22 | question: {
23 | color: colors.light.zodiacBlue,
24 | },
25 | link: {
26 | color: colors.light.ultramarineBlue,
27 | },
28 | },
29 | [themes.dark]: {
30 | question: {
31 | color: colors.dark.white,
32 | },
33 | link: {
34 | color: colors.light.ultramarineBlue,
35 | },
36 | },
37 | };
38 | }
39 |
--------------------------------------------------------------------------------
/src/modules/Transactions/api/useTransactionQuery.test.js:
--------------------------------------------------------------------------------
1 | import { renderHook } from '@testing-library/react-hooks';
2 |
3 | import { mockGetTransactionQuery, mockTransactions } from '../__fixtures__';
4 | import { useTransactionQuery } from './useTransactionQuery';
5 | import { applicationsWrapper } from '../../../tests/applicationsWrapper';
6 |
7 | jest.useRealTimers();
8 |
9 | describe('useTransactionQuery hook', () => {
10 | const wrapper = ({ children }) => applicationsWrapper({ children });
11 |
12 | it('fetch data correctly', async () => {
13 | const { result, waitFor } = renderHook(() => useTransactionQuery(mockTransactions[0].id), {
14 | wrapper,
15 | });
16 |
17 | expect(result.current.isLoading).toBeTruthy();
18 |
19 | await waitFor(() => result.current.isFetched);
20 |
21 | expect(result.current.isSuccess).toBeTruthy();
22 |
23 | const expectedResponse = mockGetTransactionQuery;
24 |
25 | expect(result.current.data).toEqual(expectedResponse);
26 | });
27 | });
28 |
--------------------------------------------------------------------------------
/src/components/shared/DiscreteModeComponent/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View, Image } from 'react-native';
3 | import { useSelector } from 'react-redux';
4 |
5 | import { useTheme } from 'contexts/ThemeContext';
6 |
7 | import getStyles from './styles';
8 | import { BLUR_VARIANTS } from './constants';
9 | import { getDiscreteModeDataSize } from './utils';
10 |
11 | export default function DiscreteModeComponent({ children, blurVariant = 'incoming', data, style }) {
12 | const isDiscreteMode = useSelector((state) => state.settings.discrete);
13 |
14 | const { theme, styles } = useTheme({ styles: getStyles() });
15 |
16 | if (!isDiscreteMode) return children;
17 |
18 | const dataSize = getDiscreteModeDataSize(data);
19 |
20 | return (
21 |
22 |
26 |
27 | );
28 | }
29 |
--------------------------------------------------------------------------------
/src/components/screens/LoadingFallbackScreen/LoadingFallbackScreen.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { SafeAreaView, View } from 'react-native';
3 |
4 | import { useTheme } from 'contexts/ThemeContext';
5 | import LiskMobileLogoSvg from 'assets/svgs/LiskMobileLogoSvg';
6 | import LiskLogoAnimation from 'assets/animations/LiskLogoAnimation';
7 | import { colors } from 'constants/styleGuide';
8 |
9 | import { getLoadingFallbackScreenStyles } from './LoadingFallbackScreen.styles';
10 |
11 | /**
12 | * Fallback screen component for application loading state.
13 | */
14 | export default function LoadingFallbackScreen() {
15 | const { styles } = useTheme({ styles: getLoadingFallbackScreenStyles() });
16 |
17 | return (
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | );
26 | }
27 |
--------------------------------------------------------------------------------
/src/modules/Bookmark/components/EmptyState.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View, Image } from 'react-native';
3 | import { translate } from 'react-i18next';
4 | import { themes } from 'constants/styleGuide';
5 | import noBookmarkLightImg from 'assets/images/send/noBookmarks3xLight.png';
6 | import noBookmarkDarkImg from 'assets/images/send/noBookmarks3xDark.png';
7 | import { P } from 'components/shared/toolBox/typography';
8 | import withTheme from 'components/shared/withTheme';
9 | import getStyles from './styles';
10 |
11 | const EmptyState = ({ theme, styles, t, style }) => (
12 |
13 |
14 |
18 |
19 | {t('You don’t have any bookmarks.')}
20 |
21 | );
22 |
23 | export default withTheme(translate()(EmptyState), getStyles());
24 |
--------------------------------------------------------------------------------
/src/tests/constants/wallets.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable max-lines */
2 | const wallets = {
3 | genesis: {
4 | recoveryPhrase: 'peanut hundred pen hawk invite exclude brain chunk gadget wait wrong ready',
5 | summary: {
6 | publicKey: '0fe9a3f1a21b5530f27f87a414b549e79a940bf24fdf2b2f05e7f22aeeecc86a',
7 | serverPublicKey: '0fe9a3f1a21b5530f27f87a414b549e79a940bf24fdf2b2f05e7f22aeeecc86a',
8 | address: 'lskdxc4ta5j43jp9ro3f8zqbxta9fn6jwzjucw7yt',
9 | balance: '9897000000000000',
10 | isMigrated: true,
11 | isMultisignature: false,
12 | privateKey:
13 | 'ae7522b1fd7a24886b1396b392368fe6c9b2e0e40cf86ecf193e46babe3cbe8a0fe9a3f1a21b5530f27f87a414b549e79a940bf24fdf2b2f05e7f22aeeecc86a',
14 | },
15 | token: { balance: '9897000000000000' },
16 | sequence: { nonce: '1' },
17 | keys: { numberOfSignatures: 0, mandatoryKeys: [], optionalKeys: [] },
18 | dpos: {
19 | delegate: {},
20 | sentVotes: [],
21 | },
22 | },
23 | };
24 |
25 | export default wallets;
26 |
--------------------------------------------------------------------------------
/src/utilities/api/hooks/useIndexStatusQuery.js:
--------------------------------------------------------------------------------
1 | import { API_URL, METHOD } from 'utilities/api/constants';
2 | import { GET_INDEX_STATUS_QUERY } from 'utilities/api/queries';
3 | import { useCustomQuery } from 'utilities/api/hooks/useCustomQuery';
4 | import liskAPIClient from 'utilities/api/LiskAPIClient';
5 | import { useMemo } from 'react';
6 |
7 | export function useIndexStatusQuery() {
8 | const config = {
9 | url: `${API_URL}/index/status`,
10 | method: 'GET',
11 | event: 'get.index.status',
12 | };
13 |
14 | const keys = [GET_INDEX_STATUS_QUERY, config, METHOD];
15 |
16 | const options = {
17 | refetchInterval: 10000,
18 | refetchIntervalInBackground: false,
19 | };
20 |
21 | const query = useCustomQuery({ config, keys, options, client: liskAPIClient });
22 |
23 | const isLoading = useMemo(
24 | () => query.isLoading || query.data?.data.isIndexingInProgress,
25 | [query.isLoading, query.data?.data.isIndexingInProgress]
26 | );
27 |
28 | return { ...query, isLoading };
29 | }
30 |
--------------------------------------------------------------------------------
/src/assets/svgs/AddSvg.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Animated } from 'react-native';
3 | import { Svg, Path } from 'react-native-svg';
4 | import { colors } from 'constants/styleGuide';
5 |
6 | const AnimatedPath = Animated.createAnimatedComponent(Path);
7 |
8 | export default ({ color = colors.light.ultramarineBlue, height = 16, width = 16, style }) => (
9 |
17 | );
18 |
--------------------------------------------------------------------------------
/src/modules/BlockchainApplication/api/useApplicationsMetaQuery.test.js:
--------------------------------------------------------------------------------
1 | import { renderHook } from '@testing-library/react-hooks';
2 | import { applicationsWrapper } from '../../../tests/applicationsWrapper';
3 |
4 | import { mockApplicationsMeta } from '../__fixtures__';
5 |
6 | import { useApplicationsMetaQuery } from './useApplicationsMetaQuery';
7 |
8 | describe.skip('useApplicationsMetaQuery hook', () => {
9 | it('should fetch data correctly', async () => {
10 | const wrapper = ({ children }) => applicationsWrapper({ children });
11 |
12 | const { result, waitFor } = renderHook(() => useApplicationsMetaQuery(), { wrapper });
13 |
14 | await waitFor(() => result.current.isFetched);
15 |
16 | expect(result.current.isSuccess).toBeTruthy();
17 |
18 | const expectedResponse = {
19 | data: mockApplicationsMeta,
20 | meta: {
21 | count: mockApplicationsMeta.length,
22 | offset: 0,
23 | },
24 | };
25 |
26 | expect(result.current.data).toEqual(expectedResponse);
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/src/assets/svgs/DownloadSvg.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Svg, Path } from 'react-native-svg';
3 |
4 | export default function DownloadSvg({ color = '#4070F4', height = 16, width = 16, style }) {
5 | return (
6 |
16 | );
17 | }
18 |
--------------------------------------------------------------------------------
/src/modules/BlockchainApplication/components/ApplicationsStats/components/ApplicationsStatsLegendItem.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View } from 'react-native';
3 | import i18next from 'i18next';
4 |
5 | import { P } from 'components/shared/toolBox/typography';
6 | import { useTheme } from 'contexts/ThemeContext';
7 |
8 | import getStyles from '../ApplicationsStat.styles';
9 |
10 | export default function ApplicationsStatsLegendItem({ label, amount }) {
11 | const { styles } = useTheme({ styles: getStyles() });
12 |
13 | return (
14 |
15 |
16 |
17 |
18 |
19 | {amount}{' '}
20 |
21 | {i18next.t(`application.stats.${label}`)}
22 |
23 |
24 |
25 | );
26 | }
27 |
--------------------------------------------------------------------------------