├── .buckconfig ├── .eslintrc.js ├── .flowconfig ├── .gitattributes ├── .gitignore ├── .prettierrc.js ├── .watchmanconfig ├── README.md ├── __tests__ └── App-test.js ├── android ├── app │ ├── _BUCK │ ├── build.gradle │ ├── build_defs.bzl │ ├── debug.keystore │ ├── proguard-rules.pro │ └── src │ │ ├── assets │ │ └── fonts │ │ │ ├── Roboto-Black.ttf │ │ │ ├── Roboto-BlackItalic.ttf │ │ │ ├── Roboto-Bold.ttf │ │ │ ├── Roboto-BoldCondensed.ttf │ │ │ ├── Roboto-BoldCondensedItalic.ttf │ │ │ ├── Roboto-BoldItalic.ttf │ │ │ ├── Roboto-Condensed.ttf │ │ │ ├── Roboto-CondensedItalic.ttf │ │ │ ├── Roboto-Italic.ttf │ │ │ ├── Roboto-Light.ttf │ │ │ ├── Roboto-LightItalic.ttf │ │ │ ├── Roboto-Medium.ttf │ │ │ ├── Roboto-MediumItalic.ttf │ │ │ ├── Roboto-Regular.ttf │ │ │ ├── Roboto-Thin.ttf │ │ │ └── Roboto-ThinItalic.ttf │ │ ├── debug │ │ └── AndroidManifest.xml │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── assets │ │ ├── InpageBridgeWeb3.js │ │ └── fonts │ │ │ ├── antfill.ttf │ │ │ └── antoutline.ttf │ │ ├── java │ │ └── com │ │ │ └── qhwallet │ │ │ ├── MainActivity.java │ │ │ └── MainApplication.java │ │ └── res │ │ ├── ic_launcher.png │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-ldpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values │ │ ├── strings.xml │ │ └── styles.xml │ │ └── xml │ │ └── network_security_config.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle ├── app.json ├── babel.config.js ├── branch.json ├── index.js ├── ios ├── Podfile ├── QHWallet copy-Info.plist ├── QHWallet-tvOS │ └── Info.plist ├── QHWallet-tvOSTests │ └── Info.plist ├── QHWallet.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── QHWallet.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── QHWallet │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Base.lproj │ │ └── LaunchScreen.xib │ ├── Images.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── icon-1024.png │ │ │ ├── icon-20@2x-ipad.png │ │ │ ├── icon-20@3x.png │ │ │ ├── icon-29-ipad.png │ │ │ ├── icon-29@2x-ipad.png │ │ │ ├── icon-29@3x.png │ │ │ ├── icon-40@2x.png │ │ │ ├── icon-40@3x.png │ │ │ ├── icon-60@2x.png │ │ │ └── icon-60@3x.png │ │ └── Contents.json │ ├── Info.plist │ └── main.m ├── QHWalletTests │ ├── Info.plist │ └── QHWalletTests.m └── fonts │ ├── Roboto-Black.ttf │ ├── Roboto-BlackItalic.ttf │ ├── Roboto-Bold.ttf │ ├── Roboto-BoldCondensed.ttf │ ├── Roboto-BoldCondensedItalic.ttf │ ├── Roboto-BoldItalic.ttf │ ├── Roboto-Condensed.ttf │ ├── Roboto-CondensedItalic.ttf │ ├── Roboto-Italic.ttf │ ├── Roboto-Light.ttf │ ├── Roboto-LightItalic.ttf │ ├── Roboto-Medium.ttf │ ├── Roboto-MediumItalic.ttf │ ├── Roboto-Regular.ttf │ ├── Roboto-Thin.ttf │ └── Roboto-ThinItalic.ttf ├── metro.config.js ├── package.json ├── scripts └── build.sh └── src ├── App.js ├── components ├── Base │ └── RemoteImage │ │ ├── __snapshots__ │ │ └── index.test.js.snap │ │ ├── index.js │ │ └── index.test.js ├── ClearTitleBar.js ├── CoinHeader.js ├── CoinImage.js ├── Container.js ├── Drawer.js ├── DrawerIcon.js ├── FlatListLoadMoreView.js ├── LoadingIndicator.js ├── Separator.js ├── SvgIcon.js ├── TitleBar.js ├── TransactionSummary │ └── index.js └── UI │ ├── AccountApproval │ ├── index.js │ └── index.test.js │ ├── AccountInfoCard │ ├── index.js │ └── index.test.js │ ├── AccountInput │ └── index.js │ ├── AccountList │ ├── AccountElement │ │ └── index.js │ └── index.js │ ├── AccountOverview │ └── index.js │ ├── AccountSelect │ ├── index.js │ └── index.test.js │ ├── ActionModal │ ├── ActionContent │ │ └── index.js │ ├── index.js │ └── index.test.js │ ├── ActionView │ ├── index.js │ └── index.test.js │ ├── AddCustomCollectible │ ├── index.js │ └── index.test.js │ ├── AddCustomToken │ ├── index.js │ └── index.test.js │ ├── AddressQRCode │ └── index.js │ ├── AssetActionButtons │ ├── index.js │ └── index.test.js │ ├── AssetIcon │ ├── index.js │ └── index.test.js │ ├── AssetList │ ├── index.js │ └── index.test.js │ ├── AssetOverview │ ├── index.js │ └── index.test.js │ ├── AssetSearch │ ├── index.js │ └── index.test.js │ ├── BrowserBottomBar │ ├── index.js │ └── index.test.js │ ├── Button │ ├── index.js │ └── index.test.js │ ├── CollectibleImage │ ├── index.js │ └── index.test.js │ ├── CustomGas │ ├── index.js │ └── index.test.js │ ├── DrawerView │ ├── index.js │ └── index.test.js │ ├── EthInput │ ├── SelectableAsset │ │ └── index.js │ ├── index.js │ └── index.test.js │ ├── EthereumAddress │ └── index.js │ ├── FadeView │ ├── index.js │ └── index.test.js │ ├── GenericButton │ ├── index.android.js │ ├── index.ios.js │ └── index.test.js │ ├── Identicon │ ├── index.js │ └── index.test.js │ ├── NetworkList │ ├── index.js │ └── index.test.js │ ├── OnboardingWizard │ ├── Coachmark │ │ ├── index.js │ │ └── index.test.js │ ├── Step1 │ │ ├── index.js │ │ └── index.test.js │ ├── Step2 │ │ ├── index.js │ │ └── index.test.js │ ├── Step3 │ │ ├── index.js │ │ └── index.test.js │ ├── Step4 │ │ ├── index.js │ │ └── index.test.js │ ├── Step5 │ │ ├── index.js │ │ └── index.test.js │ ├── Step6 │ │ ├── index.js │ │ └── index.test.js │ ├── index.js │ ├── index.test.js │ └── styles.js │ ├── PhishingModal │ ├── index.js │ └── index.test.js │ ├── ReceiveRequest │ ├── ReceiveRequestAction │ │ ├── index.js │ │ └── index.test.js │ ├── index.js │ └── index.test.js │ ├── SearchTokenAutocomplete │ ├── index.js │ └── index.test.js │ ├── Tabs │ ├── TabCountIcon │ │ ├── index.js │ │ └── index.test.js │ ├── TabThumbnail │ │ ├── index.js │ │ └── index.test.js │ ├── index.js │ └── index.test.js │ ├── TokenImage │ ├── index.js │ └── index.test.js │ ├── Tokens │ ├── index.js │ └── index.test.js │ ├── TransactionActionModal │ ├── TransactionActionContent │ │ └── index.js │ └── index.js │ ├── TransactionEdit │ ├── index.js │ └── index.test.js │ ├── TransactionEditor │ ├── index.js │ └── index.test.js │ ├── TransactionElement │ ├── TransactionDetails │ │ ├── index.js │ │ └── index.test.js │ ├── index.js │ ├── index.test.js │ └── utils.js │ ├── TransactionHeader │ ├── index.js │ └── index.test.js │ ├── TransactionReview │ ├── TransactionReviewData │ │ ├── index.js │ │ └── index.test.js │ ├── TransactionReviewFeeCard │ │ ├── index.js │ │ └── index.test.js │ ├── TransactionReviewInformation │ │ ├── index.js │ │ └── index.test.js │ ├── TransactionReviewSummary │ │ ├── index.js │ │ └── index.test.js │ ├── index.js │ └── index.test.js │ ├── Transactions │ ├── index.js │ └── index.test.js │ ├── UrlAutocomplete │ ├── index.js │ └── index.test.js │ ├── WatchAssetRequest │ ├── index.js │ └── index.test.js │ ├── WebsiteIcon │ ├── index.js │ └── index.test.js │ ├── WebviewError │ └── index.js │ └── WebviewProgressBar │ ├── index.js │ └── index.test.js ├── config ├── abi │ └── cross.js └── const.js ├── entry.js ├── images ├── Common │ ├── decentralized.png │ ├── frog.png │ ├── fund.png │ └── open_source.png ├── Drawer │ ├── settings.png │ └── wallet.png ├── Tab │ ├── bitcoin_wallet_normal.png │ ├── bitcoin_wallet_selected.png │ ├── dapp_normal.png │ ├── dapp_selected.png │ ├── trade_normal.png │ └── trade_selected.png ├── Wallet │ ├── BTC.png │ ├── asset_invisual.png │ ├── asset_visual.png │ ├── erc20.png │ ├── fibos.png │ └── history_chart.png ├── eth-logo.png ├── qingah.png └── starting.png ├── locales ├── en.js ├── i18n.js └── zh.js ├── modules ├── common │ ├── AppInfo.js │ └── network.js ├── ironman │ ├── RenderIronman.js │ ├── index.js │ └── ironmanProxy.js ├── metamask │ ├── core │ │ ├── AppConstants.js │ │ ├── BackgroundBridge.js │ │ ├── DeeplinkManager.js │ │ ├── DrawerStatusTracker.js │ │ ├── Encryptor.js │ │ ├── Engine.js │ │ ├── Engine.test.js │ │ ├── EntryScriptWeb3.js │ │ ├── InpageBridgeWeb3.js │ │ ├── LockManager.js │ │ ├── MobilePortStream.js │ │ ├── PaymentChannelsClient.js │ │ ├── PreventScreenshot.js │ │ ├── SecureKeychain.js │ │ ├── TransactionTypes.js │ │ ├── TransactionsNotificationManager.js │ │ └── WalletConnect.js │ ├── cross.js │ └── index.js ├── okchain │ └── index.js ├── scatter │ ├── RenderScatter.js │ └── index.js └── tronweb │ ├── RenderTronWeb.js │ └── index.js ├── pages ├── AddAsset │ ├── index.js │ └── index.test.js ├── AddBookmark │ └── index.js ├── Approval │ ├── index.js │ └── index.test.js ├── ApproveView │ └── Approve │ │ ├── index.js │ │ └── index.test.js ├── Asset │ ├── index.js │ └── index.test.js ├── Browser │ └── index.js ├── BrowserTab │ ├── index.js │ └── index.test.js ├── CreateImport │ ├── BackupWallet.js │ ├── BackupWalletVerify.js │ ├── CreateImportWallet.js │ ├── CreateWalletSuccess.js │ ├── ImportMethod.js │ ├── InputPhrases.js │ ├── InputPrivateKey.js │ ├── NameWallet.js │ ├── PrivacyPolicies.js │ └── SelectTypes.js ├── Defi │ └── Defi.js ├── QRScanner │ └── index.js ├── SendFlow │ ├── AddressElement │ │ └── index.js │ ├── AddressInputs │ │ └── index.js │ ├── AddressList │ │ └── index.js │ ├── Amount │ │ └── index.js │ ├── Confirm │ │ └── index.js │ ├── CustomGas │ │ ├── index.js │ │ └── index.test.js │ ├── ErrorMessage │ │ ├── index.js │ │ └── index.test.js │ ├── SendTo │ │ ├── index.js │ │ └── index.test.js │ └── WarningMessage │ │ └── index.js ├── Settings │ ├── AboutUs.js │ ├── AddContacts.js │ ├── Contacts.js │ ├── Currency.js │ ├── Language.js │ ├── Security.js │ └── Settings.js ├── Splash │ ├── Splash.js │ └── Welcome.js ├── TransactionDirection │ ├── index.js │ └── index.test.js └── Wallet │ ├── AddWallet.js │ ├── ChangeWalletName.js │ ├── CreateNameWallet.js │ ├── DeleteWallet.js │ ├── History.js │ ├── Receive.js │ ├── ScanImage.js │ ├── SendCoin.js │ ├── VoteList.js │ ├── Wallet.js │ ├── WalletManagement.js │ ├── WalletSetting.js │ └── components │ ├── AssetsAction.js │ └── AssetsHeader.js ├── router.js ├── stores ├── account.js ├── account │ ├── Account.js │ ├── AccountStorage.js │ ├── CommonAccount.js │ ├── HDAccount.js │ └── MultiSigAccount.js ├── bookmarks.js ├── browser.js ├── common.js ├── engine.js ├── index.js ├── modals.js ├── price.js ├── privacy.js ├── settings.js ├── store.js ├── transaction.js ├── wallet.js ├── wallet │ ├── BTCWallet.js │ ├── Coin.js │ ├── CoinStore.js │ ├── CustomWallet.js │ ├── EOSWallet.js │ ├── ETHWallet.js │ ├── FOWallet.js │ ├── Fees.js │ ├── MultiSigWallet.js │ ├── OKTWallet.js │ ├── TRXWallet.js │ ├── Wallet.js │ ├── WalletTxStore.js │ ├── btc │ │ ├── BTCMultiSigWallet.js │ │ ├── BTCSegwit.js │ │ ├── BTCTransaction.js │ │ └── USDTTransaction.js │ └── util │ │ ├── address.js │ │ ├── base58.js │ │ ├── baseX.js │ │ ├── opcode.js │ │ └── serialize.js └── wizard.js ├── styles └── common.js ├── svgs └── getSvg.js ├── theme └── index.js └── utils ├── ENSUtils.js ├── GlobalNavigation.js ├── NumberUtil.js ├── Storage.js ├── Theme.js ├── Timer.js ├── address.js ├── assets.js ├── bip39Util.js ├── blockies.js ├── browser.js ├── browserScripts.js ├── btc.js ├── bytes.js ├── collectibles-transfer.json ├── common.js ├── crypto.js ├── currency-symbols.json ├── custom-gas.js ├── dapp-url-list.js ├── date.js ├── device.js ├── devices.js ├── ethereum.js ├── etherscan.js ├── iban.js ├── keychain.js ├── logger.js ├── middlewares.js ├── networks.js ├── number.js ├── payment-link-generator.js ├── request.js ├── streams.js ├── transaction-reducer-helpers.js └── transactions.js /.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | "parser": "babel-eslint", 4 | "env": { 5 | "browser": true, 6 | "node": true 7 | }, 8 | "extends": [ 9 | "@react-native-community", 10 | "airbnb", 11 | "prettier", 12 | "prettier/react", 13 | "plugin:jest/recommended" 14 | ], 15 | "plugins": [ 16 | "react", 17 | "jsx-a11y", 18 | "import", 19 | "prettier" 20 | ], 21 | "globals": { 22 | "__DEV__": true, 23 | "isNaN": true 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | ; We fork some components by platform 3 | .*/*[.]android.js 4 | 5 | ; Ignore "BUCK" generated dirs 6 | /\.buckd/ 7 | 8 | ; Ignore polyfills 9 | node_modules/react-native/Libraries/polyfills/.* 10 | 11 | ; These should not be required directly 12 | ; require from fbjs/lib instead: require('fbjs/lib/warning') 13 | node_modules/warning/.* 14 | 15 | ; Flow doesn't support platforms 16 | .*/Libraries/Utilities/LoadingView.js 17 | 18 | [untyped] 19 | .*/node_modules/@react-native-community/cli/.*/.* 20 | 21 | [include] 22 | 23 | [libs] 24 | node_modules/react-native/Libraries/react-native/react-native-interface.js 25 | node_modules/react-native/flow/ 26 | 27 | [options] 28 | emoji=true 29 | 30 | esproposal.optional_chaining=enable 31 | esproposal.nullish_coalescing=enable 32 | 33 | module.file_ext=.js 34 | module.file_ext=.json 35 | module.file_ext=.ios.js 36 | 37 | munge_underscores=true 38 | 39 | module.name_mapper='^react-native$' -> '/node_modules/react-native/Libraries/react-native/react-native-implementation' 40 | module.name_mapper='^react-native/\(.*\)$' -> '/node_modules/react-native/\1' 41 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> '/node_modules/react-native/Libraries/Image/RelativeImageStub' 42 | 43 | suppress_type=$FlowIssue 44 | suppress_type=$FlowFixMe 45 | suppress_type=$FlowFixMeProps 46 | suppress_type=$FlowFixMeState 47 | 48 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\) 49 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)?:? #[0-9]+ 50 | suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError 51 | 52 | [lints] 53 | sketchy-null-number=warn 54 | sketchy-null-mixed=warn 55 | sketchy-number=warn 56 | untyped-type-import=warn 57 | nonstrict-import=warn 58 | deprecated-type=warn 59 | unsafe-getters-setters=warn 60 | inexact-spread=warn 61 | unnecessary-invariant=warn 62 | signature-verification-failure=warn 63 | deprecated-utility=error 64 | 65 | [strict] 66 | deprecated-type 67 | nonstrict-import 68 | sketchy-null 69 | unclear-type 70 | unsafe-getters-setters 71 | untyped-import 72 | untyped-type-import 73 | 74 | [version] 75 | ^0.105.0 76 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | 24 | # Android/IntelliJ 25 | # 26 | build/ 27 | .idea 28 | .gradle 29 | local.properties 30 | *.iml 31 | 32 | # node.js 33 | # 34 | node_modules/ 35 | npm-debug.log 36 | yarn-error.log 37 | 38 | # BUCK 39 | buck-out/ 40 | \.buckd/ 41 | *.keystore 42 | !debug.keystore 43 | 44 | # fastlane 45 | # 46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 47 | # screenshots whenever they are needed. 48 | # For more information about the recommended setup visit: 49 | # https://docs.fastlane.tools/best-practices/source-control/ 50 | 51 | */fastlane/report.xml 52 | */fastlane/Preview.html 53 | */fastlane/screenshots 54 | 55 | # Bundle artifact 56 | *.jsbundle 57 | 58 | # CocoaPods 59 | /ios/Pods/ 60 | /ios/Podfile.lock 61 | /src/svgs/svgs.js 62 | yarn.lock 63 | package-lock.json 64 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | jsxBracketSameLine: true, 3 | // trailingComma: 'all', 4 | "printWidth": 160, 5 | "tabWidth": 2, 6 | "useTabs": false, 7 | "singleQuote": true, 8 | "semi": false, 9 | "trailingComma": "es5", 10 | "bracketSpacing": true, 11 | "arrowParens": "avoid" 12 | }; 13 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Qingah Wallet 2 | 3 | ## The ultimate decentralized Wallet 4 | 5 | ## Start 6 | 1. install `npm run autoInstall / yarn autoInstall` 7 | 2. start service`npm run start / yarn start` 8 | 3. debug `npm run ios / npm run android` 9 | 4. release ipa`npm run ipa-release` 10 | 5. release apk`npm run apk-release`(On windows, use `npm run apk-release-cmd`) 11 | 12 | [Wiki](https://github.com/kilmas/QHWallet/wiki) 13 | -------------------------------------------------------------------------------- /__tests__/App-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @format 3 | */ 4 | 5 | import 'react-native'; 6 | import React from 'react'; 7 | import App from '../App'; 8 | 9 | // Note: test renderer must be required after react-native. 10 | import renderer from 'react-test-renderer'; 11 | 12 | it('renders correctly', () => { 13 | renderer.create(); 14 | }); 15 | -------------------------------------------------------------------------------- /android/app/_BUCK: -------------------------------------------------------------------------------- 1 | # To learn about Buck see [Docs](https://buckbuild.com/). 2 | # To run your application with Buck: 3 | # - install Buck 4 | # - `npm start` - to start the packager 5 | # - `cd android` 6 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"` 7 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck 8 | # - `buck install -r android/app` - compile, install and run application 9 | # 10 | 11 | load(":build_defs.bzl", "create_aar_targets", "create_jar_targets") 12 | 13 | lib_deps = [] 14 | 15 | create_aar_targets(glob(["libs/*.aar"])) 16 | 17 | create_jar_targets(glob(["libs/*.jar"])) 18 | 19 | android_library( 20 | name = "all-libs", 21 | exported_deps = lib_deps, 22 | ) 23 | 24 | android_library( 25 | name = "app-code", 26 | srcs = glob([ 27 | "src/main/java/**/*.java", 28 | ]), 29 | deps = [ 30 | ":all-libs", 31 | ":build_config", 32 | ":res", 33 | ], 34 | ) 35 | 36 | android_build_config( 37 | name = "build_config", 38 | package = "com.qhwallet", 39 | ) 40 | 41 | android_resource( 42 | name = "res", 43 | package = "com.qhwallet", 44 | res = "src/main/res", 45 | ) 46 | 47 | android_binary( 48 | name = "app", 49 | keystore = "//android/keystores:debug", 50 | manifest = "src/main/AndroidManifest.xml", 51 | package_type = "debug", 52 | deps = [ 53 | ":app-code", 54 | ], 55 | ) 56 | -------------------------------------------------------------------------------- /android/app/build_defs.bzl: -------------------------------------------------------------------------------- 1 | """Helper definitions to glob .aar and .jar targets""" 2 | 3 | def create_aar_targets(aarfiles): 4 | for aarfile in aarfiles: 5 | name = "aars__" + aarfile[aarfile.rindex("/") + 1:aarfile.rindex(".aar")] 6 | lib_deps.append(":" + name) 7 | android_prebuilt_aar( 8 | name = name, 9 | aar = aarfile, 10 | ) 11 | 12 | def create_jar_targets(jarfiles): 13 | for jarfile in jarfiles: 14 | name = "jars__" + jarfile[jarfile.rindex("/") + 1:jarfile.rindex(".jar")] 15 | lib_deps.append(":" + name) 16 | prebuilt_jar( 17 | name = name, 18 | binary_jar = jarfile, 19 | ) 20 | -------------------------------------------------------------------------------- /android/app/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/android/app/debug.keystore -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /android/app/src/assets/fonts/Roboto-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/android/app/src/assets/fonts/Roboto-Black.ttf -------------------------------------------------------------------------------- /android/app/src/assets/fonts/Roboto-BlackItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/android/app/src/assets/fonts/Roboto-BlackItalic.ttf -------------------------------------------------------------------------------- /android/app/src/assets/fonts/Roboto-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/android/app/src/assets/fonts/Roboto-Bold.ttf -------------------------------------------------------------------------------- /android/app/src/assets/fonts/Roboto-BoldCondensed.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/android/app/src/assets/fonts/Roboto-BoldCondensed.ttf -------------------------------------------------------------------------------- /android/app/src/assets/fonts/Roboto-BoldCondensedItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/android/app/src/assets/fonts/Roboto-BoldCondensedItalic.ttf -------------------------------------------------------------------------------- /android/app/src/assets/fonts/Roboto-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/android/app/src/assets/fonts/Roboto-BoldItalic.ttf -------------------------------------------------------------------------------- /android/app/src/assets/fonts/Roboto-Condensed.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/android/app/src/assets/fonts/Roboto-Condensed.ttf -------------------------------------------------------------------------------- /android/app/src/assets/fonts/Roboto-CondensedItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/android/app/src/assets/fonts/Roboto-CondensedItalic.ttf -------------------------------------------------------------------------------- /android/app/src/assets/fonts/Roboto-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/android/app/src/assets/fonts/Roboto-Italic.ttf -------------------------------------------------------------------------------- /android/app/src/assets/fonts/Roboto-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/android/app/src/assets/fonts/Roboto-Light.ttf -------------------------------------------------------------------------------- /android/app/src/assets/fonts/Roboto-LightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/android/app/src/assets/fonts/Roboto-LightItalic.ttf -------------------------------------------------------------------------------- /android/app/src/assets/fonts/Roboto-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/android/app/src/assets/fonts/Roboto-Medium.ttf -------------------------------------------------------------------------------- /android/app/src/assets/fonts/Roboto-MediumItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/android/app/src/assets/fonts/Roboto-MediumItalic.ttf -------------------------------------------------------------------------------- /android/app/src/assets/fonts/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/android/app/src/assets/fonts/Roboto-Regular.ttf -------------------------------------------------------------------------------- /android/app/src/assets/fonts/Roboto-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/android/app/src/assets/fonts/Roboto-Thin.ttf -------------------------------------------------------------------------------- /android/app/src/assets/fonts/Roboto-ThinItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/android/app/src/assets/fonts/Roboto-ThinItalic.ttf -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 18 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/antfill.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/android/app/src/main/assets/fonts/antfill.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/antoutline.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/android/app/src/main/assets/fonts/antoutline.ttf -------------------------------------------------------------------------------- /android/app/src/main/java/com/qhwallet/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.qhwallet; 2 | 3 | import com.facebook.react.ReactActivity; 4 | 5 | public class MainActivity extends ReactActivity { 6 | 7 | /** 8 | * Returns the name of the main component registered from JavaScript. This is used to schedule 9 | * rendering of the component. 10 | */ 11 | @Override 12 | protected String getMainComponentName() { 13 | return "QHWallet"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /android/app/src/main/res/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/android/app/src/main/res/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-ldpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/android/app/src/main/res/mipmap-ldpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | QHWallet 3 | 4 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /android/app/src/main/res/xml/network_security_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext { 5 | buildToolsVersion = "29.0.3" 6 | minSdkVersion = 16 7 | compileSdkVersion = 29 8 | targetSdkVersion = 28 9 | } 10 | repositories { 11 | google() 12 | jcenter() 13 | } 14 | dependencies { 15 | classpath("com.android.tools.build:gradle:3.4.2") 16 | 17 | // NOTE: Do not place your application dependencies here; they belong 18 | // in the individual module build.gradle files 19 | } 20 | } 21 | 22 | allprojects { 23 | repositories { 24 | mavenLocal() 25 | maven { 26 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 27 | url("$rootDir/../node_modules/react-native/android") 28 | } 29 | maven { 30 | // Android JSC is installed from npm 31 | url("$rootDir/../node_modules/jsc-android/dist") 32 | } 33 | 34 | google() 35 | jcenter() 36 | maven { url 'https://jitpack.io' } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | android.useAndroidX=true 21 | android.enableJetifier=true 22 | 23 | MYAPP_RELEASE_STORE_FILE=qhwallet.keystore 24 | MYAPP_RELEASE_KEY_ALIAS=qhwallet 25 | MYAPP_RELEASE_STORE_PASSWORD=123456 26 | MYAPP_RELEASE_KEY_PASSWORD=123456 27 | 28 | # TODO: disable daemon on CI, since builds should be clean and reliable on servers 29 | org.gradle.daemon=true 30 | 31 | # Specifies the JVM arguments used for the daemon process. 32 | # The setting is particularly useful for tweaking memory settings. 33 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 34 | org.gradle.jvmargs=-Xmx8192M -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.5-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'QHWallet' 2 | apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) 3 | include ':app' 4 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "QHWallet", 3 | "displayName": "QHWallet" 4 | } -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['module:metro-react-native-babel-preset'], 3 | // sourceMaps: true, 4 | plugins: [ 5 | // ['@babel/plugin-transform-flow-strip-types'], 6 | ['@babel/plugin-proposal-decorators', { legacy: true }], 7 | ], 8 | env: { 9 | production: { 10 | plugins: ["transform-remove-console"] 11 | } 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /branch.json: -------------------------------------------------------------------------------- 1 | { 2 | "debugMode": true, 3 | "useTestInstance": true, 4 | "delayInitToCheckForSearchAds": true, 5 | "enableFacebookLinkCheck": true 6 | } -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @format 3 | */ 4 | 5 | // Node-specific polyfill 6 | import 'node-libs-react-native/globals'; 7 | 8 | import { AppRegistry } from 'react-native'; 9 | import App from './src/App'; 10 | import { name as appName } from './app.json'; 11 | 12 | AppRegistry.registerComponent(appName, () => App); 13 | -------------------------------------------------------------------------------- /ios/QHWallet-tvOS/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 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | NSAppTransportSecurity 26 | 27 | NSExceptionDomains 28 | 29 | localhost 30 | 31 | NSExceptionAllowsInsecureHTTPLoads 32 | 33 | 34 | 35 | 36 | NSLocationWhenInUseUsageDescription 37 | 38 | UILaunchStoryboardName 39 | LaunchScreen 40 | UIRequiredDeviceCapabilities 41 | 42 | armv7 43 | 44 | UISupportedInterfaceOrientations 45 | 46 | UIInterfaceOrientationPortrait 47 | UIInterfaceOrientationLandscapeLeft 48 | UIInterfaceOrientationLandscapeRight 49 | 50 | UIViewControllerBasedStatusBarAppearance 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /ios/QHWallet-tvOSTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 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 | -------------------------------------------------------------------------------- /ios/QHWallet.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/QHWallet.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/QHWallet.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/QHWallet/AppDelegate.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #import 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (nonatomic, strong) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /ios/QHWallet/AppDelegate.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #import "AppDelegate.h" 9 | 10 | #import 11 | #import 12 | #import 13 | 14 | @implementation AppDelegate 15 | 16 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 17 | { 18 | RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; 19 | RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge 20 | moduleName:@"QHWallet" 21 | initialProperties:nil]; 22 | 23 | rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; 24 | 25 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 26 | UIViewController *rootViewController = [UIViewController new]; 27 | rootViewController.view = rootView; 28 | self.window.rootViewController = rootViewController; 29 | [self.window makeKeyAndVisible]; 30 | return YES; 31 | } 32 | 33 | - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge 34 | { 35 | #if DEBUG 36 | return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil]; 37 | #else 38 | return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; 39 | #endif 40 | } 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /ios/QHWallet/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "icon-20@2x-ipad.png", 5 | "idiom" : "iphone", 6 | "scale" : "2x", 7 | "size" : "20x20" 8 | }, 9 | { 10 | "filename" : "icon-20@3x.png", 11 | "idiom" : "iphone", 12 | "scale" : "3x", 13 | "size" : "20x20" 14 | }, 15 | { 16 | "filename" : "icon-29-ipad.png", 17 | "idiom" : "iphone", 18 | "scale" : "1x", 19 | "size" : "29x29" 20 | }, 21 | { 22 | "filename" : "icon-29@2x-ipad.png", 23 | "idiom" : "iphone", 24 | "scale" : "2x", 25 | "size" : "29x29" 26 | }, 27 | { 28 | "filename" : "icon-29@3x.png", 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "29x29" 32 | }, 33 | { 34 | "filename" : "icon-40@2x.png", 35 | "idiom" : "iphone", 36 | "scale" : "2x", 37 | "size" : "40x40" 38 | }, 39 | { 40 | "filename" : "icon-40@3x.png", 41 | "idiom" : "iphone", 42 | "scale" : "3x", 43 | "size" : "40x40" 44 | }, 45 | { 46 | "filename" : "icon-60@2x.png", 47 | "idiom" : "iphone", 48 | "scale" : "2x", 49 | "size" : "60x60" 50 | }, 51 | { 52 | "filename" : "icon-60@3x.png", 53 | "idiom" : "iphone", 54 | "scale" : "3x", 55 | "size" : "60x60" 56 | }, 57 | { 58 | "filename" : "icon-1024.png", 59 | "idiom" : "ios-marketing", 60 | "scale" : "1x", 61 | "size" : "1024x1024" 62 | } 63 | ], 64 | "info" : { 65 | "author" : "xcode", 66 | "version" : 1 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /ios/QHWallet/Images.xcassets/AppIcon.appiconset/icon-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/ios/QHWallet/Images.xcassets/AppIcon.appiconset/icon-1024.png -------------------------------------------------------------------------------- /ios/QHWallet/Images.xcassets/AppIcon.appiconset/icon-20@2x-ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/ios/QHWallet/Images.xcassets/AppIcon.appiconset/icon-20@2x-ipad.png -------------------------------------------------------------------------------- /ios/QHWallet/Images.xcassets/AppIcon.appiconset/icon-20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/ios/QHWallet/Images.xcassets/AppIcon.appiconset/icon-20@3x.png -------------------------------------------------------------------------------- /ios/QHWallet/Images.xcassets/AppIcon.appiconset/icon-29-ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/ios/QHWallet/Images.xcassets/AppIcon.appiconset/icon-29-ipad.png -------------------------------------------------------------------------------- /ios/QHWallet/Images.xcassets/AppIcon.appiconset/icon-29@2x-ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/ios/QHWallet/Images.xcassets/AppIcon.appiconset/icon-29@2x-ipad.png -------------------------------------------------------------------------------- /ios/QHWallet/Images.xcassets/AppIcon.appiconset/icon-29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/ios/QHWallet/Images.xcassets/AppIcon.appiconset/icon-29@3x.png -------------------------------------------------------------------------------- /ios/QHWallet/Images.xcassets/AppIcon.appiconset/icon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/ios/QHWallet/Images.xcassets/AppIcon.appiconset/icon-40@2x.png -------------------------------------------------------------------------------- /ios/QHWallet/Images.xcassets/AppIcon.appiconset/icon-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/ios/QHWallet/Images.xcassets/AppIcon.appiconset/icon-40@3x.png -------------------------------------------------------------------------------- /ios/QHWallet/Images.xcassets/AppIcon.appiconset/icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/ios/QHWallet/Images.xcassets/AppIcon.appiconset/icon-60@2x.png -------------------------------------------------------------------------------- /ios/QHWallet/Images.xcassets/AppIcon.appiconset/icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/ios/QHWallet/Images.xcassets/AppIcon.appiconset/icon-60@3x.png -------------------------------------------------------------------------------- /ios/QHWallet/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /ios/QHWallet/main.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #import 9 | 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ios/QHWalletTests/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 | -------------------------------------------------------------------------------- /ios/QHWalletTests/QHWalletTests.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #import 9 | #import 10 | 11 | #import 12 | #import 13 | 14 | #define TIMEOUT_SECONDS 600 15 | #define TEXT_TO_LOOK_FOR @"Welcome to React" 16 | 17 | @interface QHWalletTests : XCTestCase 18 | 19 | @end 20 | 21 | @implementation QHWalletTests 22 | 23 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test 24 | { 25 | if (test(view)) { 26 | return YES; 27 | } 28 | for (UIView *subview in [view subviews]) { 29 | if ([self findSubviewInView:subview matching:test]) { 30 | return YES; 31 | } 32 | } 33 | return NO; 34 | } 35 | 36 | - (void)testRendersWelcomeScreen 37 | { 38 | UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; 39 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; 40 | BOOL foundElement = NO; 41 | 42 | __block NSString *redboxError = nil; 43 | #ifdef DEBUG 44 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { 45 | if (level >= RCTLogLevelError) { 46 | redboxError = message; 47 | } 48 | }); 49 | #endif 50 | 51 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { 52 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 53 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 54 | 55 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) { 56 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { 57 | return YES; 58 | } 59 | return NO; 60 | }]; 61 | } 62 | 63 | #ifdef DEBUG 64 | RCTSetLogFunction(RCTDefaultLogFunction); 65 | #endif 66 | 67 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); 68 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); 69 | } 70 | 71 | 72 | @end 73 | -------------------------------------------------------------------------------- /ios/fonts/Roboto-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/ios/fonts/Roboto-Black.ttf -------------------------------------------------------------------------------- /ios/fonts/Roboto-BlackItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/ios/fonts/Roboto-BlackItalic.ttf -------------------------------------------------------------------------------- /ios/fonts/Roboto-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/ios/fonts/Roboto-Bold.ttf -------------------------------------------------------------------------------- /ios/fonts/Roboto-BoldCondensed.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/ios/fonts/Roboto-BoldCondensed.ttf -------------------------------------------------------------------------------- /ios/fonts/Roboto-BoldCondensedItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/ios/fonts/Roboto-BoldCondensedItalic.ttf -------------------------------------------------------------------------------- /ios/fonts/Roboto-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/ios/fonts/Roboto-BoldItalic.ttf -------------------------------------------------------------------------------- /ios/fonts/Roboto-Condensed.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/ios/fonts/Roboto-Condensed.ttf -------------------------------------------------------------------------------- /ios/fonts/Roboto-CondensedItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/ios/fonts/Roboto-CondensedItalic.ttf -------------------------------------------------------------------------------- /ios/fonts/Roboto-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/ios/fonts/Roboto-Italic.ttf -------------------------------------------------------------------------------- /ios/fonts/Roboto-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/ios/fonts/Roboto-Light.ttf -------------------------------------------------------------------------------- /ios/fonts/Roboto-LightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/ios/fonts/Roboto-LightItalic.ttf -------------------------------------------------------------------------------- /ios/fonts/Roboto-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/ios/fonts/Roboto-Medium.ttf -------------------------------------------------------------------------------- /ios/fonts/Roboto-MediumItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/ios/fonts/Roboto-MediumItalic.ttf -------------------------------------------------------------------------------- /ios/fonts/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/ios/fonts/Roboto-Regular.ttf -------------------------------------------------------------------------------- /ios/fonts/Roboto-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/ios/fonts/Roboto-Thin.ttf -------------------------------------------------------------------------------- /ios/fonts/Roboto-ThinItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kilmas/QHWallet/dc1e153d9c96139bb9114a7837ffeb66aeb83401/ios/fonts/Roboto-ThinItalic.ttf -------------------------------------------------------------------------------- /metro.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Metro configuration for React Native 3 | * https://github.com/facebook/react-native 4 | * 5 | * @format 6 | */ 7 | 8 | const nodeLibs = require('node-libs-react-native'); 9 | // nodeLibs.bs58 = require.resolve('bs58'); 10 | nodeLibs.vm = require.resolve('vm-browserify'); 11 | nodeLibs.stream = require.resolve('stream-browserify'); 12 | 13 | module.exports = { 14 | resolver: { 15 | extraNodeModules: nodeLibs, 16 | }, 17 | transformer: { 18 | getTransformOptions: async () => ({ 19 | transform: { 20 | experimentalImportSupport: false, 21 | inlineRequires: false, 22 | }, 23 | }), 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import 'react-native-gesture-handler' 2 | import 'crypto-js' 3 | import 'mobx-react-lite/batchingForReactNative' 4 | import React from 'react' 5 | import { Platform } from 'react-native' 6 | import { Provider as Mobx } from 'mobx-react' 7 | import rootStore from './stores' 8 | import Entry from './entry' 9 | 10 | Platform.select({ 11 | ios: 'Press Cmd+R to reload,\n' + 'Cmd+D or shake for dev menu', 12 | android: 'Double tap R on your keyboard to reload,\n' + 'Shake or press menu button for dev menu', 13 | }) 14 | 15 | console.disableYellowBox = true 16 | 17 | class App extends React.Component { 18 | render() { 19 | return ( 20 | 21 | 22 | 23 | ) 24 | } 25 | } 26 | 27 | export default App 28 | -------------------------------------------------------------------------------- /src/components/Base/RemoteImage/__snapshots__/index.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`RemoteImage should render correctly 1`] = ` 4 | 7 | 17 | 18 | `; 19 | -------------------------------------------------------------------------------- /src/components/Base/RemoteImage/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { View, Image, ViewPropTypes } from 'react-native'; 4 | import FadeIn from 'react-native-fade-in-image'; 5 | // eslint-disable-next-line import/default 6 | import resolveAssetSource from 'react-native/Libraries/Image/resolveAssetSource'; 7 | import { SvgCssUri } from 'react-native-svg'; 8 | 9 | const RemoteImage = props => { 10 | const source = resolveAssetSource(props.source); 11 | if (source && (source.uri && source.uri.match('.svg'))) { 12 | const style = props.style || {}; 13 | if (source.__packager_asset && typeof style !== 'number') { 14 | if (!style.width) { 15 | style.width = source.width; 16 | } 17 | if (!style.height) { 18 | style.height = source.height; 19 | } 20 | } 21 | return ( 22 | 23 | 24 | 25 | ); 26 | } 27 | 28 | if (props.fadeIn) { 29 | return ( 30 | 31 | 32 | 33 | ); 34 | } 35 | return ; 36 | }; 37 | 38 | RemoteImage.propTypes = { 39 | /** 40 | * Flag that determines the fade in behavior 41 | */ 42 | fadeIn: PropTypes.bool, 43 | /** 44 | * Source of the image 45 | */ 46 | source: PropTypes.any, 47 | /** 48 | * Style for the image 49 | */ 50 | style: ViewPropTypes.style, 51 | /** 52 | * Style for the placeholder (used for fadeIn) 53 | */ 54 | placeholderStyle: ViewPropTypes.style 55 | }; 56 | 57 | export default RemoteImage; 58 | -------------------------------------------------------------------------------- /src/components/Base/RemoteImage/index.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { shallow } from 'enzyme'; 3 | import RemoteImage from './'; 4 | 5 | describe('RemoteImage', () => { 6 | it('should render correctly', () => { 7 | const wrapper = shallow( 8 | 13 | ); 14 | expect(wrapper).toMatchSnapshot(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/components/ClearTitleBar.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import { Text, TouchableOpacity, View } from 'react-native' 4 | import { Flex, Icon } from '@ant-design/react-native' 5 | import { withNavigation } from 'react-navigation' 6 | import { styles } from '../theme' 7 | import GlobalNavigation from '../utils/GlobalNavigation' 8 | import { statusBarHeight } from '../utils/device' 9 | 10 | class ClearTitleBar extends React.PureComponent { 11 | static defaultProps = { 12 | renderLeft: () => ( 13 | { 19 | GlobalNavigation.goBack() 20 | }}> 21 | 22 | 23 | ), 24 | renderRight: () => null, 25 | title: 'Miss a title', 26 | type: '', 27 | } 28 | 29 | static propTypes = { 30 | type: PropTypes.string, 31 | renderLeft: PropTypes.func, 32 | renderRight: PropTypes.func, 33 | title: PropTypes.string, 34 | } 35 | 36 | render() { 37 | return ( 38 | 39 | 40 | 46 | {this.props.title} 47 | 48 | 49 | {this.props.renderLeft()} 50 | {this.props.renderRight()} 51 | 52 | ) 53 | } 54 | } 55 | 56 | export default withNavigation(ClearTitleBar) 57 | -------------------------------------------------------------------------------- /src/components/CoinImage.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Image, StyleSheet } from 'react-native' 3 | import { Icon } from '@ant-design/react-native' 4 | 5 | export default class CoinImage extends React.Component { 6 | render() { 7 | const { coin, icon } = this.props 8 | switch (coin) { 9 | case 'BTC': 10 | return icon && 11 | case 'USDT': 12 | return icon && 13 | case 'ETH': 14 | return icon && 15 | case 'FO': 16 | return icon && 17 | case 'EOS': 18 | return icon && 19 | case 'OKT': 20 | return icon && 21 | case 'TRX': 22 | return icon && 23 | 24 | default: 25 | return 26 | } 27 | } 28 | } 29 | 30 | const styles = StyleSheet.create({ 31 | icon: { width: 65, height: 65 }, 32 | }) 33 | -------------------------------------------------------------------------------- /src/components/Container.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { View } from 'react-native'; 3 | 4 | function Container(props) { 5 | return ( 6 | 13 | {props.children} 14 | 15 | ); 16 | } 17 | 18 | export default Container; 19 | -------------------------------------------------------------------------------- /src/components/DrawerIcon.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | TouchableOpacity, 4 | } from 'react-native'; 5 | import { Badge, Icon } from '@ant-design/react-native'; 6 | import GlobalNavigation from '../utils/GlobalNavigation'; 7 | 8 | const DrawerIcon = (dot) => ( 9 | GlobalNavigation.toggleDrawer()}> 10 | 11 | 12 | 13 | 14 | ) 15 | 16 | export default DrawerIcon; -------------------------------------------------------------------------------- /src/components/FlatListLoadMoreView.js: -------------------------------------------------------------------------------- 1 | import React, { Component, PureComponent } from "react"; 2 | import { StyleSheet, View, ActivityIndicator, Text } from "react-native"; 3 | import PropTypes from "prop-types"; 4 | import { strings } from "../locales/i18n"; 5 | 6 | class FlatListLoadMoreView extends PureComponent { 7 | static propTypes = { 8 | status: PropTypes.oneOf(["empty", "loading", "nomore"]), 9 | text: PropTypes.string, 10 | }; 11 | 12 | static defaultProps = { 13 | status: "empty", 14 | text: `- ${strings("end line")} -`, 15 | }; 16 | 17 | render() { 18 | if (this.props.status === "empty") { 19 | return ; 20 | } 21 | return ( 22 | 23 | {this.props.status === "loading" ? ( 24 | 25 | ) : ( 26 | {this.props.text} 27 | )} 28 | 29 | ); 30 | } 31 | } 32 | 33 | const styles = StyleSheet.create({ 34 | container: { 35 | flex: 1, 36 | height: 62, 37 | alignItems: "center", 38 | justifyContent: "center", 39 | }, 40 | text: { 41 | fontSize: 12, 42 | color: '#333', 43 | }, 44 | }); 45 | export default FlatListLoadMoreView; 46 | -------------------------------------------------------------------------------- /src/components/LoadingIndicator.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react' 2 | import { ActivityIndicator, StyleSheet, Text, View } from 'react-native' 3 | import { deviceHeight } from '../utils/device' 4 | import { styles } from '../theme' 5 | 6 | export default class LoadingIndicator extends PureComponent { 7 | static propTypes = {} 8 | 9 | static defaultProps = {} 10 | 11 | state = { 12 | isShowLoading: false, 13 | mask: true, 14 | } 15 | showLoading = async mask => { 16 | //默认显示遮罩层mask 17 | let showMask = mask === undefined || mask === true 18 | 19 | if (this.state.isShowLoading === false) { 20 | this.setState( 21 | { 22 | mask: showMask, 23 | isShowLoading: true, 24 | }, 25 | () => { 26 | return null 27 | } 28 | ) 29 | } else { 30 | return null 31 | } 32 | } 33 | hideLoading = async () => { 34 | if (this.state.isShowLoading === true) { 35 | this.setState( 36 | { 37 | isShowLoading: false, 38 | }, 39 | () => { 40 | return null 41 | } 42 | ) 43 | } else { 44 | return null 45 | } 46 | } 47 | 48 | render() { 49 | if (this.state.isShowLoading === false) { 50 | return null 51 | } 52 | 53 | return ( 54 | 66 | 74 | 75 | 82 | Loading... 83 | 84 | 85 | 86 | ) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/components/Separator.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | import { StyleSheet, View } from 'react-native'; 4 | import { Flex } from '@ant-design/react-native'; 5 | 6 | class Separator extends React.PureComponent { 7 | static defaultProps = { 8 | style: {}, 9 | }; 10 | 11 | static propTypes = { 12 | style: PropTypes.object, 13 | }; 14 | 15 | render() { 16 | return ( 17 | 18 | 27 | 28 | ); 29 | } 30 | } 31 | 32 | export default Separator; 33 | -------------------------------------------------------------------------------- /src/components/SvgIcon.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { SvgXml } from 'react-native-svg'; 4 | import svgs from '../svgs/svgs'; 5 | 6 | export default 7 | class SvgIcon extends React.Component { 8 | static propTypes = { 9 | icon: PropTypes.string.isRequired, 10 | size: PropTypes.number, 11 | width: PropTypes.number, 12 | height: PropTypes.number, 13 | style: PropTypes.object, 14 | } 15 | 16 | static defaultProps = { 17 | style: {}, 18 | size: null, 19 | width: 0, 20 | height: 0, 21 | } 22 | 23 | render() { 24 | const svgXmlData = svgs[this.props.icon]; 25 | 26 | if (!svgXmlData) { 27 | const errMsg = `Miss "${this.props.icon}" svg file`; 28 | throw new Error(errMsg); 29 | } 30 | 31 | return ( 32 | 38 | ); 39 | } 40 | } -------------------------------------------------------------------------------- /src/components/TitleBar.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import { Text, TouchableOpacity, View } from 'react-native' 4 | import { Flex, Icon } from '@ant-design/react-native' 5 | import LinearGradient from 'react-native-linear-gradient' 6 | import { withNavigation } from 'react-navigation' 7 | import { statusBarHeight } from '../utils/device' 8 | import { styles, LGColor } from '../theme' 9 | import GlobalNavigation from '../utils/GlobalNavigation' 10 | 11 | class TitleBar extends React.PureComponent { 12 | static defaultProps = { 13 | renderLeft: () => ( 14 | { 17 | GlobalNavigation.goBack() 18 | }}> 19 | 20 | 21 | ), 22 | renderRight: () => null, 23 | title: '', 24 | } 25 | 26 | static propTypes = { 27 | renderLeft: PropTypes.func, 28 | renderRight: PropTypes.func, 29 | title: PropTypes.string, 30 | } 31 | 32 | render() { 33 | return ( 34 | 45 | 46 | 47 | 54 | {this.props.title} 55 | 56 | 57 | {this.props.renderLeft()} 58 | {this.props.renderRight()} 59 | 60 | 61 | ) 62 | } 63 | } 64 | 65 | export default withNavigation(TitleBar) 66 | -------------------------------------------------------------------------------- /src/components/UI/AccountApproval/index.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import AccountApproval from './' 3 | import { shallow } from 'enzyme' 4 | import configureMockStore from 'redux-mock-store' 5 | 6 | const mockStore = configureMockStore() 7 | 8 | describe('AccountApproval', () => { 9 | it('should render correctly', () => { 10 | const initialState = { 11 | engine: { 12 | backgroundState: { 13 | AccountTrackerController: { 14 | accounts: { '0x2': { balance: '0' } }, 15 | }, 16 | NetworkController: { 17 | provider: { 18 | type: 'ropsten', 19 | }, 20 | }, 21 | AssetsController: { 22 | tokens: [], 23 | }, 24 | PreferencesController: { 25 | selectedAddress: '0xe7E125654064EEa56229f273dA586F10DF96B0a1', 26 | identities: { '0xe7E125654064EEa56229f273dA586F10DF96B0a1': { name: 'Account 1' } }, 27 | }, 28 | }, 29 | }, 30 | } 31 | 32 | const wrapper = shallow(, { 33 | context: { store: mockStore(initialState) }, 34 | }) 35 | expect(wrapper.dive()).toMatchSnapshot() 36 | }) 37 | }) 38 | -------------------------------------------------------------------------------- /src/components/UI/AccountInfoCard/index.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { shallow } from 'enzyme' 3 | import configureMockStore from 'redux-mock-store' 4 | import AccountInfoCard from './' 5 | 6 | const mockStore = configureMockStore() 7 | 8 | describe('AccountInfoCard', () => { 9 | it('should render correctly', () => { 10 | const initialState = { 11 | engine: { 12 | backgroundState: { 13 | AccountTrackerController: { 14 | accounts: { 15 | '0x0': { 16 | balance: 200, 17 | }, 18 | }, 19 | }, 20 | PreferencesController: { 21 | selectedAddress: '0x0', 22 | identities: { 23 | address: '0x0', 24 | name: 'Account 1', 25 | }, 26 | }, 27 | CurrencyRateController: { 28 | conversionRate: 10, 29 | }, 30 | NetworkController: { 31 | provider: { 32 | ticker: 'eth', 33 | }, 34 | }, 35 | }, 36 | }, 37 | } 38 | 39 | const wrapper = shallow(, { 40 | context: { store: mockStore(initialState) }, 41 | }) 42 | expect(wrapper.dive()).toMatchSnapshot() 43 | }) 44 | }) 45 | -------------------------------------------------------------------------------- /src/components/UI/AccountSelect/index.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import AccountSelect from './'; 3 | import configureMockStore from 'redux-mock-store'; 4 | import { Provider } from 'mobx-react' 5 | import { shallow } from 'enzyme'; 6 | 7 | const mockStore = configureMockStore(); 8 | const store = mockStore({}); 9 | 10 | describe('AccountSelect', () => { 11 | it('should render correctly', () => { 12 | const wrapper = shallow( 13 | 14 | 15 | 16 | ); 17 | expect(wrapper).toMatchSnapshot(); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /src/components/UI/ActionModal/index.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { shallow } from 'enzyme' 3 | import ActionModal from './' 4 | 5 | describe('ActionModal', () => { 6 | it('should render correctly', () => { 7 | const wrapper = shallow() 8 | expect(wrapper).toMatchSnapshot() 9 | }) 10 | }) 11 | -------------------------------------------------------------------------------- /src/components/UI/ActionView/index.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { shallow } from 'enzyme' 3 | import ActionView from './' 4 | 5 | describe('ActionView', () => { 6 | it('should render correctly', () => { 7 | const wrapper = shallow() 8 | expect(wrapper).toMatchSnapshot() 9 | }) 10 | }) 11 | -------------------------------------------------------------------------------- /src/components/UI/AddCustomCollectible/index.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { shallow } from 'enzyme'; 3 | import AddCustomCollectible from './'; 4 | import configureMockStore from 'redux-mock-store'; 5 | 6 | const mockStore = configureMockStore(); 7 | 8 | describe('AddCustomCollectible', () => { 9 | it('should render correctly', () => { 10 | const initialState = { 11 | engine: { 12 | backgroundState: { 13 | PreferencesController: { 14 | selectedAddress: '0x1' 15 | } 16 | } 17 | } 18 | }; 19 | 20 | const wrapper = shallow(, { 21 | context: { store: mockStore(initialState) } 22 | }); 23 | expect(wrapper.dive()).toMatchSnapshot(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/components/UI/AddCustomToken/index.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { shallow } from 'enzyme'; 3 | import AddCustomToken from './'; 4 | 5 | describe('AddCustomToken', () => { 6 | it('should render correctly', () => { 7 | const wrapper = shallow(); 8 | expect(wrapper).toMatchSnapshot(); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /src/components/UI/AssetActionButtons/index.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { shallow } from 'enzyme' 3 | import AssetActionButtons from './' 4 | 5 | describe('AssetActionButtons', () => { 6 | it('should render correctly', () => { 7 | const wrapper = shallow() 8 | expect(wrapper).toMatchSnapshot() 9 | }) 10 | }) 11 | -------------------------------------------------------------------------------- /src/components/UI/AssetIcon/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { StyleSheet } from 'react-native'; 3 | import PropTypes from 'prop-types'; 4 | import RemoteImage from '../../Base/RemoteImage'; 5 | import getAssetLogoPath from '../../../utils/assets'; 6 | import { colors } from '../../../styles/common'; 7 | 8 | const styles = StyleSheet.create({ 9 | logo: { 10 | width: 50, 11 | height: 50 12 | } 13 | }); 14 | 15 | /** 16 | * PureComponent that provides an asset icon dependent on OS. 17 | */ 18 | // eslint-disable-next-line react/display-name 19 | const AssetIcon = React.memo(props => { 20 | if (!props.logo) return null; 21 | const uri = props.watchedAsset ? props.logo : getAssetLogoPath(props.logo); 22 | const style = [styles.logo, props.customStyle]; 23 | return ; 24 | }); 25 | 26 | AssetIcon.propTypes = { 27 | /** 28 | * String of the asset icon to be searched in contractMap 29 | */ 30 | logo: PropTypes.string, 31 | /** 32 | * Whether logo has to be fetched from eth-contract-metadata 33 | */ 34 | watchedAsset: PropTypes.bool, 35 | /** 36 | * Custom style to apply to image 37 | */ 38 | customStyle: PropTypes.object 39 | }; 40 | 41 | export default AssetIcon; 42 | -------------------------------------------------------------------------------- /src/components/UI/AssetIcon/index.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { shallow } from 'enzyme' 3 | import AssetIcon from './' 4 | 5 | describe('AssetIcon', () => { 6 | it('should render correctly', () => { 7 | const wrapper = shallow() 8 | expect(wrapper).toMatchSnapshot() 9 | }) 10 | }) 11 | -------------------------------------------------------------------------------- /src/components/UI/AssetList/index.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { shallow } from 'enzyme'; 3 | import AssetList from './'; 4 | 5 | describe('AssetList', () => { 6 | it('should render correctly', () => { 7 | const wrapper = shallow( 8 | 14 | ); 15 | expect(wrapper).toMatchSnapshot(); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /src/components/UI/AssetOverview/index.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import AssetOverview from './'; 3 | import configureMockStore from 'redux-mock-store'; 4 | import { shallow } from 'enzyme'; 5 | import { Provider } from 'mobx-react' 6 | 7 | const mockStore = configureMockStore(); 8 | const store = mockStore({}); 9 | 10 | describe('AssetOverview', () => { 11 | it('should render correctly', () => { 12 | const initialState = { 13 | settings: { 14 | primaryCurrency: 'ETH' 15 | } 16 | }; 17 | const asset = { 18 | balance: 4, 19 | balanceFiat: 1500, 20 | logo: 'https://upload.wikimedia.org/wikipedia/commons/0/05/Ethereum_logo_2014.svg', 21 | symbol: 'ETH', 22 | name: 'Ethereum' 23 | }; 24 | 25 | const wrapper = shallow( 26 | 27 | 28 | , 29 | { 30 | context: { store: mockStore(initialState) } 31 | } 32 | ); 33 | expect(wrapper).toMatchSnapshot(); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /src/components/UI/AssetSearch/index.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { shallow } from 'enzyme'; 3 | import AssetSearch from './'; 4 | 5 | describe('AssetSearch', () => { 6 | it('should render correctly', () => { 7 | const wrapper = shallow(); 8 | expect(wrapper).toMatchSnapshot(); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /src/components/UI/BrowserBottomBar/index.test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable react/jsx-no-bind */ 2 | import React from 'react' 3 | import { shallow } from 'enzyme' 4 | import BrowserBottomBar from './' 5 | 6 | describe('BrowserBottomBar', () => { 7 | it('should render correctly', () => { 8 | const fn = () => null 9 | 10 | const wrapper = shallow() 11 | expect(wrapper).toMatchSnapshot() 12 | }) 13 | }) 14 | -------------------------------------------------------------------------------- /src/components/UI/Button/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { ViewPropTypes, StyleSheet } from 'react-native'; 4 | import GenericButton from '../GenericButton'; // eslint-disable-line import/no-unresolved 5 | import { colors } from '../../../styles/common'; 6 | 7 | const styles = StyleSheet.create({ 8 | button: { 9 | flex: 1, 10 | alignItems: 'center', 11 | justifyContent: 'center', 12 | backgroundColor: colors.blue, 13 | paddingVertical: 10, 14 | paddingHorizontal: 15, 15 | height: 40, 16 | borderRadius: 4 17 | } 18 | }); 19 | 20 | /** 21 | * UI component that wraps GenericButton 22 | * which renders the appropiate UI elements for each platform (android & iOS) 23 | */ 24 | const Button = props => ( 25 | 26 | {props.children} 27 | 28 | ); 29 | 30 | Button.propTypes = { 31 | /** 32 | * Children components of the Button 33 | * it can be a text node, an image, or an icon 34 | * or an Array with a combination of them 35 | */ 36 | children: PropTypes.any, 37 | /** 38 | * Styles to be applied to the Button 39 | */ 40 | style: ViewPropTypes.style, 41 | /** 42 | * Function to be called on press 43 | */ 44 | onPress: PropTypes.func 45 | }; 46 | 47 | export default Button; 48 | -------------------------------------------------------------------------------- /src/components/UI/Button/index.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { shallow } from 'enzyme' 3 | import Button from './' 4 | 5 | describe('Button', () => { 6 | it('should render correctly', () => { 7 | const wrapper = shallow( 61 | 62 | 63 | ) 64 | } 65 | } 66 | 67 | export default PrivacyPolicies 68 | -------------------------------------------------------------------------------- /src/pages/SendFlow/CustomGas/index.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { shallow } from 'enzyme' 3 | import CustomGas from './' 4 | import configureMockStore from 'redux-mock-store' 5 | 6 | describe('CustomGas', () => { 7 | const mockStore = configureMockStore() 8 | it('should render correctly', () => { 9 | const initialState = { 10 | engine: { 11 | backgroundState: { 12 | NetworkController: { 13 | provider: { 14 | ticker: 'ETH', 15 | }, 16 | }, 17 | CurrencyRateController: { 18 | currentCurrency: 'USD', 19 | conversionRate: 1, 20 | }, 21 | }, 22 | }, 23 | } 24 | const wrapper = shallow(, { 25 | context: { store: mockStore(initialState) }, 26 | }) 27 | expect(wrapper.dive()).toMatchSnapshot() 28 | }) 29 | }) 30 | -------------------------------------------------------------------------------- /src/pages/SendFlow/ErrorMessage/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { StyleSheet, View, Text } from 'react-native' 3 | import PropTypes from 'prop-types' 4 | import { colors, fontStyles } from '../../../styles/common' 5 | 6 | const styles = StyleSheet.create({ 7 | wrapper: { 8 | backgroundColor: colors.red000, 9 | borderWidth: 1, 10 | borderColor: colors.red, 11 | borderRadius: 4, 12 | padding: 15, 13 | }, 14 | errorMessage: { 15 | ...fontStyles.normal, 16 | fontSize: 12, 17 | color: colors.red, 18 | flexDirection: 'row', 19 | alignItems: 'center', 20 | }, 21 | }) 22 | 23 | export default function ErrorMessage(props) { 24 | const { errorMessage } = props 25 | return ( 26 | 27 | {errorMessage} 28 | 29 | ) 30 | } 31 | 32 | ErrorMessage.propTypes = { 33 | /** 34 | * Error message to display 35 | */ 36 | errorMessage: PropTypes.string, 37 | } 38 | -------------------------------------------------------------------------------- /src/pages/SendFlow/ErrorMessage/index.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { shallow } from 'enzyme' 3 | import ErrorMessage from './' 4 | import configureMockStore from 'redux-mock-store' 5 | 6 | describe('ErrorMessage', () => { 7 | const mockStore = configureMockStore() 8 | it('should render correctly', () => { 9 | const initialState = {} 10 | 11 | const wrapper = shallow(, { 12 | context: { store: mockStore(initialState) }, 13 | }) 14 | expect(wrapper.dive()).toMatchSnapshot() 15 | }) 16 | }) 17 | -------------------------------------------------------------------------------- /src/pages/SendFlow/WarningMessage/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { StyleSheet, View, Text } from 'react-native' 3 | import PropTypes from 'prop-types' 4 | import { Icon } from '@ant-design/react-native' 5 | import { colors, fontStyles } from '../../../styles/common' 6 | 7 | const styles = StyleSheet.create({ 8 | wrapper: { 9 | backgroundColor: colors.yellow100, 10 | borderWidth: 1, 11 | borderColor: colors.yellow, 12 | borderRadius: 4, 13 | padding: 8, 14 | flexDirection: 'row', 15 | }, 16 | errorMessage: { 17 | ...fontStyles.normal, 18 | flex: 1, 19 | fontSize: 12, 20 | color: colors.grey, 21 | flexDirection: 'row', 22 | alignItems: 'center', 23 | }, 24 | icon: { 25 | paddingRight: 8, 26 | }, 27 | iconWrapper: { 28 | alignItems: 'center', 29 | flexDirection: 'row', 30 | alignSelf: 'flex-start', 31 | }, 32 | }) 33 | 34 | export default function WarningMessage(props) { 35 | const { warningMessage } = props 36 | return ( 37 | 38 | 39 | 40 | 41 | {warningMessage} 42 | 43 | ) 44 | } 45 | 46 | WarningMessage.propTypes = { 47 | /** 48 | * Warning message to display 49 | */ 50 | warningMessage: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), 51 | } 52 | -------------------------------------------------------------------------------- /src/pages/Settings/Currency.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Text, TouchableOpacity } from 'react-native' 3 | import { Radio } from '@ant-design/react-native' 4 | import { inject, observer } from 'mobx-react' 5 | import TitleBar from '../../components/TitleBar' 6 | import { strings } from '../../locales/i18n' 7 | import Container from '../../components/Container' 8 | import GlobalNavigation from '../../utils/GlobalNavigation' 9 | import { BGGray, styles as themeStyles } from '../../theme' 10 | import CoinStore from '../../stores/wallet/CoinStore' 11 | 12 | @inject('store') 13 | @observer 14 | class Currency extends React.Component { 15 | state = { 16 | currency: { 17 | name: 'USD', 18 | unit: '$', 19 | }, 20 | list: [ 21 | { 22 | name: 'CNY', 23 | unit: '¥', 24 | }, 25 | { 26 | name: 'USD', 27 | unit: '$', 28 | }, 29 | ], 30 | } 31 | 32 | async componentDidMount() { 33 | this.setState({ 34 | currency: { 35 | name: CoinStore.currency, 36 | unit: CoinStore.currencySymbol, 37 | }, 38 | }) 39 | } 40 | 41 | render() { 42 | return ( 43 | 44 | ( 48 | { 51 | // this.props.store.settings.setCurrency(this.state.currency) 52 | CoinStore.setCurrency(this.state.currency.name) 53 | GlobalNavigation.goBack() 54 | }}> 55 | {strings('save')} 56 | 57 | )} 58 | /> 59 | {this.state.list.map(({ name, unit }, index) => ( 60 | { 64 | if (event.target.checked) { 65 | this.setState({ currency: { name, unit } }) 66 | } 67 | }}> 68 | {name} 69 | 70 | ))} 71 | 72 | ) 73 | } 74 | } 75 | 76 | export default Currency 77 | -------------------------------------------------------------------------------- /src/pages/Settings/Language.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Text, TouchableOpacity } from 'react-native' 3 | import { Radio } from '@ant-design/react-native' 4 | import { inject, observer } from 'mobx-react' 5 | import i18n from 'react-native-i18n' 6 | import TitleBar from '../../components/TitleBar' 7 | import { strings } from '../../locales/i18n' 8 | import Container from '../../components/Container' 9 | import GlobalNavigation from '../../utils/GlobalNavigation' 10 | import { BGGray, styles as themeStyles } from '../../theme' 11 | 12 | @inject('store') 13 | @observer 14 | class Language extends React.Component { 15 | state = { 16 | language: { 17 | name: 'English', 18 | locale: 'en', 19 | }, 20 | list: [ 21 | { 22 | name: 'English', 23 | locale: 'en', 24 | }, 25 | { 26 | name: '简体中文', 27 | locale: 'zh', 28 | }, 29 | ], 30 | } 31 | 32 | async componentDidMount() { 33 | this.setState({ language: this.props.store.settings.language }) 34 | } 35 | 36 | render() { 37 | const { language } = this.state 38 | return ( 39 | 40 | ( 44 | { 47 | i18n.locale = language.locale 48 | this.props.store.settings.setLanguage(language) 49 | GlobalNavigation.reset('Splash') 50 | }}> 51 | {strings('save')} 52 | 53 | )} 54 | /> 55 | {this.state.list.map(({ name, locale }, index) => ( 56 | { 60 | if (event.target.checked) { 61 | this.setState({ language: { name, locale } }) 62 | } 63 | }}> 64 | {name} 65 | 66 | ))} 67 | 68 | ) 69 | } 70 | } 71 | export default Language 72 | -------------------------------------------------------------------------------- /src/pages/Splash/Splash.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Image, ActivityIndicator } from 'react-native' 3 | import { when } from 'mobx' 4 | import { inject, observer } from 'mobx-react' 5 | import Container from '../../components/Container' 6 | import GlobalNavigation from '../../utils/GlobalNavigation' 7 | import { styles as themeStyles } from '../../theme' 8 | import SecureKeychain from '../../modules/metamask/core/SecureKeychain' 9 | import Engine from '../../modules/metamask/core/Engine' 10 | import AppInfo from '../../modules/common/AppInfo' 11 | 12 | @inject('store') 13 | @observer 14 | class Splash extends React.Component { 15 | componentDidMount() { 16 | // SecureKeychain.resetGenericPassword() 17 | const { accountStore } = this.props.store 18 | when( 19 | () => accountStore.isInit, 20 | () => { 21 | this.goNext(true, accountStore.currentAccount) 22 | } 23 | ) 24 | this.goNext(accountStore.isInit, accountStore.currentAccount) 25 | AppInfo.checkUpdate() 26 | } 27 | 28 | goNext = async (isInit, currentAccount) => { 29 | if (isInit) { 30 | if (currentAccount) { 31 | try { 32 | const credentials = await SecureKeychain.getGenericPassword() 33 | if (credentials) { 34 | const { accountStore } = this.props.store 35 | accountStore.setPwd(true) 36 | accountStore.checkHdAccount() 37 | const { KeyringController } = Engine.context 38 | KeyringController.submitPassword(credentials.password) 39 | GlobalNavigation.reset('TabDrawer') 40 | } 41 | } catch (error) { 42 | console.warn(error) 43 | } 44 | return 45 | } 46 | GlobalNavigation.reset('Welcome') 47 | } 48 | } 49 | 50 | render() { 51 | const { accountStore } = this.props.store 52 | 53 | return ( 54 | 55 | {!accountStore.isInit ? : } 56 | 57 | ) 58 | } 59 | } 60 | 61 | export default Splash 62 | -------------------------------------------------------------------------------- /src/pages/TransactionDirection/index.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { shallow } from 'enzyme'; 3 | import TransactionDirection from './'; 4 | import configureMockStore from 'redux-mock-store'; 5 | 6 | const mockStore = configureMockStore(); 7 | 8 | describe('TransactionDirection', () => { 9 | it('should render correctly', () => { 10 | const initialState = { 11 | transaction: {}, 12 | engine: { 13 | backgroundState: { 14 | PreferencesController: { 15 | identities: { '0x1': { name: 'Account 1' } } 16 | } 17 | } 18 | } 19 | }; 20 | 21 | const wrapper = shallow(, { 22 | context: { store: mockStore(initialState) } 23 | }); 24 | expect(wrapper).toMatchSnapshot(); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /src/pages/Wallet/CreateNameWallet.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Text, TextInput, TouchableOpacity, View, StyleSheet } from 'react-native' 3 | import Container from '../../components/Container' 4 | import { styles as themeStyles, BGGray } from '../../theme' 5 | import { strings } from '../../locales/i18n' 6 | import TitleBar from '../../components/TitleBar' 7 | import GlobalNavigation from '../../utils/GlobalNavigation' 8 | import { inject, observer } from 'mobx-react' 9 | 10 | @inject('store') 11 | @observer 12 | class CreateNameWallet extends React.Component { 13 | render() { 14 | return ( 15 | 16 | 17 | 18 | {strings('wallet.nameWallet')} 19 | 20 | { 23 | GlobalNavigation.navigate('AddWallet') 24 | }}> 25 | {strings('next')} 26 | 27 | 28 | 29 | ) 30 | } 31 | } 32 | 33 | const styles = StyleSheet.create({ 34 | content: { 35 | paddingHorizontal: 23, 36 | paddingVertical: 18, 37 | }, 38 | contentTitle: { 39 | fontSize: 23, 40 | fontWeight: '500', 41 | color: '#0A113B', 42 | alignSelf: 'flex-start', 43 | }, 44 | textInput: { 45 | width: 320, 46 | height: 44, 47 | backgroundColor: BGGray, 48 | borderRadius: 5, 49 | marginTop: 25, 50 | marginBottom: 50, 51 | paddingHorizontal: 13, 52 | color: '#000000', 53 | }, 54 | }) 55 | 56 | export default CreateNameWallet 57 | -------------------------------------------------------------------------------- /src/pages/Wallet/ScanImage.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { RNCamera } from 'react-native-camera' 3 | import { inject, observer } from 'mobx-react' 4 | import { Toast } from '@ant-design/react-native' 5 | import BarcodeMask from 'react-native-barcode-mask' 6 | import Container from '../../components/Container' 7 | import TitleBar from '../../components/TitleBar' 8 | 9 | @inject('store') 10 | @observer 11 | class ScanImage extends React.Component { 12 | 13 | render() { 14 | return ( 15 | 16 | { 24 | Toast.info(code.data, 1); 25 | this.props.navigation.goBack(); 26 | this.props.navigation.state.params.onSave(code.data); 27 | }}> 28 | 34 | 35 | 36 | 37 | ) 38 | } 39 | } 40 | 41 | export default ScanImage 42 | -------------------------------------------------------------------------------- /src/stores/account/Account.js: -------------------------------------------------------------------------------- 1 | import { computed, observable } from "mobx"; 2 | import _ from "lodash"; 3 | import CryptoJS from "crypto-js" 4 | import { persist } from 'mobx-persist' 5 | 6 | class Account { 7 | @persist @observable id = null; 8 | /** 9 | * 10 | * @type { String } 11 | * @memberof MultiChainAccount 12 | */ 13 | @persist @observable name = ''; 14 | @persist @observable type = null; 15 | @computed get totalAsset() { 16 | throw new Error("not implemented totalAsset"); 17 | } 18 | @computed get floatingAsset() { 19 | throw new Error("not implemented floatingAsset"); 20 | } 21 | 22 | /** 23 | * 更新account相关业务数据 24 | * 25 | * @memberof Account 26 | */ 27 | update = async () => { 28 | throw new Error("not implemented update"); 29 | }; 30 | 31 | constructor(obj = {}) { 32 | this.id = obj.id; 33 | this.name = obj.name; 34 | this.type = obj.type; 35 | } 36 | generateWalletID = data => { 37 | const hash = CryptoJS.SHA256(data).toString(); 38 | const salt = CryptoJS.SHA256("wallet.qingah.com").toString(); 39 | return CryptoJS.SHA3(hash + salt, { outputLength: 256 }).toString(); 40 | }; 41 | } 42 | 43 | export default Account; 44 | -------------------------------------------------------------------------------- /src/stores/bookmarks.js: -------------------------------------------------------------------------------- 1 | import { action, observable } from 'mobx' 2 | import { persist } from 'mobx-persist' 3 | 4 | export default class Bookmarks { 5 | @persist('list') @observable bookmarks = [] 6 | 7 | @action 8 | addBookmark = bookmarks => { 9 | this.bookmarks.push(bookmarks) 10 | } 11 | 12 | @action 13 | removeBookmark = bookmark => { 14 | this.bookmarks = this.bookmarks.filter(item => item.url !== bookmark.url) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/stores/browser.js: -------------------------------------------------------------------------------- 1 | import { action, observable } from 'mobx'; 2 | import { persist } from 'mobx-persist' 3 | 4 | export default class Browser { 5 | 6 | @persist('list') @observable history = [] 7 | @persist('list') @observable whitelist = [] 8 | @persist('list') @observable tabs = [] 9 | @persist @observable activeTab = null 10 | 11 | @action 12 | addToWhitelist = url => { 13 | this.whitelist.push(url) 14 | }; 15 | 16 | @action 17 | addToHistory = ({ url, name }) => { 18 | this.history.push({ url, name }) 19 | } 20 | 21 | @action 22 | createNewTab = (url, id = Date.now()) => { 23 | const tab = { url, id } 24 | this.tabs.push(tab) 25 | return tab 26 | } 27 | 28 | @action 29 | closeAllTabs = () => { 30 | this.tabs = [] 31 | } 32 | 33 | @action 34 | closeTab = (id) => { 35 | this.tabs = this.tabs.filter(item => item.id !== id) 36 | } 37 | 38 | @action 39 | setActiveTab = (id) => { 40 | this.activeTab = id 41 | } 42 | 43 | @action 44 | updateTab = (id, data) => { 45 | this.tabs = this.tabs.map(tab => { 46 | if (tab.id === id) { 47 | return { ...tab, ...data }; 48 | } 49 | return tab; 50 | }) 51 | } 52 | 53 | } 54 | 55 | -------------------------------------------------------------------------------- /src/stores/common.js: -------------------------------------------------------------------------------- 1 | import { action, observable } from 'mobx'; 2 | 3 | class Store { 4 | @observable newVersion = false; 5 | @observable availableBTC = 0; 6 | @observable totalCreditLine = 0; 7 | @observable loadingId = 0; 8 | 9 | @action 10 | setNewVersion = newVersion => { 11 | this.newVersion = newVersion; 12 | }; 13 | 14 | @action 15 | setTotalCreditLine = totalCreditLine => { 16 | this.totalCreditLine = totalCreditLine; 17 | }; 18 | 19 | @action 20 | setLoadingId = (id) => { 21 | this.loadingId = id 22 | } 23 | } 24 | 25 | export default new Store(); 26 | -------------------------------------------------------------------------------- /src/stores/modals.js: -------------------------------------------------------------------------------- 1 | import { action, observable } from 'mobx' 2 | import { persist } from 'mobx-persist' 3 | 4 | export default class Modals { 5 | 6 | @persist @observable networkModalVisible = false; 7 | @persist @observable accountsModalVisible = false; 8 | @persist @observable collectibleContractModalVisible = false; 9 | @persist @observable receiveModalVisible = false; 10 | @persist('object') @observable receiveAsset = {}; 11 | 12 | @action 13 | toggleNetworkModal = () => { 14 | this.networkModalVisible = !this.networkModalVisible 15 | }; 16 | 17 | @action 18 | toggleReceiveModal = (asset) => { 19 | this.receiveAsset = asset 20 | this.receiveModalVisible = !this.receiveModalVisible 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /src/stores/price.js: -------------------------------------------------------------------------------- 1 | import {action, observable} from 'mobx'; 2 | 3 | class Store { 4 | rate = Math.pow(10, 8); 5 | //当前使用钱包 6 | @observable BTC = 0; 7 | 8 | @action 9 | setBTC = btcPrice => { 10 | this.BTC = btcPrice; 11 | }; 12 | } 13 | 14 | export default new Store(); 15 | -------------------------------------------------------------------------------- /src/stores/privacy.js: -------------------------------------------------------------------------------- 1 | import { action, observable } from 'mobx' 2 | import { persist } from 'mobx-persist' 3 | export default class Privacy { 4 | 5 | @persist('object') @observable approvedHosts = {} 6 | @persist @observable privacyMode = true 7 | 8 | @action 9 | approveHost = hostname => { 10 | this.approvedHosts = { 11 | ...this.approvedHosts, 12 | [hostname]: true 13 | }; 14 | }; 15 | } 16 | 17 | -------------------------------------------------------------------------------- /src/stores/settings.js: -------------------------------------------------------------------------------- 1 | import { action, observable } from 'mobx'; 2 | import { persist } from 'mobx-persist' 3 | import AppConstants from '../modules/metamask/core/AppConstants'; 4 | 5 | export default class Store { 6 | 7 | @persist @observable searchEngine = AppConstants.DEFAULT_SEARCH_ENGINE; 8 | @persist @observable primaryCurrency = 'ETH'; 9 | @persist @observable lockTime = -1; // Disabled by default 10 | @persist @observable paymentChannelsEnabled = false 11 | 12 | 13 | @persist @observable initialRouteName = null 14 | 15 | @persist('object') @observable language = { 16 | name: '简体中文', 17 | locale: 'zh', 18 | }; 19 | @persist('object') @observable currency = { 20 | name: 'USD', 21 | unit: '$', 22 | }; 23 | 24 | @persist @observable passwordSet = false 25 | 26 | @observable username = ''; 27 | @observable email = ''; 28 | @observable exchangeRate = 1; 29 | 30 | @action 31 | setInitialRouteName = (initialRouteName = "Wallet") => { 32 | this.initialRouteName = initialRouteName; 33 | }; 34 | 35 | @persist('list') @observable contacts = []; 36 | 37 | @persist @observable fibosNetwork = 1; 38 | 39 | @action 40 | setFibosNetwork = network => { 41 | this.fibosNetwork = network; 42 | }; 43 | 44 | @action 45 | setContacts = contact => { 46 | this.contacts = contact; 47 | }; 48 | 49 | @action 50 | addContacts = async contact => { 51 | let temp = this.contacts; 52 | temp.push(contact); 53 | this.contacts = temp; 54 | }; 55 | 56 | @action 57 | removeContacts = async index => { 58 | let temp = this.contacts; 59 | temp.splice(index, 1); 60 | this.contacts = temp; 61 | }; 62 | 63 | @action 64 | setLanguage = language => { 65 | this.language = language; 66 | }; 67 | 68 | @action 69 | setLockTime = (value) => { 70 | this.lockTime = value 71 | } 72 | 73 | @action 74 | setPassword = () => { 75 | this.passwordSet = true 76 | } 77 | } -------------------------------------------------------------------------------- /src/stores/store.js: -------------------------------------------------------------------------------- 1 | import AsyncStorage from "@react-native-community/async-storage"; 2 | 3 | class Store { 4 | 5 | stateStorage = "stateStorage" 6 | 7 | constructor() { 8 | this._stateStorage() 9 | } 10 | 11 | /** 12 | * 从本地存储中查询对象 13 | * @returns {Promise} 14 | * @private 15 | */ 16 | async _stateStorage() { 17 | const value = await AsyncStorage.getItem(this.stateStorage); 18 | this.userbean = value ? JSON.parse(value) : {}; 19 | } 20 | } 21 | 22 | export default Store; -------------------------------------------------------------------------------- /src/stores/wallet.js: -------------------------------------------------------------------------------- 1 | import { action, observable } from 'mobx'; 2 | import _ from 'lodash' 3 | import { persist } from 'mobx-persist'; 4 | 5 | export default class Store { 6 | //当前使用钱包 7 | @observable current = null; 8 | 9 | @observable BTC = 0; 10 | 11 | @observable USDT = 0; 12 | 13 | @persist @observable dataText = ''; 14 | 15 | @action 16 | setMyBalance = (token, balance) => { 17 | switch (token) { 18 | case 'BTC': 19 | this.BTC = balance; 20 | break; 21 | case 'USDT': 22 | this.USDT = balance; 23 | break; 24 | default: 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/stores/wallet/util/address.js: -------------------------------------------------------------------------------- 1 | import { COIN_ID_ETH, COIN_ID_BTC } from "../../../config/const"; 2 | 3 | export default { 4 | decodeAdress: function(str) { 5 | if (str.startsWith("0x")) { 6 | return { 7 | address: str, 8 | type: COIN_ID_ETH, 9 | }; 10 | } 11 | const firstChar = str.charAt(0); 12 | if (firstChar === "1" || firstChar === "3" || firstChar === "2" || firstChar === "m" || firstChar === "n") { 13 | return { 14 | address: str, 15 | type: COIN_ID_BTC, 16 | }; 17 | } 18 | return { 19 | address: str, 20 | type: 0, 21 | }; 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /src/stores/wallet/util/base58.js: -------------------------------------------------------------------------------- 1 | const basex = require("./baseX"); 2 | const ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; 3 | 4 | module.exports = basex(ALPHABET); 5 | -------------------------------------------------------------------------------- /src/stores/wizard.js: -------------------------------------------------------------------------------- 1 | import { action, observable } from 'mobx'; 2 | import { persist } from 'mobx-persist' 3 | 4 | export default class Wizard { 5 | 6 | @persist @observable step = 0; 7 | 8 | @action 9 | setOnboardingWizardStep = step => { 10 | this.step = step; 11 | }; 12 | } -------------------------------------------------------------------------------- /src/styles/common.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Common styles and variables 3 | */ 4 | 5 | /** 6 | * Map of color names to HEX values 7 | */ 8 | export const colors = { 9 | fontPrimary: '#000000', 10 | fontSecondary: '#777777', 11 | fontTertiary: '#AAAAAA', 12 | fontError: '#D73A49', 13 | fontWarning: '#f66a0a', 14 | primaryFox: '#f66a0a', 15 | black: '#000000', 16 | white: '#FFFFFF', 17 | white100: '#F9FAFB', 18 | grey600: '#5B5D67', 19 | grey500: '#6a737d', 20 | grey400: '#848c96', 21 | grey300: '#9fa6ae', 22 | grey200: '#bbc0c5', 23 | grey100: '#d6d9dc', 24 | grey050: '#D8D8D8', 25 | grey000: '#f2f3f4', 26 | greytransparent: 'rgba(36, 41, 46, 0.6)', 27 | grey: '#333333', 28 | red: '#D73A49', 29 | red000: '#fcf2f3', 30 | blue: '#037dd6', 31 | blue000: '#eaf6ff', 32 | green600: '#1e7e34', 33 | green500: '#28a745', 34 | green400: '#28A745', 35 | green300: '#86e29b', 36 | green200: '#afecbd', 37 | green100: '#e6f9ea', 38 | yellow: '#FFD33D', 39 | yellow700: '#705700', 40 | yellow200: '#ffe281', 41 | yellow100: '#fffcdb', 42 | orange: '#f66a0a', 43 | orange300: '#faa66c', 44 | orange000: '#fef5ef', 45 | spinnerColor: '#037DD6', 46 | dimmed: '#00000080', 47 | transparent: 'transparent', 48 | lightOverlay: 'rgba(0,0,0,.2)', 49 | overlay: 'rgba(0,0,0,.5)', 50 | darkAlert: 'rgba(0,0,0,.75)', 51 | normalAlert: 'rgba(55,55,55,.97)', 52 | spinnerBackground: `rgba(185, 156, 171, 0.396)` 53 | }; 54 | 55 | /** 56 | * Map of reusable base styles 57 | */ 58 | export const baseStyles = { 59 | flexGrow: { 60 | flex: 1 61 | }, 62 | flexStatic: { 63 | flex: 0 64 | } 65 | }; 66 | 67 | /** 68 | * Map of reusable fonts 69 | */ 70 | export const fontStyles = { 71 | normal: { 72 | fontWeight: '400' 73 | }, 74 | light: { 75 | fontWeight: '300' 76 | }, 77 | thin: { 78 | fontWeight: '100' 79 | }, 80 | bold: { 81 | fontWeight: '600' 82 | } 83 | }; 84 | -------------------------------------------------------------------------------- /src/svgs/getSvg.js: -------------------------------------------------------------------------------- 1 | // getSvg.js 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | 5 | const svgDir = path.resolve(__dirname, './assets'); 6 | 7 | // 读取单个文件 8 | function readfile(filename) { 9 | return new Promise((resolve, reject) => { 10 | fs.readFile(path.join(svgDir, filename), 'utf8', (err, data) => { 11 | // console.log(data.replace(/<\?xml.*?\?>|<\!--.*?-->|/g, '')); 12 | if (err) { 13 | reject(err); 14 | } 15 | 16 | // remove comment 17 | 18 | const comment = ``; 19 | const commentStart = data.indexOf(comment); 20 | const commentEnd = data.indexOf(comment) + comment.length; 21 | const commentData = 22 | data.substring(0, commentStart) + data.substring(commentEnd); 23 | 24 | // remove title 25 | const titleStart = commentData.indexOf(''); 26 | const titleEnd = commentData.indexOf('') + ''.length; 27 | const titleData = 28 | commentData.substring(0, titleStart) + commentData.substring(titleEnd); 29 | 30 | // remove desc 31 | const descStart = titleData.indexOf(''); 32 | const descEnd = titleData.indexOf('') + ''.length; 33 | const descData = 34 | titleData.substring(0, descStart) + titleData.substring(descEnd); 35 | resolve({ 36 | [filename.slice(0, filename.lastIndexOf('.'))]: descData, 37 | }); 38 | }); 39 | }); 40 | } 41 | 42 | // 读取SVG文件夹下所有svg 43 | function readSvgs() { 44 | return new Promise((resolve, reject) => { 45 | // Logger.info(`svgDir: ${svgDir}`); 46 | fs.readdir(svgDir, (err, files) => { 47 | if (err) { 48 | reject(err); 49 | } 50 | 51 | Promise.all(files.map(filename => readfile(filename))) 52 | .then(data => resolve(data)) 53 | .catch(err1 => reject(err1)); 54 | }); 55 | }); 56 | } 57 | 58 | // 生成js文件 59 | readSvgs() 60 | .then(data => { 61 | const svgFile = `export default ${JSON.stringify( 62 | Object.assign.apply(this, data), 63 | )}`; 64 | fs.writeFile(path.resolve(__dirname, './svgs.js'), svgFile, err => { 65 | if (err) { 66 | throw new Error(err); 67 | } 68 | }); 69 | }) 70 | .catch(err => { 71 | throw new Error(err) 72 | }) 73 | -------------------------------------------------------------------------------- /src/utils/ENSUtils.js: -------------------------------------------------------------------------------- 1 | import networkMap from 'ethjs-ens/lib/network-map.json'; 2 | import ENS from 'ethjs-ens'; 3 | import Engine from '../modules/metamask/core/Engine'; 4 | 5 | /** 6 | * Utility class with the single responsibility 7 | * of caching ENS names 8 | */ 9 | class ENSCache { 10 | static cache = {}; 11 | } 12 | 13 | export async function doENSReverseLookup(address, network) { 14 | const cache = ENSCache.cache[address]; 15 | if (cache) { 16 | return Promise.resolve(cache); 17 | } 18 | 19 | const { provider } = Engine.context.NetworkController; 20 | 21 | const networkHasEnsSupport = Boolean(networkMap[network]); 22 | 23 | if (networkHasEnsSupport) { 24 | this.ens = new ENS({ provider, network }); 25 | try { 26 | const name = await this.ens.reverse(address); 27 | const resolvedAddress = await this.ens.lookup(name); 28 | if (address.toLowerCase() === resolvedAddress.toLowerCase()) { 29 | ENSCache.cache[address] = name; 30 | return name; 31 | } 32 | // eslint-disable-next-line no-empty 33 | } catch (e) { } 34 | } 35 | } 36 | 37 | export async function doENSLookup(ensName, network) { 38 | const { provider } = Engine.context.NetworkController; 39 | 40 | const networkHasEnsSupport = Boolean(networkMap[network]); 41 | 42 | if (networkHasEnsSupport) { 43 | this.ens = new ENS({ provider, network }); 44 | try { 45 | const resolvedAddress = await this.ens.lookup(ensName); 46 | return resolvedAddress; 47 | // eslint-disable-next-line no-empty 48 | } catch (e) { } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/utils/GlobalNavigation.js: -------------------------------------------------------------------------------- 1 | import {NavigationActions, StackActions} from 'react-navigation'; 2 | import {DrawerActions} from 'react-navigation-drawer'; 3 | 4 | let _navigator; 5 | // add other navigation functions that you need and export them 6 | 7 | const GlobalNavigation = { 8 | navigate(routeName, params) { 9 | if (_navigator) { 10 | _navigator._navigation.navigate(routeName, params); 11 | } 12 | }, 13 | reset(routeName, params) { 14 | if (_navigator) { 15 | const resetAction = StackActions.reset({ 16 | index: 0, 17 | actions: [NavigationActions.navigate({routeName, params})], 18 | }); 19 | _navigator._navigation.dispatch(resetAction); 20 | } 21 | }, 22 | setTopLevelNavigator(navigatorRef) { 23 | _navigator = navigatorRef; 24 | }, 25 | dispatch(option) { 26 | if (_navigator) { 27 | _navigator.dispatch(option); 28 | } 29 | }, 30 | goBack(key) { 31 | if (_navigator) { 32 | const {routes} = _navigator.state.nav; 33 | const currentPageKey = routes[routes.length - 1].key; 34 | _navigator._navigation.goBack(key || currentPageKey); 35 | // _navigator.dispatch(NavigationActions.back()) 36 | } 37 | }, 38 | 39 | toggleDrawer() { 40 | if (_navigator) { 41 | _navigator.dispatch(DrawerActions.toggleDrawer()); 42 | } 43 | }, 44 | }; 45 | 46 | export default GlobalNavigation; 47 | -------------------------------------------------------------------------------- /src/utils/Storage.js: -------------------------------------------------------------------------------- 1 | import Storage from "react-native-storage"; 2 | import AsyncStorage from '@react-native-community/async-storage'; 3 | 4 | const storage = new Storage({ 5 | // 最大容量,默认值1000条数据循环存储 6 | size: 1000, 7 | 8 | // 存储引擎:对于rn使用asyncstorage,对于web使用window.localstorage 9 | // 如果不指定则数据只会保存在内存中,重启后即丢失 10 | storageBackend: AsyncStorage, 11 | 12 | // 数据过期时间,默认一整天(1000 * 3600 * 24 毫秒),设为null则永不过期 13 | defaultExpires: null, 14 | 15 | // 读写时在内存中缓存数据。默认启用。 16 | enableCache: true, 17 | }); 18 | 19 | // 缓存key 20 | // !!!!注意,key中不要用_下划线字符,否则在key-id的存储形式下有问题 21 | const STORAGE_KEY = { 22 | CONTACT_LIST: "contactList", // 联系人列表 23 | APP_INFO: "appinfo", // app信息 24 | }; 25 | 26 | // api 使用参见https://github.com/sunnylqm/react-native-storage/blob/master/README-CHN.md 27 | // 28 | export default storage; 29 | export { STORAGE_KEY }; 30 | -------------------------------------------------------------------------------- /src/utils/Timer.js: -------------------------------------------------------------------------------- 1 | function sleep(ms) { 2 | return new Promise(resolve => setTimeout(resolve, ms)); 3 | } 4 | 5 | export { sleep }; 6 | -------------------------------------------------------------------------------- /src/utils/assets.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Utility function to return corresponding eth-contract-metadata logo 3 | * 4 | * @param {string} logo - Logo path from eth-contract-metadata 5 | */ 6 | export default function getAssetLogoPath(logo) { 7 | if (!logo) return; 8 | let uri = logo 9 | if (!/^http(s)?/.test(logo)) { 10 | uri = `https://raw.githubusercontent.com/metamask/eth-contract-metadata/v1.16.0/images/${logo}`; 11 | } 12 | return uri; 13 | } 14 | -------------------------------------------------------------------------------- /src/utils/bip39Util.js: -------------------------------------------------------------------------------- 1 | import { entropyToMnemonic } from 'bip39'; 2 | import { randomBytes } from 'react-native-randombytes'; 3 | 4 | const STRENGTH_MAP = { 5 | 12: 16 * 8, 6 | 15: 20 * 8, 7 | 18: 24 * 8, 8 | 21: 28 * 8, 9 | 24: 32 * 8, 10 | }; 11 | 12 | /** 13 | * Generate random bytes 14 | * 15 | * @param {Number} length 16 | * @returns {Buffer} Random bytes 17 | */ 18 | const randomAsU8a = (length = 32) => 19 | new Promise((resolve, reject) => { 20 | randomBytes(length, (err, bytes) => { 21 | if (err) return reject(err); 22 | resolve(bytes); 23 | }); 24 | }); 25 | 26 | /** 27 | * Use bip39 to generate mnemonic words 28 | * 29 | * @param {Number} words length 30 | * @returns {String} Mnemonic words 31 | */ 32 | const mnemonicGenerate = async (words = 12) => { 33 | const strength = STRENGTH_MAP[words]; 34 | const entropy = await randomAsU8a(strength / 8); 35 | return entropyToMnemonic(entropy); 36 | }; 37 | 38 | export { mnemonicGenerate, randomAsU8a }; 39 | -------------------------------------------------------------------------------- /src/utils/browser.js: -------------------------------------------------------------------------------- 1 | import URL from 'url-parse'; 2 | 3 | /** 4 | * Returns a sanitized url, which could be a search engine url if 5 | * a keyword is detected instead of a url 6 | * 7 | * @param {string} input - String corresponding to url input 8 | * @param {string} searchEngine - Protocol string to append to URLs that have none 9 | * @param {string} defaultProtocol - Protocol string to append to URLs that have none 10 | * @returns {string} - String corresponding to sanitized input depending if it's a search or url 11 | */ 12 | export default function onUrlSubmit(input, searchEngine = 'Google', defaultProtocol = 'https://') { 13 | //Check if it's a url or a keyword 14 | const res = input.match(/^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w.-]+)+[\w\-._~:/?#[\]@!&',;=.+]+$/g); 15 | if (res === null) { 16 | // Add exception for localhost 17 | if (!input.startsWith('http://localhost') && !input.startsWith('localhost')) { 18 | // In case of keywords we default to google search 19 | let searchUrl = 'https://www.google.com/search?q=' + escape(input); 20 | if (searchEngine === 'DuckDuckGo') { 21 | searchUrl = 'https://duckduckgo.com/?q=' + escape(input); 22 | } 23 | return searchUrl; 24 | } 25 | } 26 | const hasProtocol = input.match(/^[a-z]*:\/\//); 27 | const sanitizedURL = hasProtocol ? input : `${defaultProtocol}${input}`; 28 | return sanitizedURL; 29 | } 30 | 31 | /** 32 | * Return host from url string 33 | * 34 | * @param {string} url - String containing url 35 | * @param {string} defaultProtocol - Protocol string to append to URLs that have none 36 | * @returns {string} - String corresponding to host 37 | */ 38 | export function getHost(url, defaultProtocol = 'https://') { 39 | const hasProtocol = url && url.match(/^[a-z]*:\/\//); 40 | const urlObj = new URL(hasProtocol ? url : `${defaultProtocol}${url}`); 41 | const { hostname } = urlObj; 42 | return hostname; 43 | } 44 | 45 | /** 46 | * Return an URL object from url string 47 | * 48 | * @param {string} url - String containing url 49 | * @returns {object} - URL object 50 | */ 51 | export function getUrlObj(url) { 52 | const urlObj = new URL(url); 53 | return urlObj; 54 | } 55 | -------------------------------------------------------------------------------- /src/utils/bytes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Converts an array of bytes into a hex string 3 | * 4 | * @param value - Array of bytes 5 | * 6 | * @returns - Hex string 7 | */ 8 | export default function byteArrayToHex(value) { 9 | const HexCharacters = '0123456789abcdef'; 10 | const result = []; 11 | for (let i = 0; i < value.length; i++) { 12 | const v = value[i]; 13 | result.push(HexCharacters[(v & 0xf0) >> 4] + HexCharacters[v & 0x0f]); 14 | } 15 | return '0x' + result.join(''); 16 | } 17 | -------------------------------------------------------------------------------- /src/utils/collectibles-transfer.json: -------------------------------------------------------------------------------- 1 | { 2 | "0x5d00d312e171be5342067c09bae883f9bcb2003b": { 3 | "name": "ethermon", 4 | "tradable": true, 5 | "method": "transferFrom" 6 | }, 7 | "0x06012c8cf97bead5deae237070f9587f8e7a266d": { 8 | "name": "cryptokitties", 9 | "tradable": true, 10 | "method": "transfer" 11 | }, 12 | "0x8c9b261faef3b3c2e64ab5e58e04615f8c788099": { 13 | "name": "LucidSight-MLB-NFT", 14 | "tradable": true, 15 | "method": "transferFrom" 16 | }, 17 | "0x7b00ae36c7485b678fe945c2dd9349eb5baf7b6b": { 18 | "name": "Spheroid SPACE", 19 | "tradable": false 20 | }, 21 | "0xbd13e53255ef917da7557db1b7d2d5c38a2efe24": { 22 | "name": "DozerDoll", 23 | "tradable": true, 24 | "method": "transferFrom" 25 | }, 26 | "0x8bc67d00253fd60b1afcce88b78820413139f4c6": { 27 | "name": "CryptoFlowers", 28 | "tradable": true, 29 | "method": "transferFrom" 30 | }, 31 | "0x1d963688fe2209a98db35c67a041524822cf04ff": { 32 | "name": "MARBLE-NFT", 33 | "tradable": false 34 | }, 35 | "0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab": { 36 | "name": "Gods Unchained", 37 | "tradable": false 38 | }, 39 | "0xdceaf1652a131f32a821468dc03a92df0edd86ea": { 40 | "name": "MyCryptoHeroes:Extension", 41 | "tradable": true, 42 | "method": "transferFrom" 43 | }, 44 | "0x273f7f8e6489682df756151f5525576e322d51a3": { 45 | "name": "MyCryptoHeroes:Hero", 46 | "tradable": true, 47 | "method": "transferFrom" 48 | }, 49 | "0x2aea4add166ebf38b63d09a75de1a7b94aa24163": { 50 | "name": "KudosToken", 51 | "tradable": true, 52 | "method": "transferFrom" 53 | } 54 | } -------------------------------------------------------------------------------- /src/utils/common.js: -------------------------------------------------------------------------------- 1 | import { InteractionManager } from 'react-native' 2 | import _ from 'lodash' 3 | 4 | export const goBrowser = _.throttle((navigation, browserUrl) => { 5 | navigation.navigate('Browser') 6 | InteractionManager.runAfterInteractions(() => { 7 | setTimeout(() => { 8 | navigation.navigate('DApp', { 9 | newTabUrl: browserUrl, 10 | }) 11 | }, 300) 12 | }) 13 | }, 8000) 14 | -------------------------------------------------------------------------------- /src/utils/crypto.js: -------------------------------------------------------------------------------- 1 | import _ from "lodash"; 2 | const CryptoJS = require("crypto-js"); 3 | 4 | export default { 5 | aesEncrypt(data, secretKey) { 6 | return CryptoJS.AES.encrypt(data, CryptoJS.enc.Utf8.parse(secretKey), { 7 | mode: CryptoJS.mode.ECB, 8 | padding: CryptoJS.pad.Pkcs7, 9 | }).toString(); 10 | }, 11 | aesDecrypt(data, secretKey) { 12 | return CryptoJS.AES.decrypt(data, CryptoJS.enc.Utf8.parse(secretKey), { 13 | mode: CryptoJS.mode.ECB, 14 | padding: CryptoJS.pad.Pkcs7, 15 | }).toString(CryptoJS.enc.Utf8); 16 | }, 17 | hash160(data, { asByte = false } = {}) { 18 | if (asByte && _.isString(data)) { 19 | data = CryptoJS.enc.Hex.parse(data); 20 | } 21 | return CryptoJS.RIPEMD160(this.sha256(data)); 22 | }, 23 | sha256(data, { asByte = false } = {}) { 24 | if (asByte && _.isString(data)) { 25 | data = CryptoJS.enc.Hex.parse(data); 26 | } 27 | return CryptoJS.SHA256(data); 28 | }, 29 | sha3(data, length = 256) { 30 | return CryptoJS.SHA3(data, { outputLength: length }); 31 | }, 32 | toWordsArray(hex) { 33 | return CryptoJS.enc.Hex.parse(hex); 34 | }, 35 | }; 36 | -------------------------------------------------------------------------------- /src/utils/currency-symbols.json: -------------------------------------------------------------------------------- 1 | { 2 | "eur": "\u20AC", 3 | "hkd": "\u0024", 4 | "jpy": "\u00A5", 5 | "php": "\u20B1", 6 | "rub": "\u20BD", 7 | "sgd": "\u0024", 8 | "usd": "\u0024" 9 | } 10 | -------------------------------------------------------------------------------- /src/utils/date.js: -------------------------------------------------------------------------------- 1 | import { strings } from "../locales/i18n"; 2 | 3 | export function toLocaleDateTime(timestamp) { 4 | const dateObj = new Date(timestamp); 5 | const date = dateObj.toLocaleDateString(); 6 | const time = dateObj.toLocaleTimeString(); 7 | return `${date} ${time}`; 8 | } 9 | 10 | export function toDateFormat(timestamp) { 11 | const dateObj = new Date(timestamp); 12 | const month = strings(`date.months.${dateObj.getMonth()}`); 13 | const day = dateObj.getDate(); 14 | let meridiem = 'am'; 15 | let hour = dateObj.getHours(); 16 | if (hour > 12) { 17 | meridiem = 'pm'; 18 | hour -= 12; 19 | } 20 | let min = dateObj.getMinutes(); 21 | if (`${min}`.length === 1) min = `0${min}`; 22 | return `${month} ${day} ${strings('date.connector')} ${hour}:${min}${meridiem}`; 23 | } 24 | 25 | export function toLocaleDate(timestamp) { 26 | return new Date(timestamp).toLocaleDateString(); 27 | } 28 | 29 | export function toLocaleTime(timestamp) { 30 | return new Date(timestamp).toLocaleTimeString(); 31 | } 32 | -------------------------------------------------------------------------------- /src/utils/devices.js: -------------------------------------------------------------------------------- 1 | import { Dimensions, Platform } from 'react-native'; 2 | 3 | export default class Device { 4 | static getDeviceWidth() { 5 | return Dimensions.get('window').width; 6 | } 7 | 8 | static getDeviceHeight() { 9 | return Dimensions.get('window').height; 10 | } 11 | 12 | static isIos() { 13 | return Platform.OS === 'ios'; 14 | } 15 | 16 | static isAndroid() { 17 | return Platform.OS === 'android'; 18 | } 19 | 20 | static isIpad() { 21 | return this.getDeviceWidth() >= 1000 || this.getDeviceHeight() >= 1000; 22 | } 23 | 24 | static isLandscape() { 25 | return this.getDeviceWidth() > this.getDeviceHeight(); 26 | } 27 | 28 | static isIphone5() { 29 | return this.getDeviceWidth() === 320; 30 | } 31 | 32 | static isIphone5S() { 33 | return this.getDeviceWidth() === 320; 34 | } 35 | 36 | static isIphone6() { 37 | return this.getDeviceWidth() === 375; 38 | } 39 | 40 | static isIphone6Plus() { 41 | return this.getDeviceWidth() === 414; 42 | } 43 | 44 | static isIphone6SPlus() { 45 | return this.getDeviceWidth() === 414; 46 | } 47 | 48 | static isIphoneX() { 49 | return this.getDeviceWidth() >= 375 && this.getDeviceHeight() >= 812; 50 | } 51 | 52 | static isIpadPortrait9_7() { 53 | return this.getDeviceHeight() === 1024 && this.getDeviceWidth() === 736; 54 | } 55 | static isIpadLandscape9_7() { 56 | return this.getDeviceHeight() === 736 && this.getDeviceWidth() === 1024; 57 | } 58 | 59 | static isIpadPortrait10_5() { 60 | return this.getDeviceHeight() === 1112 && this.getDeviceWidth() === 834; 61 | } 62 | static isIpadLandscape10_5() { 63 | return this.getDeviceWidth() === 1112 && this.getDeviceHeight() === 834; 64 | } 65 | 66 | static isIpadPortrait12_9() { 67 | return this.getDeviceWidth() === 1024 && this.getDeviceHeight() === 1366; 68 | } 69 | 70 | static isIpadLandscape12_9() { 71 | return this.getDeviceWidth() === 1366 && this.getDeviceHeight() === 1024; 72 | } 73 | 74 | static isSmallDevice() { 75 | return this.getDeviceHeight() < 600; 76 | } 77 | 78 | static isMediumDevice() { 79 | return this.getDeviceHeight() < 736; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/utils/etherscan.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Gets the etherscan link for an address in a specific network 3 | * 4 | * @param {network} string - name of the network 5 | * @param {address} string - ethereum address to be used on the link 6 | * @returns - string 7 | */ 8 | export function getEtherscanAddressUrl(network, address) { 9 | return `${getEtherscanBaseUrl(network)}/address/${address}`; 10 | } 11 | 12 | /** 13 | * Gets the etherscan link for a transaction in a specific network 14 | * 15 | * @param {network} string - name of the network 16 | * @param {tx_hash} string - hash of the transaction to be used on the link 17 | * @returns - string 18 | */ 19 | export function getEtherscanTransactionUrl(network, tx_hash) { 20 | return `${getEtherscanBaseUrl(network)}/tx/${tx_hash}`; 21 | } 22 | 23 | /** 24 | * Gets the base etherscan link for a transaction in a specific network 25 | * 26 | * @param {network} string - name of the network 27 | * @returns - string 28 | */ 29 | export function getEtherscanBaseUrl(network) { 30 | const subdomain = network.toLowerCase() === 'mainnet' ? '' : `${network.toLowerCase()}.`; 31 | return `https://${subdomain}etherscan.io`; 32 | } 33 | -------------------------------------------------------------------------------- /src/utils/keychain.js: -------------------------------------------------------------------------------- 1 | import { Toast, Modal } from "@ant-design/react-native"; 2 | import AsyncStorage from "@react-native-community/async-storage"; 3 | import SecureKeychain from "../modules/metamask/core/SecureKeychain"; 4 | 5 | const setKeyChain = async (username, password) => { 6 | await SecureKeychain.setGenericPassword(username, password, { 7 | accessControl: SecureKeychain.ACCESS_CONTROL.WHEN_UNLOCKED_THIS_DEVICE_ONLY 8 | }); 9 | try { 10 | const credentials = await SecureKeychain.getGenericPassword(); 11 | if (credentials) { 12 | console.log('Credentials successfully loaded for user '); 13 | return true; 14 | } else { 15 | console.log('No credentials stored'); 16 | } 17 | } catch (error) { 18 | console.log("Keychain couldn't be accessed!", error); 19 | Toast.fail('Create credentials failed'); 20 | return false; 21 | } 22 | } 23 | 24 | export const isBiometry = async () => { 25 | const biometryChoice = await AsyncStorage.getItem('@QHWallet:biometryChoice'); 26 | const biometryType = await SecureKeychain.getSupportedBiometryType() 27 | if (biometryChoice !== '' && biometryChoice === biometryType) { 28 | return true 29 | } 30 | return false 31 | } 32 | 33 | export const authSubmit = async (callback) => { 34 | try { 35 | const biometry = await isBiometry() 36 | const submit = () => { 37 | 38 | } 39 | if (biometry) { 40 | try { 41 | const { password } = await SecureKeychain.getGenericPassword() 42 | callback(null, password) 43 | } catch (e) { 44 | callback('cancel') 45 | } 46 | return 47 | } else { 48 | Modal.prompt( 49 | 'Please input your password', 50 | 'Save it carefully!', 51 | async (pwd) => { 52 | try { 53 | const { password } = await SecureKeychain.getGenericPassword() 54 | if (password === pwd) { 55 | callback(null, password) 56 | } else { 57 | callback('password fail') 58 | } 59 | } catch (e) { 60 | console.warn(e) 61 | callback('cancel') 62 | } 63 | }, 64 | 'secure-text', 65 | '' 66 | ) 67 | } 68 | } catch (error) { 69 | callback(false) 70 | console.warn(error); 71 | } 72 | } 73 | 74 | export default setKeyChain; -------------------------------------------------------------------------------- /src/utils/middlewares.js: -------------------------------------------------------------------------------- 1 | 2 | const REJECTED_TRANSACTION_ERROR = 'User rejected the transaction'; 3 | 4 | /** 5 | * Returns a middleware that appends the DApp origin to request 6 | * @param {{ origin: string }} opts - The middleware options 7 | * @returns {Function} 8 | */ 9 | export function createOriginMiddleware(opts) { 10 | return function originMiddleware(/** @type {any} */ req, /** @type {any} */ _, /** @type {Function} */ next) { 11 | req.origin = opts.origin; 12 | 13 | // web3-provider-engine compatibility 14 | // TODO:provider delete this after web3-provider-engine deprecation 15 | if (!req.params) { 16 | req.params = []; 17 | } 18 | 19 | next(); 20 | }; 21 | } 22 | 23 | /** 24 | * Returns a middleware that logs RPC activity 25 | * @param {{ origin: string }} opts - The middleware options 26 | * @returns {Function} 27 | */ 28 | export function createLoggerMiddleware(opts) { 29 | return function loggerMiddleware(/** @type {any} */ req, /** @type {any} */ res, /** @type {Function} */ next) { 30 | next((/** @type {Function} */ cb) => { 31 | if (res.error) { 32 | const { error, ...resWithoutError } = res; 33 | if (error && error.message !== REJECTED_TRANSACTION_ERROR) { 34 | console.error(error, { message: 'Error in RPC response', res: resWithoutError }); 35 | } 36 | } 37 | if (req.isMetamaskInternal) { 38 | return; 39 | } 40 | console.log(`RPC (${opts.origin}):`, req, '->', res); 41 | cb(); 42 | }); 43 | }; 44 | } 45 | -------------------------------------------------------------------------------- /src/utils/payment-link-generator.js: -------------------------------------------------------------------------------- 1 | import { build } from 'eth-url-parser'; 2 | import AppConstants from '../modules/metamask/core/AppConstants'; 3 | 4 | /** 5 | * Generate a universal link / app link based on EIP-681 / EIP-831 URLs 6 | * 7 | * @param {string} address - Ethereum address 8 | * 9 | * @returns Payment request universal link / app link 10 | */ 11 | export function generateUniversalLinkAddress(address) { 12 | return `https://${AppConstants.MM_UNIVERSAL_LINK_HOST}/send/${address}`; 13 | } 14 | 15 | /** 16 | * Generate a universal link / app link based on EIP-681 / EIP-831 URLs 17 | * 18 | * @param {string} ethereum_link - EIP-681 / EIP-831 compatible url 19 | * 20 | * @returns Payment request universal link / app link 21 | */ 22 | export function generateUniversalLinkRequest(ethereum_link) { 23 | const universal_link_format = `https://${AppConstants.MM_UNIVERSAL_LINK_HOST}/send/`; 24 | return ethereum_link.replace('ethereum:', universal_link_format); 25 | } 26 | 27 | /** 28 | * Generate ETH payment request link 29 | * 30 | * @param {string} receiverAddress - Receiver address 31 | * @param {string} value - Value to request, in float number 32 | * @param {string} chainId - Chain id 33 | * 34 | * @returns Payment request link, it could throw if errors are found 35 | */ 36 | export function generateETHLink(receiverAddress, value, chainId) { 37 | const data = { 38 | chain_id: chainId, 39 | function_name: undefined, 40 | parameters: { 41 | value: value + 'e18' 42 | }, 43 | scheme: 'ethereum', 44 | target_address: receiverAddress 45 | }; 46 | return build(data); 47 | } 48 | 49 | /** 50 | * Generate ERC asset payment request link 51 | * 52 | * @param {string} receiverAddress - Receiver address 53 | * @param {string} assetAddress - ERC20 asset address 54 | * @param {string} value - Value to request, in float number 55 | * @param {string} chainId - Chain id 56 | * 57 | * @returns Payment request link, it could throw if errors are found 58 | */ 59 | export function generateERC20Link(receiverAddress, assetAddress, value, chainId) { 60 | const data = { 61 | chain_id: chainId, 62 | function_name: 'transfer', 63 | parameters: { 64 | address: receiverAddress, 65 | uint256: value 66 | }, 67 | scheme: 'ethereum', 68 | target_address: assetAddress 69 | }; 70 | return build(data); 71 | } 72 | -------------------------------------------------------------------------------- /src/utils/streams.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-commonjs */ 2 | const Through = require('through2'); 3 | const ObjectMultiplex = require('obj-multiplex'); 4 | const pump = require('pump'); 5 | 6 | /** 7 | * Returns a stream transform that parses JSON strings passing through 8 | * @return {stream.Transform} 9 | */ 10 | function jsonParseStream() { 11 | return Through.obj(function (serialized, _, cb) { 12 | this.push(JSON.parse(serialized)); 13 | cb(); 14 | }); 15 | } 16 | 17 | /** 18 | * Returns a stream transform that calls {@code JSON.stringify} 19 | * on objects passing through 20 | * @return {stream.Transform} the stream transform 21 | */ 22 | function jsonStringifyStream() { 23 | return Through.obj(function (obj, _, cb) { 24 | this.push(JSON.stringify(obj)); 25 | cb(); 26 | }); 27 | } 28 | 29 | /** 30 | * Sets up stream multiplexing for the given stream 31 | * @param {any} connectionStream - the stream to mux 32 | * @return {stream.Stream} the multiplexed stream 33 | */ 34 | function setupMultiplex(connectionStream) { 35 | const mux = new ObjectMultiplex(); 36 | pump(connectionStream, mux, connectionStream, err => { 37 | if (err) { 38 | console.warn("stream:", err); 39 | } 40 | }); 41 | return mux; 42 | } 43 | 44 | export { jsonParseStream, jsonStringifyStream, setupMultiplex }; 45 | -------------------------------------------------------------------------------- /src/utils/transaction-reducer-helpers.js: -------------------------------------------------------------------------------- 1 | function getDefinedProperties(object) { 2 | return Object.entries(object).reduce((obj, [key, val]) => (val !== undefined ? { ...obj, [key]: val } : obj), {}) 3 | } 4 | 5 | /** 6 | * Get the standard set of properties of a transaction from a larger set of tx data 7 | * 8 | * @param {object} txMeta - An object containing data about a transaction 9 | * @returns {object} - An object containing the standard properties of a transaction 10 | */ 11 | export function getTxData(txMeta = {}) { 12 | const { data, from, gas, gasPrice, to, value } = txMeta // eslint-disable-line no-unused-vars 13 | const txData = { data, from, gas, gasPrice, to, value } 14 | return getDefinedProperties(txData) 15 | } 16 | 17 | /** 18 | * Get meta data of a transaction, without the standard properties, from a set of tx data 19 | * 20 | * @param {object} txMeta - An object containing data about a transaction 21 | * @returns {object} - An object containing the standard properties of a transaction 22 | */ 23 | export function getTxMeta(txMeta = {}) { 24 | const { data, from, gas, gasPrice, to, value, ...rest } = txMeta // eslint-disable-line no-unused-vars 25 | return getDefinedProperties(rest) 26 | } 27 | --------------------------------------------------------------------------------