├── .babelrc ├── .bundle └── config ├── .env.demo ├── .env.dev ├── .env.release ├── .eslintrc.js ├── .github ├── FUNDING.yml └── workflows │ └── codeql-analysis.yml ├── .gitignore ├── .node-version ├── .prettierrc.js ├── .travis.yml ├── .watchmanconfig ├── CONTRIBUTING.md ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── README.md ├── android ├── app │ ├── _BUCK │ ├── build.gradle │ ├── debug.keystore │ ├── proguard-rules.pro │ └── src │ │ ├── debug │ │ ├── AndroidManifest.xml │ │ └── java │ │ │ └── app │ │ │ └── ironbelly │ │ │ └── ReactNativeFlipper.java │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── assets │ │ │ ├── fonts │ │ │ │ ├── Poppins-ExtraBold.ttf │ │ │ │ ├── Poppins-ExtraBoldItalic.ttf │ │ │ │ ├── Poppins-ExtraLight.ttf │ │ │ │ ├── Poppins-ExtraLightItalic.ttf │ │ │ │ ├── Poppins-Italic.ttf │ │ │ │ ├── Poppins-Light.ttf │ │ │ │ ├── Poppins-LightItalic.ttf │ │ │ │ ├── Poppins-Medium.ttf │ │ │ │ ├── Poppins-MediumItalic.ttf │ │ │ │ ├── Poppins-Regular.ttf │ │ │ │ ├── Poppins-SemiBold.ttf │ │ │ │ ├── Poppins-SemiBoldItalic.ttf │ │ │ │ ├── Poppins-Thin.ttf │ │ │ │ └── Poppins-ThinItalic.ttf │ │ │ └── tor │ │ │ │ ├── bridges.txt │ │ │ │ ├── geoip │ │ │ │ └── geoip6 │ │ ├── java │ │ │ └── app │ │ │ │ └── ironbelly │ │ │ │ ├── CustomGrinBridge.java │ │ │ │ ├── GrinBridge.java │ │ │ │ ├── MainActivity.java │ │ │ │ ├── MainApplication.java │ │ │ │ ├── SplashActivity.java │ │ │ │ └── tor │ │ │ │ ├── TorConfig.kt │ │ │ │ ├── TorProxyManager.kt │ │ │ │ ├── TorProxyState.kt │ │ │ │ └── TorResourceInstaller.kt │ │ ├── jniLibs │ │ │ └── Android.mk │ │ └── res │ │ │ ├── drawable │ │ │ ├── background_splash.xml │ │ │ └── rn_edit_text_material.xml │ │ │ ├── layout │ │ │ └── launch_screen.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── values-night │ │ │ └── colors.xml │ │ │ ├── values │ │ │ ├── colors.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ │ └── xml │ │ │ ├── filepaths.xml │ │ │ └── network_security_config.xml │ │ └── release │ │ └── java │ │ └── app │ │ └── ironbelly │ │ └── ReactNativeFlipper.java ├── build.gradle ├── get_apk_from_aab.sh ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle ├── app.json ├── docs ├── balance.png ├── balance.uml ├── navigation.png ├── navigation.uml ├── refresh.png ├── refresh.uml └── release_test.md ├── e2e ├── config.json ├── init.js ├── utils.js └── walletInit.spec.js ├── fastlane ├── Appfile ├── Deliverfile ├── Fastfile ├── Pluginfile ├── README.md ├── Snapfile └── SnapshotHelper.swift ├── index.js ├── ios ├── .xcode.env ├── .xcode.env.local ├── Cartfile ├── Cartfile.resolved ├── Ironbelly.xcodeproj │ ├── project.pbxproj │ └── xcshareddata │ │ └── xcschemes │ │ ├── Ironbelly.xcscheme │ │ └── Snapshots.xcscheme ├── Ironbelly.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings ├── Ironbelly │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── Icon.png │ │ │ ├── icon_20pt.png │ │ │ ├── icon_20pt@2x-1.png │ │ │ ├── icon_20pt@2x.png │ │ │ ├── icon_20pt@3x.png │ │ │ ├── icon_29pt.png │ │ │ ├── icon_29pt@2x-1.png │ │ │ ├── icon_29pt@2x.png │ │ │ ├── icon_29pt@3x.png │ │ │ ├── icon_40pt.png │ │ │ ├── icon_40pt@2x-1.png │ │ │ ├── icon_40pt@2x.png │ │ │ ├── icon_40pt@3x.png │ │ │ ├── icon_60pt@2x.png │ │ │ ├── icon_60pt@3x.png │ │ │ ├── icon_76pt.png │ │ │ ├── icon_76pt@2x.png │ │ │ └── icon_83.5@2x.png │ │ ├── Contents.json │ │ └── LaunchLogo.imageset │ │ │ ├── Contents.json │ │ │ ├── LaunchLogo.png │ │ │ ├── LaunchLogo@2x.png │ │ │ └── LaunchLogo@3x.png │ ├── Base.lproj │ │ └── LaunchScreen.storyboard │ ├── GrinBridge.m │ ├── GrinBridge.swift │ ├── Images.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── Contents.json │ ├── Info.plist │ ├── LaunchScreen.storyboard │ ├── Tor │ │ ├── Helpers │ │ │ ├── Ipv6Tester.swift │ │ │ ├── NetworkTools.h │ │ │ └── NetworkTools.m │ │ ├── OnionConnector.swift │ │ ├── OnionManager.swift │ │ └── OnionSettings.swift │ ├── Utils.swift │ ├── Wallet-Bridging-Header.h │ └── assets │ │ └── src │ │ └── assets │ │ └── images │ │ ├── ReceiveTX.png │ │ ├── ReceiveTX@2x.png │ │ ├── ReceiveTX@3x.png │ │ ├── SendTX.png │ │ ├── SendTX@2x.png │ │ ├── SendTX@3x.png │ │ ├── Settings.png │ │ ├── Settings@2x.png │ │ ├── Settings@3x.png │ │ ├── Share.png │ │ ├── Share@2x.png │ │ ├── Share@3x.png │ │ ├── x.png │ │ ├── x@2x.png │ │ └── x@3x.png ├── IronbellyTests │ └── IronbellyTests.m ├── Podfile ├── Podfile.lock ├── UITests │ ├── Info.plist │ └── UITests.swift └── Wallet.xcframework │ └── Info.plist ├── jest.config.js ├── metro.config.js ├── package.json ├── patches ├── react-native-background-timer+2.4.1.patch ├── react-native-config+1.5.1.patch ├── react-native-fs+2.20.0.patch ├── react-native-keep-awake+4.0.0.patch ├── react-native-linear-gradient+2.8.3.patch ├── react-native-navigation-bar-color+2.0.2.patch ├── react-native-splash-screen+3.3.0.patch └── react-native-vector-icons+10.0.3.patch ├── react-native.config.js ├── rn-polyfill-depricated-proptypes.js ├── rust ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── build.rs ├── scripts │ ├── build.sh │ ├── init.sh │ └── variables.sh └── src │ ├── android.rs │ ├── errors.rs │ ├── ios.rs │ └── lib.rs ├── scripts ├── additional-licenses.js ├── applesimutils.sh ├── licenses.js ├── npm.sh └── test.sh ├── sign-with-local.sh ├── src ├── App.tsx ├── assets │ ├── fonts │ │ ├── Poppins-ExtraBold.ttf │ │ ├── Poppins-ExtraBoldItalic.ttf │ │ ├── Poppins-ExtraLight.ttf │ │ ├── Poppins-ExtraLightItalic.ttf │ │ ├── Poppins-Italic.ttf │ │ ├── Poppins-Light.ttf │ │ ├── Poppins-LightItalic.ttf │ │ ├── Poppins-Medium.ttf │ │ ├── Poppins-MediumItalic.ttf │ │ ├── Poppins-Regular.ttf │ │ ├── Poppins-SemiBold.ttf │ │ ├── Poppins-SemiBoldItalic.ttf │ │ ├── Poppins-Thin.ttf │ │ └── Poppins-ThinItalic.ttf │ └── images │ │ ├── ChevronLeft.png │ │ ├── ChevronLeft@2x.png │ │ ├── ChevronLeft@3x.png │ │ ├── ChevronRight.png │ │ ├── ChevronRight@2x.png │ │ ├── ChevronRight@3x.png │ │ ├── Close.png │ │ ├── Close@2x.png │ │ ├── Close@3x.png │ │ ├── Share.png │ │ ├── Share@2x.png │ │ ├── Share@3x.png │ │ ├── landing.png │ │ ├── landing@2x.png │ │ ├── landing@3x.png │ │ ├── x.png │ │ ├── x@2x.png │ │ └── x@3x.png ├── bridges │ └── wallet.ts ├── common │ ├── bip39words.ts │ ├── colors.ts │ ├── index.ts │ ├── logger.ts │ ├── migrations.ts │ ├── redux.ts │ ├── sideEffects.ts │ └── types.ts ├── components │ ├── Balance.tsx │ ├── CardTitle.tsx │ ├── CopyButton.tsx │ ├── CopyHeader.tsx │ ├── CustomFont.tsx │ ├── FormTextInput.tsx │ ├── Header.tsx │ ├── HeaderSpan.tsx │ ├── InputContentRow.tsx │ ├── Notice.tsx │ ├── NumericInput.tsx │ ├── PasteButton.tsx │ ├── ScanQRCodeButton.tsx │ ├── SectionTitle.tsx │ ├── SettingsListItem.tsx │ ├── ShareButton.tsx │ ├── ShareRow.tsx │ ├── ShowQRCodeButton.tsx │ ├── Textarea.tsx │ ├── TxListItem.tsx │ └── TxPostConfirmationModal.tsx ├── documents │ ├── legal-disclaimer-ios.ts │ └── receive-from-another-person.ts ├── mocks.ts ├── modules │ ├── app.ts │ ├── balance.ts │ ├── currency-rates.ts │ ├── navigation.tsx │ ├── settings.ts │ ├── toaster.ts │ ├── tor.ts │ ├── tx.ts │ ├── tx │ │ └── receive.ts │ └── wallet.ts ├── screens │ ├── Landing.tsx │ ├── LegalDisclaimer.tsx │ ├── License.tsx │ ├── Licenses.tsx │ ├── NewPassword.tsx │ ├── Overview.tsx │ ├── PaperKey │ │ ├── Show.tsx │ │ └── Verify.tsx │ ├── Password.tsx │ ├── ScanQRCode.tsx │ ├── Settings.tsx │ ├── Settings │ │ ├── Currency.tsx │ │ ├── GrinNode.tsx │ │ └── Support.tsx │ ├── ShowQRCode.tsx │ ├── TxDetails.tsx │ ├── TxIncompleteReceive │ │ ├── GrinAddress.tsx │ │ └── TxIncompleteReceive.tsx │ ├── TxIncompleteSend │ │ ├── SlateCreated.tsx │ │ ├── SlateNotCreated.tsx │ │ └── TxIncompleteSend.tsx │ └── WalletScan.tsx └── themes.ts ├── tsconfig.json └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["module:metro-react-native-babel-preset"], 3 | "plugins": [ 4 | [ 5 | "module-resolver", 6 | { 7 | "root": ["."], 8 | "extensions": [".ts", ".tsx"] 9 | } 10 | ] 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /.bundle/config: -------------------------------------------------------------------------------- 1 | BUNDLE_PATH: "vendor/bundle" 2 | BUNDLE_FORCE_RUBY_PLATFORM: 1 3 | -------------------------------------------------------------------------------- /.env.demo: -------------------------------------------------------------------------------- 1 | APP_ID=app.ironbelly.demo 2 | APP_DISPLAY_NAME="Ironbelly" 3 | DEMO_MODE=true 4 | -------------------------------------------------------------------------------- /.env.dev: -------------------------------------------------------------------------------- 1 | APP_ID=app.ironbelly 2 | APP_DISPLAY_NAME="Ironbelly" 3 | -------------------------------------------------------------------------------- /.env.release: -------------------------------------------------------------------------------- 1 | APP_ID=app.ironbelly 2 | APP_DISPLAY_NAME="Ironbelly" 3 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | // module.exports = { 2 | // root: true, 3 | // extends: '@react-native-community', 4 | // parser: '@typescript-eslint/parser', 5 | // plugins: ['@typescript-eslint'], 6 | // rules: { 7 | // semi: 0, 8 | // }, 9 | // } 10 | 11 | module.exports = { 12 | root: true, 13 | env: { 14 | browser: true, 15 | amd: true, 16 | node: true, 17 | }, 18 | parser: '@typescript-eslint/parser', 19 | plugins: ['react', 'react-native', '@typescript-eslint'], 20 | extends: [ 21 | 'eslint:recommended', 22 | 'plugin:@typescript-eslint/recommended', 23 | 'plugin:react-hooks/recommended', 24 | ], 25 | rules: { 26 | semi: ['error', 'never'], 27 | 'object-curly-spacing': ['error', 'always'], 28 | '@typescript-eslint/explicit-module-boundary-types': 'off', 29 | '@typescript-eslint/no-extra-semi': ['off'], 30 | 'react-native/no-unused-styles': 2, 31 | }, 32 | } 33 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: i1skn 2 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ master ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ master ] 20 | schedule: 21 | - cron: '27 8 * * 3' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'javascript' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] 37 | # Learn more: 38 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed 39 | 40 | steps: 41 | - name: Checkout repository 42 | uses: actions/checkout@v2 43 | 44 | # Initializes the CodeQL tools for scanning. 45 | - name: Initialize CodeQL 46 | uses: github/codeql-action/init@v1 47 | with: 48 | languages: ${{ matrix.language }} 49 | # If you wish to specify custom queries, you can do so here or in a config file. 50 | # By default, queries listed here will override any specified in a config file. 51 | # Prefix the list here with "+" to use these queries and those in the config file. 52 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 53 | 54 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 55 | # If this step fails, then you should remove it and run the build manually (see below) 56 | - name: Autobuild 57 | uses: github/codeql-action/autobuild@v1 58 | 59 | # ℹ️ Command-line programs to run using the OS shell. 60 | # 📚 https://git.io/JvXDl 61 | 62 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 63 | # and modify them (or add more) to build your code if your project 64 | # uses a compiled language 65 | 66 | #- run: | 67 | # make bootstrap 68 | # make release 69 | 70 | - name: Perform CodeQL Analysis 71 | uses: github/codeql-action/analyze@v1 72 | -------------------------------------------------------------------------------- /.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 | *.dSYM.zip 23 | *.xcuserstate 24 | project.xcworkspace 25 | 26 | # Android/IntelliJ 27 | # 28 | build/ 29 | .idea 30 | .gradle 31 | local.properties 32 | *.iml 33 | *.hprof 34 | .cxx/ 35 | *.keystore 36 | !debug.keystore 37 | android/.project 38 | android/.settings/org.eclipse.buildship.core.prefs 39 | android/app/.classpath 40 | android/app/.project 41 | android/app/.settings/org.eclipse.buildship.core.prefs 42 | 43 | # Visual Studio Code 44 | # 45 | .vscode/ 46 | 47 | # node.js 48 | # 49 | node_modules/ 50 | npm-debug.log 51 | yarn-error.log 52 | 53 | # fastlane 54 | # 55 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 56 | # screenshots whenever they are needed. 57 | # For more information about the recommended setup visit: 58 | # https://docs.fastlane.tools/best-practices/source-control/ 59 | 60 | **/fastlane/report.xml 61 | **/fastlane/Preview.html 62 | **/fastlane/screenshots 63 | **/fastlane/metadata 64 | **/fastlane/test_output 65 | 66 | # Bundle artifact 67 | *.jsbundle 68 | android/app/src/main/assets/index.android.bundle 69 | 70 | # Ruby / CocoaPods 71 | /ios/Pods/ 72 | /vendor/bundle/ 73 | 74 | #Cartage 75 | /ios/Carthage/Checkouts/ 76 | 77 | # Android 78 | android/key.json 79 | *.pem 80 | *.apk 81 | *.aab 82 | 83 | # Local tools 84 | slates/* 85 | 86 | # Licenses 87 | licenses.json 88 | 89 | # HTML page with all the snapshots 90 | screenshots/screenshots.html 91 | 92 | .env 93 | 94 | # Wallet compiled libraries and headers 95 | libwallet.* 96 | WalletHeaders.h 97 | 98 | 99 | # Temporary files created by Metro to check the health of the file watcher 100 | .metro-health-check* 101 | 102 | # testing 103 | /coverage 104 | -------------------------------------------------------------------------------- /.node-version: -------------------------------------------------------------------------------- 1 | 16 2 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | arrowParens: 'avoid', 3 | bracketSameLine: true, 4 | bracketSpacing: false, 5 | singleQuote: true, 6 | trailingComma: 'all', 7 | semi: true, 8 | } 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: swift 2 | osx_image: xcode10.2 3 | 4 | if: tag IS blank 5 | 6 | cache: 7 | directories: 8 | - $HOME/.cargo 9 | - $TRAVIS_BUILD_DIR/rust/target 10 | - $TRAVIS_BUILD_DIR/node_modules 11 | - $TRAVIS_BUILD_DIR/ios/Pods 12 | - /usr/local/Cellar/applesimutils 13 | - /usr/local/lib/node_modules 14 | - $HOME/Library/Detox 15 | 16 | env: 17 | global: 18 | - NODE_VERSION=stable 19 | - CODE_SIGNING_REQUIRED=NO 20 | - E2E_TEST=yes 21 | 22 | jobs: 23 | include: 24 | - stage: compile rust code 25 | script: ./scripts/rust.sh 26 | - stage: install applesimutils for detox 27 | script: ./scripts/applesimutils.sh 28 | - stage: npm install 29 | script: ./scripts/npm.sh 30 | - stage: test 31 | script: ./scripts/test.sh 32 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version 4 | ruby '>= 2.6.10' 5 | 6 | gem 'cocoapods', '~> 1.13' 7 | gem 'activesupport', '>= 6.1.7.3', '< 7.1.0' 8 | gem "fastlane" 9 | 10 | plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile') 11 | eval_gemfile(plugins_path) if File.exist?(plugins_path) 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NO LONGER SUPPORTED! 2 | Read more here: https://forum.grin.mw/t/ironbelly-is-spitting-fire-no-longer/11003 3 | 4 | # Ironbelly 5 | 6 | Named after a species of dragon - [Ukrainian Ironbelly](http://harrypotter.wikia.com/wiki/Ukrainian_Ironbelly). One of them guarded some of the oldest and deepest vaults in Gringotts. 7 | This wallet uses React-Native for the UI and official [Grin](https://github.com/mimblewimble/grin/) source code written in Rust. 8 | 9 | ## Contributing 10 | ### Install Rust 11 | `curl https://sh.rustup.rs -sSf | sh` 12 | 13 | ### Set up the environment 14 | 15 | Go to project directory and run: 16 | ``` 17 | cd rust 18 | ./scripts/init.sh // add needed targets for rust 19 | ``` 20 | 21 | ### iOS 22 | 23 | Let's install Xcode build tools first 24 | 25 | `xcode-select --install` 26 | 27 | 28 | #### Build the project 29 | 30 | Go to project directory and run: 31 | ``` 32 | cd rust 33 | ./scripts/build.sh release ios 34 | # All iOS related code lives in `ios/` directory 35 | cd ../ios 36 | sudo gem install cocoapods 37 | pod install 38 | cd .. 39 | npm install 40 | npm start # this will start React Native server 41 | ``` 42 | 43 | After all of these, please open `ios/Ironbelly.xcworkspace` in XCode and run `Product -> Build (⌘B)` 44 | 45 | ### Android 46 | #### Set up the environment 47 | 48 | Install Android SDK / NDK / Platform Tools 49 | ``` 50 | brew cask install android-sdk android-ndk android-platform-tools 51 | ``` 52 | 53 | Add to your `.bashprofile` or `.zshrc`: 54 | ``` 55 | export ANDROID_HOME="$(brew --prefix)/share/android-sdk" 56 | export PATH=$PATH:$ANDROID_HOME/emulator:$ANDROID_HOME/tools:$ANDROID_HOME/tools/bin:$ANDROID_HOME/platform-tools 57 | export ANDROID_NDK_HOME="$(brew --prefix)/share/android-ndk" 58 | ``` 59 | 60 | #### Build the project 61 | Run Android emulator or connect a real device. Now `adb devices` should show at least one device. 62 | 63 | ``` 64 | cd rust 65 | ./scripts/build.sh release android 66 | cd .. 67 | npm install 68 | ``` 69 | Go to the root of the repo and run `react-native run-android` 70 | 71 | ## Beta testing 72 | ### iOS - Testflight 73 | [https://testflight.apple.com/join/GrqGPx9W](https://testflight.apple.com/join/GrqGPx9W) 74 | ### Android 75 | [https://play.google.com/store/apps/details?id=app.ironbelly](https://play.google.com/store/apps/details?id=app.ironbelly) 76 | 77 | ## How to verify Android APK signature 78 | 1. Download the key `gpg --keyserver keys.openpgp.org --search-keys ivan@sorokin.io` 79 | 2. Verify `gpg --verify Ironbelly-vX.Y.Z.B.apk.asc Ironbelly-vX.Y.Z.B.apk` 80 | 81 | ## License 82 | 83 | Apache License v2.0. 84 | -------------------------------------------------------------------------------- /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 | lib_deps = [] 12 | 13 | for jarfile in glob(['libs/*.jar']): 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 | 21 | for aarfile in glob(['libs/*.aar']): 22 | name = 'aars__' + aarfile[aarfile.rindex('/') + 1: aarfile.rindex('.aar')] 23 | lib_deps.append(':' + name) 24 | android_prebuilt_aar( 25 | name = name, 26 | aar = aarfile, 27 | ) 28 | 29 | android_library( 30 | name = "all-libs", 31 | exported_deps = lib_deps, 32 | ) 33 | 34 | android_library( 35 | name = "app-code", 36 | srcs = glob([ 37 | "src/main/java/**/*.java", 38 | ]), 39 | deps = [ 40 | ":all-libs", 41 | ":build_config", 42 | ":res", 43 | ], 44 | ) 45 | 46 | android_build_config( 47 | name = "build_config", 48 | package = "app.ironbelly", 49 | ) 50 | 51 | android_resource( 52 | name = "res", 53 | package = "app.ironbelly", 54 | res = "src/main/res", 55 | ) 56 | 57 | android_binary( 58 | name = "app", 59 | keystore = "//android/keystores:debug", 60 | manifest = "src/main/AndroidManifest.xml", 61 | package_type = "debug", 62 | deps = [ 63 | ":app-code", 64 | ], 65 | ) 66 | -------------------------------------------------------------------------------- /android/app/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/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/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /android/app/src/debug/java/app/ironbelly/ReactNativeFlipper.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. 3 | * 4 | *

This source code is licensed under the MIT license found in the LICENSE file in the root 5 | * directory of this source tree. 6 | */ 7 | package app.ironbelly; 8 | import android.content.Context; 9 | import com.facebook.flipper.android.AndroidFlipperClient; 10 | import com.facebook.flipper.android.utils.FlipperUtils; 11 | import com.facebook.flipper.core.FlipperClient; 12 | import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin; 13 | import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin; 14 | import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin; 15 | import com.facebook.flipper.plugins.inspector.DescriptorMapping; 16 | import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin; 17 | import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor; 18 | import com.facebook.flipper.plugins.network.NetworkFlipperPlugin; 19 | import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin; 20 | import com.facebook.react.ReactInstanceEventListener; 21 | import com.facebook.react.ReactInstanceManager; 22 | import com.facebook.react.bridge.ReactContext; 23 | import com.facebook.react.modules.network.NetworkingModule; 24 | import okhttp3.OkHttpClient; 25 | public class ReactNativeFlipper { 26 | public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { 27 | if (FlipperUtils.shouldEnableFlipper(context)) { 28 | final FlipperClient client = AndroidFlipperClient.getInstance(context); 29 | client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults())); 30 | client.addPlugin(new DatabasesFlipperPlugin(context)); 31 | client.addPlugin(new SharedPreferencesFlipperPlugin(context)); 32 | client.addPlugin(CrashReporterPlugin.getInstance()); 33 | NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin(); 34 | NetworkingModule.setCustomClientBuilder( 35 | new NetworkingModule.CustomClientBuilder() { 36 | @Override 37 | public void apply(OkHttpClient.Builder builder) { 38 | builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin)); 39 | } 40 | }); 41 | client.addPlugin(networkFlipperPlugin); 42 | client.start(); 43 | // Fresco Plugin needs to ensure that ImagePipelineFactory is initialized 44 | // Hence we run if after all native modules have been initialized 45 | ReactContext reactContext = reactInstanceManager.getCurrentReactContext(); 46 | if (reactContext == null) { 47 | reactInstanceManager.addReactInstanceEventListener( 48 | new ReactInstanceEventListener() { 49 | @Override 50 | public void onReactContextInitialized(ReactContext reactContext) { 51 | reactInstanceManager.removeReactInstanceEventListener(this); 52 | reactContext.runOnNativeModulesQueueThread( 53 | new Runnable() { 54 | @Override 55 | public void run() { 56 | client.addPlugin(new FrescoFlipperPlugin()); 57 | } 58 | }); 59 | } 60 | }); 61 | } else { 62 | client.addPlugin(new FrescoFlipperPlugin()); 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 21 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 41 | 42 | 43 | 44 | 45 | 50 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Poppins-ExtraBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/android/app/src/main/assets/fonts/Poppins-ExtraBold.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Poppins-ExtraBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/android/app/src/main/assets/fonts/Poppins-ExtraBoldItalic.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Poppins-ExtraLight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/android/app/src/main/assets/fonts/Poppins-ExtraLight.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Poppins-ExtraLightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/android/app/src/main/assets/fonts/Poppins-ExtraLightItalic.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Poppins-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/android/app/src/main/assets/fonts/Poppins-Italic.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Poppins-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/android/app/src/main/assets/fonts/Poppins-Light.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Poppins-LightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/android/app/src/main/assets/fonts/Poppins-LightItalic.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Poppins-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/android/app/src/main/assets/fonts/Poppins-Medium.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Poppins-MediumItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/android/app/src/main/assets/fonts/Poppins-MediumItalic.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Poppins-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/android/app/src/main/assets/fonts/Poppins-Regular.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Poppins-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/android/app/src/main/assets/fonts/Poppins-SemiBold.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Poppins-SemiBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/android/app/src/main/assets/fonts/Poppins-SemiBoldItalic.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Poppins-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/android/app/src/main/assets/fonts/Poppins-Thin.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Poppins-ThinItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/android/app/src/main/assets/fonts/Poppins-ThinItalic.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/tor/bridges.txt: -------------------------------------------------------------------------------- 1 | obfs4 77.81.104.251:443 115C90EBD0EB631C177560A872535772215478D9 cert=UsuF7oN4KNKviZP54JOyTCoCphrdM5gwZK4vT8GnCAcmqLUJEJxyw1dpko9a/ii6He4iZg iat-mode=0 2 | obfs4 5.249.146.133:80 FAF3A0073330D6AD92F3B4874B0D945562A633EF cert=TRe8bAODtjcGij7EPQaUayWEOqR99wDh2l3B4hFtCsn1JTJCph03pRZ9tx8wynpLYKWMQg iat-mode=0 3 | meek_lite 0.0.2.0:2 97700DFE9F483596DDA6264C4D7DF7641E1E39CE url=https://meek.azureedge.net/ front=ajax.aspnetcdn.com 4 | 5 | -------------------------------------------------------------------------------- /android/app/src/main/java/app/ironbelly/CustomGrinBridge.java: -------------------------------------------------------------------------------- 1 | package app.ironbelly; 2 | 3 | import com.facebook.react.ReactPackage; 4 | import com.facebook.react.bridge.NativeModule; 5 | import com.facebook.react.bridge.ReactApplicationContext; 6 | import com.facebook.react.uimanager.ViewManager; 7 | 8 | import java.util.ArrayList; 9 | import java.util.Collections; 10 | import java.util.List; 11 | 12 | public class CustomGrinBridge implements ReactPackage { 13 | 14 | @Override 15 | public List createViewManagers(ReactApplicationContext reactContext) { 16 | return Collections.emptyList(); 17 | } 18 | 19 | @Override 20 | public List createNativeModules( 21 | ReactApplicationContext reactContext) { 22 | List modules = new ArrayList<>(); 23 | 24 | modules.add(new GrinBridge(reactContext)); 25 | 26 | return modules; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /android/app/src/main/java/app/ironbelly/MainActivity.java: -------------------------------------------------------------------------------- 1 | package app.ironbelly; 2 | import expo.modules.ReactActivityDelegateWrapper; 3 | import com.facebook.react.ReactActivityDelegate; 4 | import android.content.Intent; 5 | import android.graphics.Color; 6 | import android.net.Uri; 7 | import android.os.Build; 8 | import android.os.Bundle; 9 | import android.util.Log; 10 | import android.view.Window; 11 | import android.view.WindowManager; 12 | import com.facebook.react.ReactActivity; 13 | import com.facebook.react.ReactActivityDelegate; 14 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint; 15 | import com.facebook.react.defaults.DefaultReactActivityDelegate; 16 | import org.devio.rn.splashscreen.SplashScreen; 17 | 18 | public class MainActivity extends ReactActivity { 19 | 20 | /** 21 | * Returns the name of the main component registered from JavaScript. This is used to schedule 22 | * rendering of the component. 23 | */ 24 | @Override 25 | protected String getMainComponentName() { 26 | return "Ironbelly"; 27 | } 28 | 29 | @Override 30 | protected void onCreate(Bundle savedInstanceState) { 31 | SplashScreen.show(this); 32 | super.onCreate(savedInstanceState); 33 | Window window = getWindow(); 34 | window.setFlags(WindowManager.LayoutParams.FLAG_SECURE, 35 | WindowManager.LayoutParams.FLAG_SECURE); 36 | } 37 | 38 | // @Override 39 | // protected ReactActivityDelegate createReactActivityDelegate() { 40 | // return new ReactActivityDelegateWrapper(this, 41 | // new ReactActivityDelegate(this, getMainComponentName()) 42 | // ); 43 | // } 44 | 45 | /** 46 | * Returns the instance of the {@link ReactActivityDelegate}. There the RootView is created and 47 | * you can specify the renderer you wish to use - the new renderer (Fabric) or the old renderer 48 | * (Paper). 49 | */ 50 | @Override 51 | protected ReactActivityDelegate createReactActivityDelegate() { 52 | return new DefaultReactActivityDelegate( 53 | this, 54 | getMainComponentName(), 55 | // If you opted-in for the New Architecture, we enable the Fabric Renderer. 56 | DefaultNewArchitectureEntryPoint.getFabricEnabled()); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /android/app/src/main/java/app/ironbelly/MainApplication.java: -------------------------------------------------------------------------------- 1 | package app.ironbelly; 2 | import android.content.res.Configuration; 3 | import expo.modules.ApplicationLifecycleDispatcher; 4 | import expo.modules.ReactNativeHostWrapper; 5 | 6 | import android.app.Application; 7 | import com.facebook.react.PackageList; 8 | import com.facebook.react.ReactApplication; 9 | import com.facebook.react.ReactNativeHost; 10 | import com.facebook.react.ReactPackage; 11 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint; 12 | import com.facebook.react.defaults.DefaultReactNativeHost; 13 | import com.facebook.react.shell.MainReactPackage; 14 | import com.facebook.soloader.SoLoader; 15 | import java.util.List; 16 | import java.util.Arrays; 17 | 18 | public class MainApplication extends Application implements ReactApplication { 19 | private final ReactNativeHost mReactNativeHost = 20 | new ReactNativeHostWrapper(this, new DefaultReactNativeHost(this) { 21 | @Override 22 | public boolean getUseDeveloperSupport() { 23 | return BuildConfig.DEBUG; 24 | } 25 | 26 | @Override 27 | protected List getPackages() { 28 | @SuppressWarnings("UnnecessaryLocalVariable") 29 | List packages = new PackageList(this).getPackages(); 30 | // Packages that cannot be autolinked yet can be added manually here, for example: 31 | packages.add(new CustomGrinBridge()); 32 | return packages; 33 | } 34 | 35 | @Override 36 | protected String getJSMainModuleName() { 37 | return "index"; 38 | } 39 | 40 | @Override 41 | protected boolean isNewArchEnabled() { 42 | return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; 43 | } 44 | 45 | @Override 46 | protected Boolean isHermesEnabled() { 47 | return BuildConfig.IS_HERMES_ENABLED; 48 | } 49 | }); 50 | 51 | @Override 52 | public ReactNativeHost getReactNativeHost() { 53 | return mReactNativeHost; 54 | } 55 | 56 | @Override 57 | public void onCreate() { 58 | super.onCreate(); 59 | SoLoader.init(this, /* native exopackage */ false); 60 | ApplicationLifecycleDispatcher.onApplicationCreate(this); 61 | if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { 62 | // If you opted-in for the New Architecture, we load the native entry point for this app. 63 | DefaultNewArchitectureEntryPoint.load(); 64 | } 65 | ReactNativeFlipper.initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); 66 | } 67 | 68 | 69 | @Override 70 | public void onConfigurationChanged(Configuration newConfig) { 71 | super.onConfigurationChanged(newConfig); 72 | ApplicationLifecycleDispatcher.onConfigurationChanged(this, newConfig); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /android/app/src/main/java/app/ironbelly/SplashActivity.java: -------------------------------------------------------------------------------- 1 | package app.ironbelly; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import androidx.appcompat.app.AppCompatActivity; 6 | 7 | public class SplashActivity extends AppCompatActivity { 8 | @Override 9 | protected void onCreate(Bundle savedInstanceState) { 10 | super.onCreate(savedInstanceState); 11 | 12 | Intent intent = new Intent(this, MainActivity.class); 13 | startActivity(intent); 14 | finish(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /android/app/src/main/java/app/ironbelly/tor/TorConfig.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 The Tari Project 3 | * 4 | * Redistribution and use in source and binary forms, with or 5 | * without modification, are permitted provided that the 6 | * following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above 12 | * copyright notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * 3. Neither the name of the copyright holder nor the names of 16 | * its contributors may be used to endorse or promote products 17 | * derived from this software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 20 | * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 21 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 24 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 30 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package app.ironbelly.tor 34 | 35 | /** 36 | * Tor proxy configuration. 37 | * 38 | * @author The Tari Development Team 39 | */ 40 | data class TorConfig( 41 | val proxyPort: Int, 42 | val controlHost: String, 43 | val controlPort: Int, 44 | val cookieFilePath: String, 45 | ) -------------------------------------------------------------------------------- /android/app/src/main/java/app/ironbelly/tor/TorProxyState.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 The Tari Project 3 | * 4 | * Redistribution and use in source and binary forms, with or 5 | * without modification, are permitted provided that the 6 | * following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above 12 | * copyright notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * 3. Neither the name of the copyright holder nor the names of 16 | * its contributors may be used to endorse or promote products 17 | * derived from this software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 20 | * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 21 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 24 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 30 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | package app.ironbelly.tor 34 | 35 | /** 36 | * Tor proxy state - is deduced from connection state and bootstrap logs. 37 | * 38 | * @author The Tari Development Team 39 | */ 40 | sealed class TorProxyState { 41 | object NotReady : TorProxyState() 42 | object Initializing : TorProxyState() 43 | data class Running(val bootstrapStatus: TorBootstrapStatus) : TorProxyState() 44 | object Failed : TorProxyState() 45 | } 46 | 47 | data class TorBootstrapStatus(val progress: Int, val summary: String, val warning: String? = null) { 48 | 49 | companion object { 50 | 51 | private val warningLogRegex = Regex(".*PROGRESS=(\\d+).*SUMMARY=\"([^\"]*)\".*WARNING=\"([^\"]*)\".*") 52 | private val logRegex = Regex(".*PROGRESS=(\\d+).*SUMMARY=\"([^\"]*)\".*") 53 | const val maxProgress = 100 54 | 55 | fun from(logLine: String): TorBootstrapStatus { 56 | if (warningLogRegex.matches(logLine)) { 57 | val matchResult = warningLogRegex.find(logLine) 58 | val (progress, summary, warning) = matchResult!!.destructured 59 | return TorBootstrapStatus( 60 | progress = progress.toInt(), 61 | summary = summary, 62 | warning = warning 63 | ) 64 | } else if (logRegex.matches(logLine)) { 65 | val matchResult = logRegex.find(logLine) 66 | val (progress, summary) = matchResult!!.destructured 67 | return TorBootstrapStatus( 68 | progress = progress.toInt(), 69 | summary = summary 70 | ) 71 | } 72 | return TorBootstrapStatus( 73 | progress = 0, 74 | summary = "", 75 | warning = null 76 | ) 77 | } 78 | } 79 | 80 | } -------------------------------------------------------------------------------- /android/app/src/main/jniLibs/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | 3 | include $(CLEAR_VARS) 4 | 5 | LOCAL_MODULE := libwallet 6 | LOCAL_SRC_FILES := $(TARGET_ARCH_ABI)/libwallet.so 7 | LOCAL_LDLIBS := -llog 8 | include $(PREBUILT_SHARED_LIBRARY) 9 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/background_splash.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/rn_edit_text_material.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 21 | 22 | 23 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /android/app/src/main/res/layout/launch_screen.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #000000 4 | 5 | 6 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ffffff 4 | 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /android/app/src/main/res/xml/filepaths.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/xml/network_security_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 127.0.0.1 5 | 10.0.1.1 6 | 10.0.2.2 7 | localhost 8 | 9 | 10 | -------------------------------------------------------------------------------- /android/app/src/release/java/app/ironbelly/ReactNativeFlipper.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. 3 | * 4 | *

This source code is licensed under the MIT license found in the LICENSE file in the root 5 | * directory of this source tree. 6 | */ 7 | package com.rndiffapp; 8 | 9 | import android.content.Context; 10 | import com.facebook.react.ReactInstanceManager; 11 | 12 | /** 13 | * Class responsible of loading Flipper inside your React Native application. This is the release 14 | * flavor of it so it's empty as we don't want to load Flipper. 15 | */ 16 | public class ReactNativeFlipper { 17 | public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { 18 | // Do nothing as we don't want to initialize Flipper on Release. 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /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.kotlin_version = '1.8.0' 5 | ext { 6 | buildToolsVersion = "34.0.0" 7 | minSdkVersion = 21 8 | compileSdkVersion = 34 9 | targetSdkVersion = 34 10 | // We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP. 11 | ndkVersion = "23.1.7779620" 12 | } 13 | repositories { 14 | google() 15 | mavenCentral() 16 | } 17 | dependencies { 18 | classpath('com.android.tools.build:gradle:8.1.1') 19 | classpath("com.facebook.react:react-native-gradle-plugin") 20 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 21 | // NOTE: Do not place your application dependencies here; they belong 22 | // in the individual module build.gradle files 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /android/get_apk_from_aab.sh: -------------------------------------------------------------------------------- 1 | aab=$1 2 | apks=app.apks 3 | apk=app.apk 4 | pass=$(security -q find-generic-password -a "Ivan Sorokin" -s "android_keystore" -w) 5 | bundletool build-apks --mode=universal --bundle=$aab --output=$apks --ks=./app/upload-key.keystore --ks-pass="pass:$pass" --ks-key-alias=upload-key-alias --key-pass="pass:$pass" 6 | mv $apks apks.zip 7 | unzip apks.zip -d apks 8 | mv apks/universal.apk $apk 9 | rm -rf apks.zip 10 | rm -rf apks -------------------------------------------------------------------------------- /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: -Xmx512m -XX:MaxMetaspaceSize=256m 13 | org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m 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 | # Set this to pack app in the release mode, but signed with dev keys 21 | # LOCAL_RELEASE=true 22 | 23 | IRONBELLY_UPLOAD_STORE_FILE=upload-key.keystore 24 | IRONBELLY_UPLOAD_KEY_ALIAS=upload-key-alias 25 | 26 | # AndroidX package structure to make it clearer which packages are bundled with the 27 | # Android operating system, and which are packaged with your app's APK 28 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 29 | android.useAndroidX=true 30 | 31 | # Automatically convert third-party libraries to use AndroidX 32 | android.enableJetifier=true 33 | 34 | # Version of flipper SDK to use with React Native 35 | FLIPPER_VERSION=0.182.0 36 | 37 | # android.bundle.enableUncompressedNativeLibs=false 38 | 39 | # Use this property to specify which architecture you want to build. 40 | # You can also override it from the CLI using 41 | # ./gradlew -PreactNativeArchitectures=x86_64 42 | reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 43 | # Use this property to enable support to the new architecture. 44 | # This will allow you to use TurboModules and the Fabric render in 45 | # your application. You should enable this flag either if you want 46 | # to write custom TurboModules/Fabric components OR use libraries that 47 | # are providing them. 48 | newArchEnabled=false 49 | 50 | # Use this property to enable or disable the Hermes JS engine. 51 | # If set to false, you will be using JSC instead. 52 | hermesEnabled=true 53 | android.defaults.buildfeatures.buildconfig=true 54 | android.nonTransitiveRClass=false 55 | android.nonFinalResIds=false 56 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/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-8.1.1-all.zip 4 | networkTimeout=10000 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem http://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 33 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 34 | 35 | @rem Find java.exe 36 | if defined JAVA_HOME goto findJavaFromJavaHome 37 | 38 | set JAVA_EXE=java.exe 39 | %JAVA_EXE% -version >NUL 2>&1 40 | if %ERRORLEVEL% equ 0 goto execute 41 | 42 | echo. 43 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 44 | echo. 45 | echo Please set the JAVA_HOME variable in your environment to match the 46 | echo location of your Java installation. 47 | 48 | goto fail 49 | 50 | :findJavaFromJavaHome 51 | set JAVA_HOME=%JAVA_HOME:"=% 52 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 53 | 54 | if exist "%JAVA_EXE%" goto execute 55 | 56 | echo. 57 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 58 | echo. 59 | echo Please set the JAVA_HOME variable in your environment to match the 60 | echo location of your Java installation. 61 | 62 | goto fail 63 | 64 | :execute 65 | @rem Setup the command line 66 | 67 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 68 | 69 | @rem Execute Gradle 70 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 71 | 72 | :end 73 | @rem End local scope for the variables with windows NT shell 74 | if %ERRORLEVEL% equ 0 goto mainEnd 75 | 76 | :fail 77 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 78 | rem the _cmd.exe /c_ return code! 79 | set EXIT_CODE=%ERRORLEVEL% 80 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 81 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 82 | exit /b %EXIT_CODE% 83 | 84 | :mainEnd 85 | if "%OS%"=="Windows_NT" endlocal 86 | 87 | :omega 88 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'Ironbelly' 2 | apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) 3 | include ':app' 4 | includeBuild('../node_modules/@react-native/gradle-plugin') 5 | 6 | apply from: new File(["node", "--print", "require.resolve('expo/package.json')"].execute(null, rootDir).text.trim(), "../scripts/autolinking.gradle") 7 | useExpoModules() 8 | 9 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Ironbelly", 3 | "displayName": "Ironbelly", 4 | "ios": { "userInterfaceStyle": "automatic" } 5 | } 6 | -------------------------------------------------------------------------------- /docs/balance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/docs/balance.png -------------------------------------------------------------------------------- /docs/balance.uml: -------------------------------------------------------------------------------- 1 | @startuml balance.png 2 | title Balance 3 | ReactNative -> Rust: Request balance 4 | Rust -> lmdb: Request list of outputs 5 | lmdb -> Rust: Return list of outputs 6 | Rust -> Rust: Calculate balance 7 | Rust -> ReactNative: Return balance 8 | @enduml 9 | 10 | -------------------------------------------------------------------------------- /docs/navigation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/docs/navigation.png -------------------------------------------------------------------------------- /docs/navigation.uml: -------------------------------------------------------------------------------- 1 | @startuml 2 | 3 | start 4 | 5 | if (seed file exists?) then (yes) 6 | #lightgreen:show Locked screen; 7 | repeat :wait for user to enter password; 8 | backward :wait 1 second; 9 | repeat while (is entered password correct?) is (no) 10 | ->yes; 11 | if (restore in progress?) then (yes) 12 | #lightgreen:show Restore screen; 13 | else (no) 14 | #lightgreen:show Overview screen; 15 | endif 16 | else (no) 17 | #lightgreen:show Landing screen; 18 | endif 19 | 20 | 21 | @enduml 22 | 23 | -------------------------------------------------------------------------------- /docs/refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/docs/refresh.png -------------------------------------------------------------------------------- /docs/refresh.uml: -------------------------------------------------------------------------------- 1 | @startuml refresh.png 2 | /' skinparam dpi 300 '/ 3 | /' scale 1000 width '/ 4 | title Refresh 5 | ReactNative -> Rust: Request PMMR 6 | Rust -> GrinNode: Request chain Tip 7 | GrinNode -> Rust: Tip 8 | Rust -> GrinNode: Request PMMR range for Last scanned block..Tip blocks 9 | GrinNode -> Rust: PMMR range 10 | Rust -> ReactNative: PMMR range 11 | ReactNative -> ReactNative: n = PMMR range start 12 | loop while n < PMMR range end 13 | ReactNative -> ReactNative: m = n + CONST 14 | ReactNative -> Rust: Request n..m outputs:\nn < m <= PMMR range end 15 | Rust -> GrinNode: Scan n..m outputs 16 | GrinNode -> Rust: n..m outputs 17 | Rust -> Rust: Find ones, which belong to "us" 18 | Rust -> lmdb: Store "our" outputs 19 | Rust -> ReactNative: Successful scan of n..m outputs 20 | ReactNative -> ReactNative: n = m + 1 21 | end 22 | @enduml 23 | 24 | 25 | -------------------------------------------------------------------------------- /docs/release_test.md: -------------------------------------------------------------------------------- 1 | # Manual Test 2 | 3 | Perform this test before hitting release button in stores until we have proper e2e testing in place 4 | 5 | ## Cast 6 | 7 | - Android - new user without a paper key 8 | - iPhone - new user with paper key 9 | - Carol - donor 10 | 11 | ## What to test 12 | 13 | 1. Android sends/receives using slatepack/address 14 | 2. iPhone sends/receives using slatepack/address 15 | 16 | ## Scenario 17 | 18 | 1. iPhone restores his wallet. 19 | 2. Android creates a wallet 20 | 3. Android receives 0.1 Grin via grin address from Carol 21 | 4. iPhone receives 0.1 Grin via grin address from Carol 22 | 23 | 5. iPhone sends 0.01 Grin to Android using slatepack 24 | 25 | 6. Android sends 0.1 Grin to iPhone using slatepack 26 | 27 | 7. Android sends 0.1 back to Carol 28 | 8. iPhone sends 0.1 back to Carol 29 | 9. Android and iPhone remove their accounts 30 | ...(Android should have 0 balance), iPhone should have original balance) 31 | 10. iPhone creates a new wallet 32 | 11. Android restores iPhone's wallet 33 | -------------------------------------------------------------------------------- /e2e/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "setupFilesAfterEnv": ["./init.js"], 3 | "testEnvironment": "node" 4 | } 5 | -------------------------------------------------------------------------------- /e2e/init.js: -------------------------------------------------------------------------------- 1 | const detox = require('detox') 2 | const config = require('../package.json').detox 3 | const adapter = require('detox/runners/jest/adapter') 4 | 5 | jest.setTimeout(120000) 6 | jasmine.getEnv().addReporter(adapter) 7 | 8 | beforeAll(async () => { 9 | await detox.init(config) 10 | }) 11 | 12 | beforeEach(async () => { 13 | await adapter.beforeEach() 14 | }) 15 | 16 | afterAll(async () => { 17 | await adapter.afterAll() 18 | await detox.cleanup() 19 | }) 20 | -------------------------------------------------------------------------------- /e2e/utils.js: -------------------------------------------------------------------------------- 1 | export async function readTextValue(testID) { 2 | try { 3 | await expect(element(by.id(testID))).toHaveText('__read_element_error_') 4 | } catch (error) { 5 | const start = `AX.id='${testID}';` 6 | const end = '; AX.frame' 7 | const errorMessage = error.message.toString() 8 | const [, restMessage] = errorMessage.split(start) 9 | const [label] = restMessage.split(end) 10 | const [, value] = label.split('=') 11 | 12 | return value.slice(1, value.length - 1) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /e2e/walletInit.spec.js: -------------------------------------------------------------------------------- 1 | import { readTextValue } from './utils' 2 | 3 | describe('Ironbelly', () => { 4 | beforeEach(async () => { 5 | await device.reloadReactNative() 6 | }) 7 | 8 | it('should create a new wallet', async () => { 9 | await expect(element(by.id('LandingScreen'))).toBeVisible() 10 | 11 | await element(by.id('NewWalletButton')).tap() 12 | 13 | //Legal 14 | let nextButton = element(by.id('IAgree')) 15 | await expect(nextButton).toBeVisible() 16 | await nextButton.tap() 17 | await element(by.text('I agree to the ')).tap() 18 | await nextButton.tap() 19 | 20 | nextButton = element(by.id('SubmitPassword')) 21 | 22 | const passwordField = element(by.id('Password')) 23 | await expect(passwordField).toBeVisible() 24 | await passwordField.typeText('passcode') 25 | const passwordConfirmField = element(by.id('ConfirmPassword')) 26 | await expect(passwordConfirmField).toBeVisible() 27 | await passwordConfirmField.typeText('passcode1') 28 | await expect(nextButton).toBeVisible() 29 | // passwords are not equal, so the button is disabled 30 | // tap should not change anything 31 | await nextButton.tap() 32 | await passwordConfirmField.tap() 33 | await passwordConfirmField.typeText('passcode') 34 | // Now passwords are equal - buton tap should move to the next step 35 | await waitFor(nextButton) 36 | .toBeVisible() 37 | .withTimeout(2000) 38 | await expect(nextButton).toBeVisible() 39 | await nextButton.tap() 40 | 41 | const words = [] 42 | for (let i = 0; i < 24; i++) { 43 | words[i] = await readTextValue(`Word${i + 1}`) 44 | } 45 | await element(by.id('ShowPaperKeyScrollView')).scrollTo('bottom') 46 | nextButton = element(by.id('ShowPaperKeyContinueButton')) 47 | await expect(nextButton).toBeVisible() 48 | await nextButton.tap() 49 | 50 | nextButton = element(by.id('VerifyPaperKeyContinueButton')) 51 | const wordsCount = 24 52 | for (let i = 0; i < wordsCount - 1; i++) { 53 | const word = element(by.id(`VerifyWord${i + 1}`)) 54 | await word.typeText(words[i]) 55 | await word.tapReturnKey() 56 | } 57 | const lastWord = element(by.id(`VerifyWord${wordsCount}`)) 58 | await lastWord.typeText('aaaa') // enter wrong word 59 | await lastWord.tapReturnKey() 60 | // Words are invalid - button disabled 61 | await expect(nextButton).toBeVisible() 62 | await nextButton.tap() 63 | 64 | await lastWord.tap() 65 | await expect(lastWord).toBeVisible() 66 | await lastWord.replaceText(words[wordsCount - 1]) // enter correct word 67 | await lastWord.tapReturnKey() 68 | 69 | await expect(nextButton).toBeVisible() 70 | await nextButton.tap() 71 | 72 | nextButton = element(by.id('ShowMeButton')) 73 | await expect(nextButton).toBeVisible() 74 | await nextButton.tap() 75 | }) 76 | }) 77 | -------------------------------------------------------------------------------- /fastlane/Appfile: -------------------------------------------------------------------------------- 1 | # iOS 2 | app_identifier("app.ironbelly") # The bundle identifier of your app 3 | apple_id("ivan@sorokin.io") # Your Apple email address 4 | 5 | itc_team_id("120279655") # App Store Connect Team ID 6 | team_id("4496JM56CN") # Developer Portal Team ID 7 | 8 | # Android 9 | json_key_file("android/key.json") # Path to the json secret file - Follow https://docs.fastlane.tools/actions/supply/#setup to get one 10 | package_name("app.ironbelly") # e.g. com.krausefx.app 11 | 12 | 13 | # For more information about the Appfile, see: 14 | # https://docs.fastlane.tools/advanced/#appfile 15 | -------------------------------------------------------------------------------- /fastlane/Deliverfile: -------------------------------------------------------------------------------- 1 | # The Deliverfile allows you to store various App Store Connect metadata 2 | # For more information, check out the docs 3 | # https://docs.fastlane.tools/actions/deliver/ 4 | -------------------------------------------------------------------------------- /fastlane/Fastfile: -------------------------------------------------------------------------------- 1 | # This file contains the fastlane.tools configuration 2 | # You can find the documentation at https://docs.fastlane.tools 3 | # 4 | # For a list of all available actions, check out 5 | # 6 | # https://docs.fastlane.tools/actions 7 | # 8 | # For a list of all available plugins, check out 9 | # 10 | # https://docs.fastlane.tools/plugins/available-plugins 11 | # 12 | 13 | # Uncomment the line if you want fastlane to automatically update itself 14 | # update_fastlane 15 | 16 | default_platform(:ios) 17 | 18 | platform :ios do 19 | desc "Bump new version for iOS" 20 | 21 | lane :bumpVersion do |options| 22 | if options[:type] 23 | increment_version_number(xcodeproj: "ios/Ironbelly.xcodeproj", bump_type: options[:type]) 24 | end 25 | end 26 | 27 | lane :bumpBuildNumber do |options| 28 | increment_build_number(xcodeproj: "ios/Ironbelly.xcodeproj") 29 | end 30 | 31 | desc "Push a new beta build to TestFlight" 32 | 33 | lane :beta do 34 | build_app(workspace: "ios/Ironbelly.xcworkspace", scheme: "Ironbelly", export_xcargs: "-allowProvisioningUpdates") 35 | upload_to_testflight() 36 | end 37 | end 38 | 39 | platform :android do 40 | desc "Submit a new Alpha Build to Play Market" 41 | lane :alpha do 42 | gradle(task: "clean bundleRelease", project_dir: 'android/') 43 | upload_to_play_store(track: 'alpha') 44 | end 45 | 46 | desc "Submit a new Internal Build to Play Market" 47 | lane :internal do 48 | gradle(task: "clean bundleRelease", project_dir: 'android/') 49 | upload_to_play_store(track: 'internal') 50 | end 51 | 52 | desc "Build Release APK" 53 | lane :apk do 54 | gradle(task: "clean assembleRelease", project_dir: 'android/') 55 | end 56 | 57 | lane :bumpVersion do |options| 58 | if options[:type] 59 | increment_version_name( 60 | gradle_file_path: "./android/app/build.gradle", 61 | bump_type: options[:type] 62 | ) 63 | end 64 | end 65 | lane :bumpBuildNumber do |options| 66 | if options[:type] 67 | increment_version_code(gradle_file_path: "./android/app/build.gradle") 68 | end 69 | end 70 | end 71 | 72 | -------------------------------------------------------------------------------- /fastlane/Pluginfile: -------------------------------------------------------------------------------- 1 | # Autogenerated by fastlane 2 | # 3 | # Ensure this file is checked in to source control! 4 | 5 | gem 'fastlane-plugin-increment_version_name' 6 | gem 'fastlane-plugin-increment_version_code' 7 | -------------------------------------------------------------------------------- /fastlane/README.md: -------------------------------------------------------------------------------- 1 | fastlane documentation 2 | ---- 3 | 4 | # Installation 5 | 6 | Make sure you have the latest version of the Xcode command line tools installed: 7 | 8 | ```sh 9 | xcode-select --install 10 | ``` 11 | 12 | For _fastlane_ installation instructions, see [Installing _fastlane_](https://docs.fastlane.tools/#installing-fastlane) 13 | 14 | # Available Actions 15 | 16 | ## iOS 17 | 18 | ### ios bumpVersion 19 | 20 | ```sh 21 | [bundle exec] fastlane ios bumpVersion 22 | ``` 23 | 24 | Bump new version for iOS 25 | 26 | ### ios bumpBuildNumber 27 | 28 | ```sh 29 | [bundle exec] fastlane ios bumpBuildNumber 30 | ``` 31 | 32 | 33 | 34 | ### ios beta 35 | 36 | ```sh 37 | [bundle exec] fastlane ios beta 38 | ``` 39 | 40 | Push a new beta build to TestFlight 41 | 42 | ---- 43 | 44 | 45 | ## Android 46 | 47 | ### android alpha 48 | 49 | ```sh 50 | [bundle exec] fastlane android alpha 51 | ``` 52 | 53 | Submit a new Alpha Build to Play Market 54 | 55 | ### android internal 56 | 57 | ```sh 58 | [bundle exec] fastlane android internal 59 | ``` 60 | 61 | Submit a new Internal Build to Play Market 62 | 63 | ### android apk 64 | 65 | ```sh 66 | [bundle exec] fastlane android apk 67 | ``` 68 | 69 | Build Release APK 70 | 71 | ### android bumpVersion 72 | 73 | ```sh 74 | [bundle exec] fastlane android bumpVersion 75 | ``` 76 | 77 | 78 | 79 | ### android bumpBuildNumber 80 | 81 | ```sh 82 | [bundle exec] fastlane android bumpBuildNumber 83 | ``` 84 | 85 | 86 | 87 | ---- 88 | 89 | This README.md is auto-generated and will be re-generated every time [_fastlane_](https://fastlane.tools) is run. 90 | 91 | More information about _fastlane_ can be found on [fastlane.tools](https://fastlane.tools). 92 | 93 | The documentation of _fastlane_ can be found on [docs.fastlane.tools](https://docs.fastlane.tools). 94 | -------------------------------------------------------------------------------- /fastlane/Snapfile: -------------------------------------------------------------------------------- 1 | # Uncomment the lines below you want to change by removing the # in the beginning 2 | 3 | # A list of devices you want to take the screenshots from 4 | devices([ 5 | # "iPhone 8", 6 | "iPhone 8 Plus", 7 | # "iPhone SE", 8 | "iPhone 12 Pro Max", 9 | # "iPhone X", 10 | # "iPad Pro (12.9-inch)", 11 | # "iPad Pro (9.7-inch)", 12 | # "Apple TV 1080p" 13 | ]) 14 | 15 | languages([ 16 | "en-US", 17 | # "de-DE", 18 | # "it-IT", 19 | # ["pt", "pt_BR"] # Portuguese with Brazilian locale 20 | ]) 21 | 22 | # Choose which project/workspace to use 23 | # project "./Project.xcodeproj" 24 | workspace "./ios/Ironbelly.xcworkspace" 25 | 26 | # The name of the scheme which contains the UI Tests 27 | scheme("Snapshots") 28 | 29 | # Where should the resulting screenshots be stored? 30 | output_directory("./fastlane/screenshots") 31 | 32 | # remove the '#' to clear all previously generated screenshots before creating new ones 33 | clear_previous_screenshots(true) 34 | 35 | # Remove the '#' to set the status bar to 9:41 AM, and show full battery and reception. 36 | override_status_bar(true) 37 | 38 | # Arguments to pass to the app on launch. See https://docs.fastlane.tools/actions/snapshot/#launch-arguments 39 | # launch_arguments(["-favColor red"]) 40 | 41 | # For more information about all available options run 42 | # fastlane action snapshot 43 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Ironbelly Devs 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import './rn-polyfill-depricated-proptypes' 18 | import {AppRegistry} from 'react-native' 19 | import App from './src/App' 20 | import {name as appName} from './app.json' 21 | 22 | import '@react-native-community/netinfo' 23 | import 'react-native-gesture-handler' 24 | 25 | // NetInfo.configure({ 26 | // reachabilityUrl: ' https://node.ironbelly.app/', 27 | // reachabilityTest: async (response) => response.status === 200, 28 | // }) 29 | 30 | AppRegistry.registerComponent(appName, () => App) 31 | -------------------------------------------------------------------------------- /ios/.xcode.env: -------------------------------------------------------------------------------- 1 | # This `.xcode.env` file is versioned and is used to source the environment 2 | # used when running script phases inside Xcode. 3 | # To customize your local environment, you can create an `.xcode.env.local` 4 | # file that is not versioned. 5 | 6 | # NODE_BINARY variable contains the PATH to the node executable. 7 | # 8 | # Customize the NODE_BINARY variable here. 9 | # For example, to use nvm with brew, add the following line 10 | # . "$(brew --prefix nvm)/nvm.sh" --no-use 11 | export NODE_BINARY=$(command -v node) 12 | -------------------------------------------------------------------------------- /ios/.xcode.env.local: -------------------------------------------------------------------------------- 1 | export NODE_BINARY="/Users/i1skn/.n/bin/node" 2 | -------------------------------------------------------------------------------- /ios/Cartfile: -------------------------------------------------------------------------------- 1 | github "iCepa/Tor.framework" "master" 2 | -------------------------------------------------------------------------------- /ios/Cartfile.resolved: -------------------------------------------------------------------------------- 1 | github "iCepa/Tor.framework" "19eb9505bd77d14757322541b26a6dca7f03dfde" 2 | -------------------------------------------------------------------------------- /ios/Ironbelly.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Ironbelly.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Ironbelly.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildSystemType 6 | Latest 7 | PreviewsEnabled 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Ironbelly/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Ironbelly Devs 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 18 | 19 | import UIKit 20 | import LaunchScreenSnapshot 21 | import ExpoModulesCore 22 | import React 23 | 24 | @UIApplicationMain 25 | class AppDelegate: EXAppDelegateWrapper, RCTBridgeDelegate, UIApplicationDelegate { 26 | 27 | var window: UIWindow? 28 | var bridge: RCTBridge! 29 | 30 | func sourceURL(for bridge: RCTBridge!) -> URL! { 31 | #if DEBUG 32 | return RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index") 33 | #else 34 | Bundle.main.url(forResource: "main", withExtension: "jsbundle") 35 | #endif 36 | } 37 | 38 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 39 | 40 | c_set_logger() 41 | 42 | self.bridge = RCTBridge(delegate: self, launchOptions: launchOptions) 43 | let rootView = RCTRootView(bridge: self.bridge, moduleName: "Ironbelly", initialProperties: nil) 44 | let rootViewController = UIViewController() 45 | rootViewController.view = rootView 46 | 47 | self.window = UIWindow(frame: UIScreen.main.bounds) 48 | self.window?.rootViewController = rootViewController 49 | self.window?.makeKeyAndVisible() 50 | 51 | LaunchScreenSnapshot.protect(with: nil, trigger: .didEnterBackground) 52 | RNSplashScreen.show() 53 | 54 | return true 55 | } 56 | 57 | func application(_ app: UIApplication, 58 | open url: URL, 59 | options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { 60 | RCTLinkingManager.application(app, open: url, options: options) 61 | return true 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "icon_20pt@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "icon_20pt@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "icon_29pt@2x.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "icon_29pt@3x.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "40x40", 29 | "idiom" : "iphone", 30 | "filename" : "icon_40pt@2x.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "icon_40pt@3x.png", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "size" : "60x60", 41 | "idiom" : "iphone", 42 | "filename" : "icon_60pt@2x.png", 43 | "scale" : "2x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "icon_60pt@3x.png", 49 | "scale" : "3x" 50 | }, 51 | { 52 | "size" : "20x20", 53 | "idiom" : "ipad", 54 | "filename" : "icon_20pt.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "icon_20pt@2x-1.png", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "size" : "29x29", 65 | "idiom" : "ipad", 66 | "filename" : "icon_29pt.png", 67 | "scale" : "1x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "icon_29pt@2x-1.png", 73 | "scale" : "2x" 74 | }, 75 | { 76 | "size" : "40x40", 77 | "idiom" : "ipad", 78 | "filename" : "icon_40pt.png", 79 | "scale" : "1x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "icon_40pt@2x-1.png", 85 | "scale" : "2x" 86 | }, 87 | { 88 | "size" : "76x76", 89 | "idiom" : "ipad", 90 | "filename" : "icon_76pt.png", 91 | "scale" : "1x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "icon_76pt@2x.png", 97 | "scale" : "2x" 98 | }, 99 | { 100 | "size" : "83.5x83.5", 101 | "idiom" : "ipad", 102 | "filename" : "icon_83.5@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "1024x1024", 107 | "idiom" : "ios-marketing", 108 | "filename" : "Icon.png", 109 | "scale" : "1x" 110 | } 111 | ], 112 | "info" : { 113 | "version" : 1, 114 | "author" : "xcode" 115 | } 116 | } -------------------------------------------------------------------------------- /ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/Icon.png -------------------------------------------------------------------------------- /ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/icon_20pt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/icon_20pt.png -------------------------------------------------------------------------------- /ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/icon_20pt@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/icon_20pt@2x-1.png -------------------------------------------------------------------------------- /ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/icon_20pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/icon_20pt@2x.png -------------------------------------------------------------------------------- /ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/icon_20pt@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/icon_20pt@3x.png -------------------------------------------------------------------------------- /ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/icon_29pt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/icon_29pt.png -------------------------------------------------------------------------------- /ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/icon_29pt@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/icon_29pt@2x-1.png -------------------------------------------------------------------------------- /ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/icon_29pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/icon_29pt@2x.png -------------------------------------------------------------------------------- /ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/icon_29pt@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/icon_29pt@3x.png -------------------------------------------------------------------------------- /ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/icon_40pt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/icon_40pt.png -------------------------------------------------------------------------------- /ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/icon_40pt@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/icon_40pt@2x-1.png -------------------------------------------------------------------------------- /ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/icon_40pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/icon_40pt@2x.png -------------------------------------------------------------------------------- /ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/icon_40pt@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/icon_40pt@3x.png -------------------------------------------------------------------------------- /ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/icon_60pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/icon_60pt@2x.png -------------------------------------------------------------------------------- /ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/icon_60pt@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/icon_60pt@3x.png -------------------------------------------------------------------------------- /ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/icon_76pt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/icon_76pt.png -------------------------------------------------------------------------------- /ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/icon_76pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/icon_76pt@2x.png -------------------------------------------------------------------------------- /ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/icon_83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/Assets.xcassets/AppIcon.appiconset/icon_83.5@2x.png -------------------------------------------------------------------------------- /ios/Ironbelly/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /ios/Ironbelly/Assets.xcassets/LaunchLogo.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchLogo.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchLogo@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchLogo@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /ios/Ironbelly/Assets.xcassets/LaunchLogo.imageset/LaunchLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/Assets.xcassets/LaunchLogo.imageset/LaunchLogo.png -------------------------------------------------------------------------------- /ios/Ironbelly/Assets.xcassets/LaunchLogo.imageset/LaunchLogo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/Assets.xcassets/LaunchLogo.imageset/LaunchLogo@2x.png -------------------------------------------------------------------------------- /ios/Ironbelly/Assets.xcassets/LaunchLogo.imageset/LaunchLogo@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/Assets.xcassets/LaunchLogo.imageset/LaunchLogo@3x.png -------------------------------------------------------------------------------- /ios/Ironbelly/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /ios/Ironbelly/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ios-marketing", 45 | "scale" : "1x", 46 | "size" : "1024x1024" 47 | } 48 | ], 49 | "info" : { 50 | "author" : "xcode", 51 | "version" : 1 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /ios/Ironbelly/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /ios/Ironbelly/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | Ironbelly 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 5.3.0 21 | CFBundleVersion 22 | 52 23 | ITSAppUsesNonExemptEncryption 24 | 25 | LSRequiresIPhoneOS 26 | 27 | LSSupportsOpeningDocumentsInPlace 28 | 29 | NSAppTransportSecurity 30 | 31 | NSAllowsArbitraryLoads 32 | 33 | 34 | NSCameraUsageDescription 35 | To scan QR codes 36 | NSFaceIDUsageDescription 37 | Enabling Face ID allows you quick and secure access to your wallet. 38 | NSLocationAlwaysUsageDescription 39 | Need access while using app to access your location. 40 | NSLocationWhenInUseUsageDescription 41 | Need access while using app to access your location. 42 | NSPhotoLibraryUsageDescription 43 | To read QR codes 44 | UIAppFonts 45 | 46 | FontAwesome5_Regular.ttf 47 | FontAwesome5_Solid.ttf 48 | MaterialCommunityIcons.ttf 49 | FontAwesome.ttf 50 | Ionicons.ttf 51 | Feather.ttf 52 | Poppins-Black.ttf 53 | Poppins-BlackItalic.ttf 54 | Poppins-Bold.ttf 55 | Poppins-BoldItalic.ttf 56 | Poppins-ExtraBold.ttf 57 | Poppins-ExtraBoldItalic.ttf 58 | Poppins-ExtraLight.ttf 59 | Poppins-ExtraLightItalic.ttf 60 | Poppins-Italic.ttf 61 | Poppins-Light.ttf 62 | Poppins-LightItalic.ttf 63 | Poppins-Medium.ttf 64 | Poppins-MediumItalic.ttf 65 | Poppins-Regular.ttf 66 | Poppins-SemiBold.ttf 67 | Poppins-SemiBoldItalic.ttf 68 | Poppins-Thin.ttf 69 | Poppins-ThinItalic.ttf 70 | 71 | UILaunchStoryboardName 72 | LaunchScreen 73 | UIRequiredDeviceCapabilities 74 | 75 | armv7 76 | 77 | UISupportedInterfaceOrientations 78 | 79 | UIInterfaceOrientationPortrait 80 | 81 | UISupportedInterfaceOrientations~ipad 82 | 83 | UIInterfaceOrientationPortrait 84 | UIInterfaceOrientationPortraitUpsideDown 85 | UIInterfaceOrientationLandscapeLeft 86 | UIInterfaceOrientationLandscapeRight 87 | 88 | UIViewControllerBasedStatusBarAppearance 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /ios/Ironbelly/Tor/Helpers/NetworkTools.h: -------------------------------------------------------------------------------- 1 | // NetworkTools.h 2 | 3 | /* 4 | Package MobileWallet 5 | Created by S.Shovkoplyas on 01.09.2020 6 | Using Swift 5.0 7 | Running on macOS 10.15 8 | 9 | Copyright 2019 The Tari Project 10 | 11 | Redistribution and use in source and binary forms, with or 12 | without modification, are permitted provided that the 13 | following conditions are met: 14 | 15 | 1. Redistributions of source code must retain the above copyright notice, 16 | this list of conditions and the following disclaimer. 17 | 18 | 2. Redistributions in binary form must reproduce the above 19 | copyright notice, this list of conditions and the following disclaimer in the 20 | documentation and/or other materials provided with the distribution. 21 | 22 | 3. Neither the name of the copyright holder nor the names of 23 | its contributors may be used to endorse or promote products 24 | derived from this software without specific prior written permission. 25 | 26 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 27 | CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 28 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 29 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 30 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 31 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 32 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 33 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 34 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 36 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 37 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | */ 40 | 41 | #import 42 | 43 | NS_ASSUME_NONNULL_BEGIN 44 | 45 | @interface NetworkTools : NSObject 46 | 47 | +(NSDictionary *)addressesForProtocol:(int)ipVersion; 48 | 49 | @end 50 | 51 | NS_ASSUME_NONNULL_END 52 | -------------------------------------------------------------------------------- /ios/Ironbelly/Utils.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Utils.swift 3 | // Ironbelly 4 | // 5 | // Created by Ivan Sorokin on 06.11.20. 6 | // Copyright © 2020 Ivan Sorokin. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | func returnToReact(error: UInt8, cResult: UnsafePointer, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { 12 | 13 | let result = String(cString: cResult) 14 | if error == 0 { 15 | resolve(result) 16 | } else { 17 | reject(nil, result, nil) 18 | } 19 | cstr_free(UnsafeMutablePointer(mutating: cResult)) 20 | } 21 | 22 | func checkOpenedWallet(_ wallet: UInt?, _ reject: RCTPromiseRejectBlock) -> UInt? { 23 | 24 | if let w = wallet { 25 | return w 26 | } else { 27 | reject(nil, "Wallet was not opened", nil) 28 | return nil 29 | } 30 | } 31 | 32 | extension NSPointerArray { 33 | func addObject(_ object: AnyObject?) { 34 | guard let strongObject = object else { return } 35 | 36 | let pointer = Unmanaged.passUnretained(strongObject).toOpaque() 37 | addPointer(pointer) 38 | } 39 | 40 | func insertObject(_ object: AnyObject?, at index: Int) { 41 | guard index < count, let strongObject = object else { return } 42 | 43 | let pointer = Unmanaged.passUnretained(strongObject).toOpaque() 44 | insertPointer(pointer, at: index) 45 | } 46 | 47 | func replaceObject(at index: Int, withObject object: AnyObject?) { 48 | guard index < count, let strongObject = object else { return } 49 | 50 | let pointer = Unmanaged.passUnretained(strongObject).toOpaque() 51 | replacePointer(at: index, withPointer: pointer) 52 | } 53 | 54 | func object(at index: Int) -> AnyObject? { 55 | guard index < count, let pointer = self.pointer(at: index) else { return nil } 56 | return Unmanaged.fromOpaque(pointer).takeUnretainedValue() 57 | } 58 | 59 | func removeObject(at index: Int) { 60 | guard index < count else { return } 61 | 62 | removePointer(at: index) 63 | } 64 | 65 | func remove(_ object: AnyObject) { 66 | // get pointer to the passed in object 67 | let objPtr = Unmanaged.passUnretained(object).toOpaque() 68 | var objIndex = -1 69 | for i in 0..= 0 && objIndex < count { 81 | removePointer(at: objIndex) 82 | } 83 | } 84 | } 85 | 86 | let dateFormatter = DateFormatter() 87 | 88 | func logTor(_ logMessage: String) { 89 | dateFormatter.dateFormat = "HH:mm:ss.SSS" 90 | print("TOR: \(dateFormatter.string(from: Date())) \(logMessage)") 91 | } 92 | -------------------------------------------------------------------------------- /ios/Ironbelly/Wallet-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Ironbelly Devs 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 18 | 19 | #ifndef Wallet_Bridging_Header_h 20 | #define Wallet_Bridging_Header_h 21 | 22 | #import 23 | #import "WalletHeaders.h" 24 | #import "Tor/Helpers/NetworkTools.h" 25 | #import "RNSplashScreen.h" 26 | #endif /* Wallet_Bridging_Header_h */ 27 | -------------------------------------------------------------------------------- /ios/Ironbelly/assets/src/assets/images/ReceiveTX.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/assets/src/assets/images/ReceiveTX.png -------------------------------------------------------------------------------- /ios/Ironbelly/assets/src/assets/images/ReceiveTX@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/assets/src/assets/images/ReceiveTX@2x.png -------------------------------------------------------------------------------- /ios/Ironbelly/assets/src/assets/images/ReceiveTX@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/assets/src/assets/images/ReceiveTX@3x.png -------------------------------------------------------------------------------- /ios/Ironbelly/assets/src/assets/images/SendTX.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/assets/src/assets/images/SendTX.png -------------------------------------------------------------------------------- /ios/Ironbelly/assets/src/assets/images/SendTX@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/assets/src/assets/images/SendTX@2x.png -------------------------------------------------------------------------------- /ios/Ironbelly/assets/src/assets/images/SendTX@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/assets/src/assets/images/SendTX@3x.png -------------------------------------------------------------------------------- /ios/Ironbelly/assets/src/assets/images/Settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/assets/src/assets/images/Settings.png -------------------------------------------------------------------------------- /ios/Ironbelly/assets/src/assets/images/Settings@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/assets/src/assets/images/Settings@2x.png -------------------------------------------------------------------------------- /ios/Ironbelly/assets/src/assets/images/Settings@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/assets/src/assets/images/Settings@3x.png -------------------------------------------------------------------------------- /ios/Ironbelly/assets/src/assets/images/Share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/assets/src/assets/images/Share.png -------------------------------------------------------------------------------- /ios/Ironbelly/assets/src/assets/images/Share@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/assets/src/assets/images/Share@2x.png -------------------------------------------------------------------------------- /ios/Ironbelly/assets/src/assets/images/Share@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/assets/src/assets/images/Share@3x.png -------------------------------------------------------------------------------- /ios/Ironbelly/assets/src/assets/images/x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/assets/src/assets/images/x.png -------------------------------------------------------------------------------- /ios/Ironbelly/assets/src/assets/images/x@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/assets/src/assets/images/x@2x.png -------------------------------------------------------------------------------- /ios/Ironbelly/assets/src/assets/images/x@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/ios/Ironbelly/assets/src/assets/images/x@3x.png -------------------------------------------------------------------------------- /ios/IronbellyTests/IronbellyTests.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 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 Native!" 16 | 17 | @interface IronbellyTests : XCTestCase 18 | 19 | @end 20 | 21 | @implementation IronbellyTests 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 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { 44 | if (level >= RCTLogLevelError) { 45 | redboxError = message; 46 | } 47 | }); 48 | 49 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { 50 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 51 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 52 | 53 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) { 54 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { 55 | return YES; 56 | } 57 | return NO; 58 | }]; 59 | } 60 | 61 | RCTSetLogFunction(RCTDefaultLogFunction); 62 | 63 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); 64 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); 65 | } 66 | 67 | 68 | @end 69 | -------------------------------------------------------------------------------- /ios/UITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 5.3.0 19 | CFBundleVersion 20 | 52 21 | 22 | 23 | -------------------------------------------------------------------------------- /ios/UITests/UITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UITests.swift 3 | // UITests 4 | // 5 | // Created by Ivan Sorokin on 29.11.20. 6 | // Copyright © 2020 Ivan Sorokin. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class UITests: XCTestCase { 12 | 13 | override func setUpWithError() throws { 14 | // Put setup code here. This method is called before the invocation of each test method in the class. 15 | 16 | // In UI tests it is usually best to stop immediately when a failure occurs. 17 | continueAfterFailure = false 18 | 19 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 20 | } 21 | 22 | override func tearDownWithError() throws { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | } 25 | 26 | func testSnapshots() throws { 27 | // UI tests must launch the application that they test. 28 | let app = XCUIApplication() 29 | setupSnapshot(app) 30 | app.launch() 31 | 32 | XCUIApplication().otherElements["UnlockBtn"].waitForExistence(timeout: 30) 33 | XCUIApplication().otherElements["UnlockBtn"].tap() 34 | snapshot("01OverviewScreen") 35 | 36 | //XCUIApplication().otherElements["SendTab"].waitForExistence(timeout: 30) 37 | XCUIApplication().otherElements["SendTab"].tap() 38 | snapshot("02SendScreen") 39 | XCUIApplication().otherElements["GoBackChevron"].tap() 40 | 41 | 42 | //XCUIApplication().otherElements["ReceiveTab"].waitForExistence(timeout: 30) 43 | XCUIApplication().otherElements["ReceiveTab"].tap() 44 | snapshot("03ReceiveScreen") 45 | XCUIApplication().otherElements["GoBackChevron"].tap() 46 | 47 | 48 | // XCUIApplication().otherElements["SettingsTab"].waitForExistence(timeout: 30) 49 | XCUIApplication().otherElements["SettingsTab"].tap() 50 | snapshot("04SettingsScreen") 51 | } 52 | 53 | // func testLaunchPerformance() throws { 54 | // if #available(macOS 10.15, iOS 13.0, tvOS 13.0, *) { 55 | // // This measures how long it takes to launch your application. 56 | // measure(metrics: [XCTApplicationLaunchMetric()]) { 57 | // XCUIApplication().launch() 58 | // } 59 | // } 60 | // } 61 | } 62 | -------------------------------------------------------------------------------- /ios/Wallet.xcframework/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AvailableLibraries 6 | 7 | 8 | HeadersPath 9 | ../WalletHeaders.h 10 | LibraryIdentifier 11 | ios-arm64 12 | LibraryPath 13 | libwallet.a 14 | SupportedArchitectures 15 | 16 | arm64 17 | 18 | SupportedPlatform 19 | ios 20 | 21 | 22 | HeadersPath 23 | ../WalletHeaders.h 24 | LibraryIdentifier 25 | ios-arm64_x86_64-simulator 26 | LibraryPath 27 | libwallet.a 28 | SupportedArchitectures 29 | 30 | arm64 31 | x86_64 32 | 33 | SupportedPlatform 34 | ios 35 | SupportedPlatformVariant 36 | simulator 37 | 38 | 39 | CFBundlePackageType 40 | XFWK 41 | XCFrameworkFormatVersion 42 | 1.0 43 | 44 | 45 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'react-native', 3 | }; 4 | -------------------------------------------------------------------------------- /metro.config.js: -------------------------------------------------------------------------------- 1 | const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config'); 2 | 3 | /** 4 | * Metro configuration 5 | * https://facebook.github.io/metro/docs/configuration 6 | * 7 | * @type {import('metro-config').MetroConfig} 8 | */ 9 | const config = {}; 10 | 11 | module.exports = mergeConfig(getDefaultConfig(__dirname), config); 12 | -------------------------------------------------------------------------------- /patches/react-native-background-timer+2.4.1.patch: -------------------------------------------------------------------------------- 1 | diff --git a/node_modules/react-native-background-timer/android/build.gradle b/node_modules/react-native-background-timer/android/build.gradle 2 | index 85cda09..ee0bd3f 100644 3 | --- a/node_modules/react-native-background-timer/android/build.gradle 4 | +++ b/node_modules/react-native-background-timer/android/build.gradle 5 | @@ -7,6 +7,8 @@ def safeExtGet(prop, fallback) { 6 | android { 7 | compileSdkVersion safeExtGet('compileSdkVersion', 28) 8 | 9 | + namespace "com.ocetnik.timer" 10 | + 11 | defaultConfig { 12 | minSdkVersion safeExtGet('minSdkVersion', 16) 13 | targetSdkVersion safeExtGet('targetSdkVersion', 28) 14 | diff --git a/node_modules/react-native-background-timer/android/src/main/AndroidManifest.xml b/node_modules/react-native-background-timer/android/src/main/AndroidManifest.xml 15 | index 73a8a7f..1b9c48f 100755 16 | --- a/node_modules/react-native-background-timer/android/src/main/AndroidManifest.xml 17 | +++ b/node_modules/react-native-background-timer/android/src/main/AndroidManifest.xml 18 | @@ -1,3 +1,3 @@ 19 | - 20 | + 21 | 22 | 23 | -------------------------------------------------------------------------------- /patches/react-native-config+1.5.1.patch: -------------------------------------------------------------------------------- 1 | diff --git a/node_modules/react-native-config/android/build.gradle b/node_modules/react-native-config/android/build.gradle 2 | index c8f7fd4..9ff2c3c 100644 3 | --- a/node_modules/react-native-config/android/build.gradle 4 | +++ b/node_modules/react-native-config/android/build.gradle 5 | @@ -27,6 +27,8 @@ android { 6 | lintOptions { 7 | abortOnError false 8 | } 9 | + 10 | + namespace "com.lugg.RNCConfig" 11 | } 12 | 13 | repositories { 14 | diff --git a/node_modules/react-native-config/android/src/main/AndroidManifest.xml b/node_modules/react-native-config/android/src/main/AndroidManifest.xml 15 | index 12d7c74..a2f47b6 100644 16 | --- a/node_modules/react-native-config/android/src/main/AndroidManifest.xml 17 | +++ b/node_modules/react-native-config/android/src/main/AndroidManifest.xml 18 | @@ -1,3 +1,2 @@ 19 | - 21 | + 22 | 23 | -------------------------------------------------------------------------------- /patches/react-native-fs+2.20.0.patch: -------------------------------------------------------------------------------- 1 | diff --git a/node_modules/react-native-fs/android/build.gradle b/node_modules/react-native-fs/android/build.gradle 2 | index ddef857..6772fc5 100644 3 | --- a/node_modules/react-native-fs/android/build.gradle 4 | +++ b/node_modules/react-native-fs/android/build.gradle 5 | @@ -18,6 +18,8 @@ android { 6 | compileSdkVersion safeExtGet('compileSdkVersion', 26) 7 | buildToolsVersion safeExtGet('buildToolsVersion', '26.0.3') 8 | 9 | + namespace "com.rnfs" 10 | + 11 | defaultConfig { 12 | minSdkVersion safeExtGet('minSdkVersion', 19) 13 | targetSdkVersion safeExtGet('targetSdkVersion', 26) 14 | diff --git a/node_modules/react-native-fs/android/src/main/AndroidManifest.xml b/node_modules/react-native-fs/android/src/main/AndroidManifest.xml 15 | index 6e54f65..7ce2281 100644 16 | --- a/node_modules/react-native-fs/android/src/main/AndroidManifest.xml 17 | +++ b/node_modules/react-native-fs/android/src/main/AndroidManifest.xml 18 | @@ -1,5 +1,4 @@ 19 | 20 | - 22 | + 23 | 24 | 25 | -------------------------------------------------------------------------------- /patches/react-native-keep-awake+4.0.0.patch: -------------------------------------------------------------------------------- 1 | diff --git a/node_modules/react-native-keep-awake/android/build.gradle b/node_modules/react-native-keep-awake/android/build.gradle 2 | index ba4dfe7..41f88d6 100644 3 | --- a/node_modules/react-native-keep-awake/android/build.gradle 4 | +++ b/node_modules/react-native-keep-awake/android/build.gradle 5 | @@ -1,7 +1,7 @@ 6 | buildscript { 7 | repositories { 8 | google() 9 | - jcenter() 10 | + mavenCentral() 11 | } 12 | 13 | dependencies { 14 | @@ -23,6 +23,8 @@ android { 15 | compileSdkVersion _compileSdkVersion 16 | buildToolsVersion _buildToolsVersion 17 | 18 | + namespace "com.corbt.keepawake" 19 | + 20 | defaultConfig { 21 | minSdkVersion _minSdkVersion 22 | targetSdkVersion _targetSdkVersion 23 | diff --git a/node_modules/react-native-keep-awake/android/src/main/AndroidManifest.xml b/node_modules/react-native-keep-awake/android/src/main/AndroidManifest.xml 24 | index bc02af3..9a40236 100644 25 | --- a/node_modules/react-native-keep-awake/android/src/main/AndroidManifest.xml 26 | +++ b/node_modules/react-native-keep-awake/android/src/main/AndroidManifest.xml 27 | @@ -1,4 +1,3 @@ 28 | 29 | - 31 | + 32 | 33 | diff --git a/node_modules/react-native-keep-awake/react-native-keep-awake.podspec b/node_modules/react-native-keep-awake/react-native-keep-awake.podspec 34 | index 95933a7..756ad5a 100644 35 | --- a/node_modules/react-native-keep-awake/react-native-keep-awake.podspec 36 | +++ b/node_modules/react-native-keep-awake/react-native-keep-awake.podspec 37 | @@ -18,5 +18,5 @@ Pod::Spec.new do |s| 38 | s.preserve_paths = 'README.md', 'package.json', 'index.js' 39 | s.source_files = 'ios/*.{h,m}' 40 | 41 | - s.dependency 'React' 42 | + s.dependency 'React-Core' 43 | end 44 | -------------------------------------------------------------------------------- /patches/react-native-linear-gradient+2.8.3.patch: -------------------------------------------------------------------------------- 1 | diff --git a/node_modules/react-native-linear-gradient/android/build.gradle b/node_modules/react-native-linear-gradient/android/build.gradle 2 | index e3aacde..8dc1376 100644 3 | --- a/node_modules/react-native-linear-gradient/android/build.gradle 4 | +++ b/node_modules/react-native-linear-gradient/android/build.gradle 5 | @@ -28,6 +28,8 @@ android { 6 | lintOptions { 7 | abortOnError false 8 | } 9 | + 10 | + namespace "com.BV.LinearGradient" 11 | } 12 | 13 | repositories { 14 | diff --git a/node_modules/react-native-linear-gradient/android/src/main/AndroidManifest.xml b/node_modules/react-native-linear-gradient/android/src/main/AndroidManifest.xml 15 | index a7d57a6..cc947c5 100644 16 | --- a/node_modules/react-native-linear-gradient/android/src/main/AndroidManifest.xml 17 | +++ b/node_modules/react-native-linear-gradient/android/src/main/AndroidManifest.xml 18 | @@ -1 +1 @@ 19 | - 20 | + 21 | -------------------------------------------------------------------------------- /patches/react-native-navigation-bar-color+2.0.2.patch: -------------------------------------------------------------------------------- 1 | diff --git a/node_modules/react-native-navigation-bar-color/android/build.gradle b/node_modules/react-native-navigation-bar-color/android/build.gradle 2 | index 9d285c4..835201b 100644 3 | --- a/node_modules/react-native-navigation-bar-color/android/build.gradle 4 | +++ b/node_modules/react-native-navigation-bar-color/android/build.gradle 5 | @@ -19,6 +19,8 @@ android { 6 | compileSdkVersion rootProject.ext.has('compileSdkVersion') ? rootProject.ext.compileSdkVersion : DEFAULT_COMPILE_SDK_VERSION 7 | buildToolsVersion rootProject.ext.has('buildToolsVersion') ? rootProject.ext.buildToolsVersion : DEFAULT_BUILD_TOOLS_VERSION 8 | 9 | + namespace "com.thebylito.navigationbarcolor" 10 | + 11 | defaultConfig { 12 | minSdkVersion rootProject.ext.has('minSdkVersion') ? rootProject.ext.minSdkVersion : DEFAULT_MIN_SDK_VERSION 13 | targetSdkVersion rootProject.ext.has('targetSdkVersion') ? rootProject.ext.targetSdkVersion : DEFAULT_TARGET_SDK_VERSION 14 | diff --git a/node_modules/react-native-navigation-bar-color/android/src/main/AndroidManifest.xml b/node_modules/react-native-navigation-bar-color/android/src/main/AndroidManifest.xml 15 | index 02625c9..a2f47b6 100644 16 | --- a/node_modules/react-native-navigation-bar-color/android/src/main/AndroidManifest.xml 17 | +++ b/node_modules/react-native-navigation-bar-color/android/src/main/AndroidManifest.xml 18 | @@ -1,3 +1,2 @@ 19 | - 21 | + 22 | 23 | -------------------------------------------------------------------------------- /patches/react-native-splash-screen+3.3.0.patch: -------------------------------------------------------------------------------- 1 | diff --git a/node_modules/react-native-splash-screen/android/build.gradle b/node_modules/react-native-splash-screen/android/build.gradle 2 | index baef1a9..5aab4f2 100644 3 | --- a/node_modules/react-native-splash-screen/android/build.gradle 4 | +++ b/node_modules/react-native-splash-screen/android/build.gradle 5 | @@ -25,6 +25,7 @@ android { 6 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 7 | } 8 | } 9 | + namespace "org.devio.rn.splashscreen" 10 | } 11 | 12 | dependencies { 13 | diff --git a/node_modules/react-native-splash-screen/android/src/main/AndroidManifest.xml b/node_modules/react-native-splash-screen/android/src/main/AndroidManifest.xml 14 | index be5bfe9..a2f47b6 100644 15 | --- a/node_modules/react-native-splash-screen/android/src/main/AndroidManifest.xml 16 | +++ b/node_modules/react-native-splash-screen/android/src/main/AndroidManifest.xml 17 | @@ -1,4 +1,2 @@ 18 | - 20 | - 21 | + 22 | 23 | -------------------------------------------------------------------------------- /patches/react-native-vector-icons+10.0.3.patch: -------------------------------------------------------------------------------- 1 | diff --git a/node_modules/react-native-vector-icons/android/build.gradle b/node_modules/react-native-vector-icons/android/build.gradle 2 | index 3e615e9..ea1b87d 100644 3 | --- a/node_modules/react-native-vector-icons/android/build.gradle 4 | +++ b/node_modules/react-native-vector-icons/android/build.gradle 5 | @@ -23,6 +23,10 @@ if (isNewArchitectureEnabled()) { 6 | android { 7 | namespace = "com.oblador.vectoricons" 8 | compileSdkVersion safeExtGet('compileSdkVersion', 31) 9 | + buildFeatures { 10 | + buildConfig = true 11 | + } 12 | + namespace "com.oblador.vectoricons" 13 | 14 | defaultConfig { 15 | minSdkVersion safeExtGet('minSdkVersion', 21) 16 | diff --git a/node_modules/react-native-vector-icons/android/src/main/AndroidManifest.xml b/node_modules/react-native-vector-icons/android/src/main/AndroidManifest.xml 17 | index 3bd661a..a2f47b6 100755 18 | --- a/node_modules/react-native-vector-icons/android/src/main/AndroidManifest.xml 19 | +++ b/node_modules/react-native-vector-icons/android/src/main/AndroidManifest.xml 20 | @@ -1,2 +1,2 @@ 21 | - 22 | + 23 | 24 | -------------------------------------------------------------------------------- /react-native.config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Ironbelly Devs 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | module.exports = { 18 | project: { 19 | ios: {}, 20 | android: {}, 21 | }, 22 | assets: ['./src/assets/fonts/', './src/assets/images/'], 23 | } 24 | -------------------------------------------------------------------------------- /rn-polyfill-depricated-proptypes.js: -------------------------------------------------------------------------------- 1 | /** 2 | *File: rn-polyfill-depricated-proptypes.js 3 | **/ 4 | 5 | const StandardModule = require('react-native'); 6 | const dpProps = require('deprecated-react-native-prop-types'); 7 | 8 | const txtImputProx = new Proxy(StandardModule.TextInput, { 9 | get(obj, prop) { 10 | if (prop === 'propTypes') return dpProps.TextInputPropTypes; 11 | return Reflect.get(...arguments); 12 | }, 13 | }); 14 | 15 | Object.defineProperty(StandardModule, 'ColorPropType', { 16 | configurable: true, 17 | get() { 18 | return dpProps.ColorPropType; 19 | }, 20 | }); 21 | 22 | Object.defineProperty(StandardModule, 'EdgeInsetsPropType', { 23 | configurable: true, 24 | get() { 25 | return dpProps.EdgeInsetsPropType; 26 | }, 27 | }); 28 | 29 | Object.defineProperty(StandardModule, 'PointPropType', { 30 | configurable: true, 31 | get() { 32 | return dpProps.PointPropType; 33 | }, 34 | }); 35 | 36 | Object.defineProperty(StandardModule, 'ViewPropTypes', { 37 | configurable: true, 38 | get() { 39 | return dpProps.ViewPropTypes; 40 | }, 41 | }); 42 | 43 | Object.defineProperty(StandardModule, 'TextPropTypes', { 44 | configurable: true, 45 | get() { 46 | return dpProps.TextPropTypes; 47 | }, 48 | }); 49 | 50 | Object.defineProperty(StandardModule, 'TextInputPropTypes', { 51 | configurable: true, 52 | get() { 53 | return dpProps.TextInputPropTypes; 54 | }, 55 | }); 56 | 57 | Object.defineProperty(StandardModule, 'TextInput', { 58 | configurable: true, 59 | get() { 60 | // return dpProps.TextInputPropTypes; 61 | return txtImputProx; 62 | }, 63 | }); 64 | 65 | // Object.defineProperty(StandardModule, 'TextStylePropTypes', { 66 | // configurable: true, 67 | // get() { 68 | // return dpProps.TextInputPropTypes; 69 | // }, 70 | // }); 71 | 72 | // Object.defineProperty(StandardModule, 'ImagePropTypes', { 73 | // configurable: true, 74 | // get() { 75 | // return require('deprecated-react-native-prop-types/DeprecatedImagePropType'); 76 | // }, 77 | // }); 78 | 79 | // Object.defineProperty(StandardModule, 'ImageStylePropTypes', { 80 | // configurable: true, 81 | // get() { 82 | // return require('deprecated-react-native-prop-types/DeprecatedImageStylePropTypes'); 83 | // }, 84 | // }); 85 | 86 | // Object.defineProperty(StandardModule, 'ViewStylePropTypes', { 87 | // configurable: true, 88 | // get() { 89 | // return dpProps.ViewPropTypes; 90 | // }, 91 | // }); 92 | 93 | // console.log("StandardModule--> ", StandardModule.ColorPropType); 94 | -------------------------------------------------------------------------------- /rust/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | -------------------------------------------------------------------------------- /rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ironbelly-wallet" 3 | version = "0.1.0" 4 | authors = ["Ivan Sorokin "] 5 | description = "Ironbelly - Grin mobile wallet" 6 | publish = false 7 | edition = "2018" 8 | 9 | [dependencies] 10 | clap = { version = "2.31", features = ["yaml"] } 11 | rpassword = "2.0.0" 12 | ctrlc = { version = "3.1", features = ["termination"] } 13 | jni = { version = "0.10.2", default-features = false, optional = true } 14 | failure = "0.1" 15 | failure_derive = "0.1" 16 | prettytable-rs = "0.7" 17 | log = "0.4" 18 | uuid = { version = "0.8", features = ["serde", "v4"] } 19 | serde = { version = "1.0", features = ["derive"] } 20 | serde_json = "1" 21 | serde_derive = "1" 22 | simplelog = "^0.7.4" 23 | openssl = { version = "0.10", features = ["vendored"] } 24 | futures = "0.3" 25 | 26 | 27 | # For Release 28 | # ^ 29 | # Does not exist yet 30 | 31 | # For bleeding edge 32 | grin_wallet_api = { git = "https://github.com/i1skn/grin-wallet", branch = "master" } 33 | grin_wallet_impls = { git = "https://github.com/i1skn/grin-wallet", branch = "master" } 34 | grin_wallet_libwallet = { git = "https://github.com/i1skn/grin-wallet", branch = "master" } 35 | grin_wallet_config = { git = "https://github.com/i1skn/grin-wallet", branch = "master" } 36 | grin_wallet_util = { git = "https://github.com/i1skn/grin-wallet", branch = "master" } 37 | grin_wallet_controller = { git = "https://github.com/i1skn/grin-wallet", branch = "master" } 38 | grin_core = { git = "https://github.com/mimblewimble/grin", branch = "master" } 39 | grin_keychain = { git = "https://github.com/mimblewimble/grin", branch = "master" } 40 | grin_util = { git = "https://github.com/mimblewimble/grin", branch = "master" } 41 | grin_api = { git = "https://github.com/mimblewimble/grin", branch = "master" } 42 | 43 | 44 | # For local testing 45 | # grin_wallet_api = { path = "../../../i1skn/grin-wallet/api", version = "5.2.0-beta.1" } 46 | # grin_wallet_impls = { path = "../../../i1skn/grin-wallet/impls", version = "5.2.0-beta.1" } 47 | # grin_wallet_libwallet = { path = "../../../i1skn/grin-wallet/libwallet", version = "5.2.0-beta.1" } 48 | # grin_wallet_config = { path = "../../../i1skn/grin-wallet/config", version = "5.2.0-beta.1" } 49 | # grin_wallet_util = { path = "../../../i1skn/grin-wallet/util", version = "5.2.0-beta.1" } 50 | # grin_wallet_controller = { path = "../../../i1skn/grin-wallet/controller", version = "5.2.0-beta.1" } 51 | # grin_core = { git = "https://github.com/mimblewimble/grin", branch = "master" } 52 | # grin_keychain = { git = "https://github.com/mimblewimble/grin", branch = "master" } 53 | # grin_util = { git = "https://github.com/mimblewimble/grin", branch = "master" } 54 | # grin_api = { git = "https://github.com/mimblewimble/grin", branch = "master" } 55 | 56 | 57 | [target.'cfg(target_os = "android")'.dependencies] 58 | android_logger = "0.8" 59 | 60 | [build-dependencies] 61 | built = "0.3" 62 | cbindgen = "0.8.3" 63 | 64 | [lib] 65 | name = "wallet" 66 | crate-type = ["staticlib", "cdylib"] 67 | 68 | [patch.crates-io] 69 | # croaring = { path = "../../../i1skn/croaring-rs/croaring" } 70 | liblmdb-sys = { git = "https://github.com/i1skn/lmdb-rs" } 71 | # openssl-src = { git = "https://github.com/i1skn/openssl-src-rs", branch = "release/111" } 72 | 73 | [features] 74 | default = ["jni"] 75 | -------------------------------------------------------------------------------- /rust/build.rs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Ironbelly Devs 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | extern crate cbindgen; 17 | 18 | use std::env; 19 | 20 | fn main() { 21 | let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); 22 | 23 | cbindgen::Builder::new() 24 | .with_crate(crate_dir) 25 | .with_language(cbindgen::Language::C) 26 | .with_autogen_warning( 27 | r#"typedef struct api_server {} api_server; 28 | typedef struct wallet {} wallet;"#, 29 | ) 30 | .rename_item("ApiServer", "api_server") 31 | .rename_item("Wallet", "wallet") 32 | .generate() 33 | .expect("Unable to generate bindings") 34 | .write_to_file("../ios/Wallet.xcframework/WalletHeaders.h"); 35 | } 36 | -------------------------------------------------------------------------------- /rust/scripts/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source ./scripts/variables.sh 3 | 4 | mode=$1 5 | platform=$2 6 | if [ -z "$mode" ] || [ "$mode" != "debug" -a "$mode" != "release" ] ; then 7 | echo "Please specify configuration ('debug' or 'release')" 1>&2 8 | exit 1 9 | fi 10 | if [ "$mode" == "debug" ] ; then 11 | rust_mode="" 12 | else 13 | rust_mode="--release" 14 | fi 15 | if [ -z "$platform" ] || [ "$platform" == "android" ] || [ "$platform" == "all" ] ; then 16 | if [ -z ${ANDROID_NDK_HOME+x} ]; 17 | then 18 | printf 'Please install android-ndk\n\n' 19 | printf 'from https://developer.android.com/ndk/downloads or with sdkmanager' 20 | exit 1 21 | else 22 | printf "Building Andriod targets in $mode mode...\n"; 23 | fi 24 | printf "Building ARM64 Android target...\n"; 25 | # needed for rust-bindgen 26 | CLANG_PATH="${ANDROID_PREBUILD_BIN}/aarch64-linux-android${API_LEVEL}-clang" \ 27 | CC_aarch64_linux_android="${ANDROID_PREBUILD_BIN}/aarch64-linux-android${API_LEVEL}-clang" \ 28 | CXX_aarch64_linux_android="${ANDROID_PREBUILD_BIN}/aarch64-linux-android${API_LEVEL}-clang++" \ 29 | CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER="${ANDROID_PREBUILD_BIN}/aarch64-linux-android${API_LEVEL}-clang" \ 30 | AR_aarch64_linux_android="${ANDROID_PREBUILD_BIN}/aarch64-linux-android-ar" \ 31 | cargo build --target aarch64-linux-android $rust_mode --lib 32 | 33 | printf "Building ARMv7 Android target...\n"; 34 | # needed for rust-bindgen 35 | CLANG_PATH="${ANDROID_PREBUILD_BIN}/armv7a-linux-androideabi${API_LEVEL}-clang" \ 36 | CC_armv7_linux_androideabi="${ANDROID_PREBUILD_BIN}/armv7a-linux-androideabi${API_LEVEL}-clang" \ 37 | CXX_armv7_linux_androideabi="${ANDROID_PREBUILD_BIN}/armv7a-linux-androideabi${API_LEVEL}-clang++" \ 38 | CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER="${ANDROID_PREBUILD_BIN}/armv7a-linux-androideabi${API_LEVEL}-clang" \ 39 | AR_armv7_linux_androideabi="${ANDROID_PREBUILD_BIN}/arm-linux-androideabi-ar" \ 40 | cargo build --target armv7-linux-androideabi $rust_mode --lib 41 | 42 | printf "Building 64-bit x86 Android target...\n"; 43 | # needed for rust-bindgen 44 | CLANG_PATH="${ANDROID_PREBUILD_BIN}/x86_64-linux-android${API_LEVEL}-clang" \ 45 | CC_x86_64_linux_android="${ANDROID_PREBUILD_BIN}/x86_64-linux-android${API_LEVEL}-clang" \ 46 | CXX_x86_64_linux_android="${ANDROID_PREBUILD_BIN}/x86_64-linux-android${API_LEVEL}-clang++" \ 47 | CARGO_TARGET_X86_64_LINUX_ANDROID_LINKER="${ANDROID_PREBUILD_BIN}/x86_64-linux-android${API_LEVEL}-clang" \ 48 | AR_x86_64_linux_android="${ANDROID_PREBUILD_BIN}/x86_64-linux-android-ar" \ 49 | cargo build --target x86_64-linux-android $rust_mode --lib 50 | 51 | for i in "${!ANDROID_ARCHS[@]}"; 52 | do 53 | mkdir -p -v "../android/app/src/main/jniLibs/${ANDROID_FOLDER[$i]}" 54 | cp "./target/${ANDROID_ARCHS[$i]}/$mode/lib${LIB_NAME}.so" "../android/app/src/main/jniLibs/${ANDROID_FOLDER[$i]}/lib${LIB_NAME}.so" 55 | done 56 | fi 57 | 58 | if [ -z "$platform" ] || [ "$platform" == "ios" ] || [ "$platform" == "all" ] ; then 59 | printf "Building iOS targets in $mode mode...\n"; 60 | for i in "${IOS_ARCHS[@]}"; 61 | do 62 | printf "Building $i target...\n"; 63 | cargo build --target "$i" $rust_mode --no-default-features 64 | done 65 | 66 | lipo -create -output "../ios/Wallet.xcframework/ios-arm64_x86_64-simulator/lib${LIB_NAME}.a" target/x86_64-apple-ios/$mode/lib${LIB_NAME}.a target/aarch64-apple-ios-sim/$mode/lib${LIB_NAME}.a 67 | cp target/aarch64-apple-ios/$mode/lib${LIB_NAME}.a ../ios/Wallet.xcframework/ios-arm64/lib${LIB_NAME}.a 68 | fi 69 | -------------------------------------------------------------------------------- /rust/scripts/init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./scripts/variables.sh 4 | 5 | cargo install cargo-lipo 6 | 7 | case "$(uname | tr '[:upper:]' '[:lower:]')" in 8 | darwin) 9 | echo 'Add rust toolchains for android and ios' 10 | for i in "${IOS_ARCHS[@]}"; 11 | do rustup target add "$i"; 12 | done 13 | for i in "${ANDROID_ARCHS[@]}"; 14 | do rustup target add "$i" ; 15 | done 16 | ;; 17 | linux) 18 | echo 'Add rust toolchains for android' 19 | for i in "${ANDROID_ARCHS[@]}"; 20 | do rustup target add "$i" ; 21 | done 22 | ;; 23 | *) 24 | echo 'Please use a Linux or Mac to build' 25 | ;; 26 | esac 27 | 28 | -------------------------------------------------------------------------------- /rust/scripts/variables.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Change this name to the rust library name 4 | LIB_NAME=wallet 5 | API_LEVEL=29 6 | 7 | ANDROID_ARCHS=(aarch64-linux-android armv7-linux-androideabi x86_64-linux-android) 8 | ANDROID_FOLDER=(arm64-v8a armeabi-v7a x86_64) 9 | ANDROID_BIN_PREFIX=(aarch64-linux-android armv7a-linux-androideabi x86_64-linux-android) 10 | IOS_ARCHS=(aarch64-apple-ios aarch64-apple-ios-sim x86_64-apple-ios) 11 | OS_ARCH=$(uname | tr '[:upper:]' '[:lower:]') 12 | 13 | ANDROID_PREBUILD_BIN=${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/${OS_ARCH}-x86_64/bin 14 | 15 | -------------------------------------------------------------------------------- /scripts/applesimutils.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | if [ ! $(ls -A /usr/local/Cellar/applesimutils | wc -l) -gt 0 ] 4 | then 5 | brew config 6 | brew tap wix/brew 7 | brew install applesimutils 8 | fi 9 | -------------------------------------------------------------------------------- /scripts/licenses.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const fetch = require('node-fetch') 4 | const util = require('util') 5 | const crypto = require('crypto') 6 | const fs = require('fs') 7 | const path = require('path') 8 | const checker = require('license-checker') 9 | const _ = require('lodash') 10 | 11 | const additionalPackages = require('./additional-licenses') 12 | 13 | const rootDir = path.join(__dirname, `../`) 14 | const packageNameRegexp = /\//g 15 | 16 | function sanitizePackageName(packageName) { 17 | return packageName.replace(packageNameRegexp, '-') 18 | } 19 | 20 | async function main() { 21 | const args = { 22 | start: rootDir, 23 | production: true, 24 | customFormat: { 25 | name: '', 26 | url: false, 27 | version: false, 28 | description: false, 29 | licenses: false, 30 | copyright: false, 31 | licenseFile: false, 32 | licenseText: 'none', 33 | licenseModified: false, 34 | repository: false, 35 | publisher: false, 36 | email: false, 37 | path: false, 38 | }, 39 | } 40 | 41 | const pkgs = { 42 | ...(await util.promisify(checker.init)(args)), 43 | ...additionalPackages, 44 | } 45 | const groupedPkgs = _.groupBy(pkgs, (pkg) => pkg.licenseText) 46 | 47 | const result = { 48 | licenses: {}, 49 | packages: {}, 50 | } 51 | 52 | let licenseId = 0 53 | for (const licenseText of Object.keys(groupedPkgs)) { 54 | result.licenses[licenseId] = licenseText 55 | for (const pkg of groupedPkgs[licenseText]) { 56 | result.packages[pkg.name] = licenseId 57 | } 58 | licenseId++ 59 | } 60 | fs.writeFileSync(path.join(rootDir, 'licenses.json'), JSON.stringify(result)) 61 | } 62 | 63 | main() 64 | -------------------------------------------------------------------------------- /scripts/npm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | npm install 3 | -------------------------------------------------------------------------------- /scripts/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | brew unlink applesimutils && brew link applesimutils 4 | cd ios/ 5 | pod install 6 | cd .. 7 | npm install -g react-native-cli 8 | npm install -g detox-cli 9 | detox build --configuration ios.sim.release > /dev/null 10 | # detox clean-framework-cache && detox build-framework-cache 11 | detox test --configuration ios.sim.release --cleanup 12 | -------------------------------------------------------------------------------- /sign-with-local.sh: -------------------------------------------------------------------------------- 1 | #/bin/sh 2 | 3 | if [ -z $1 ]; then 4 | echo "Please provide tx_slate_id" 5 | exit 6 | fi 7 | 8 | SLATE_PATH=slates/$1.grinslate 9 | 10 | adb pull /data/user/0/app.ironbelly/files/$SLATE_PATH $SLATE_PATH 11 | grin-wallet --floonet -p 1 receive -i $SLATE_PATH 12 | adb push $SLATE_PATH.response /sdcard/Download/ 13 | -------------------------------------------------------------------------------- /src/assets/fonts/Poppins-ExtraBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/src/assets/fonts/Poppins-ExtraBold.ttf -------------------------------------------------------------------------------- /src/assets/fonts/Poppins-ExtraBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/src/assets/fonts/Poppins-ExtraBoldItalic.ttf -------------------------------------------------------------------------------- /src/assets/fonts/Poppins-ExtraLight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/src/assets/fonts/Poppins-ExtraLight.ttf -------------------------------------------------------------------------------- /src/assets/fonts/Poppins-ExtraLightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/src/assets/fonts/Poppins-ExtraLightItalic.ttf -------------------------------------------------------------------------------- /src/assets/fonts/Poppins-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/src/assets/fonts/Poppins-Italic.ttf -------------------------------------------------------------------------------- /src/assets/fonts/Poppins-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/src/assets/fonts/Poppins-Light.ttf -------------------------------------------------------------------------------- /src/assets/fonts/Poppins-LightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/src/assets/fonts/Poppins-LightItalic.ttf -------------------------------------------------------------------------------- /src/assets/fonts/Poppins-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/src/assets/fonts/Poppins-Medium.ttf -------------------------------------------------------------------------------- /src/assets/fonts/Poppins-MediumItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/src/assets/fonts/Poppins-MediumItalic.ttf -------------------------------------------------------------------------------- /src/assets/fonts/Poppins-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/src/assets/fonts/Poppins-Regular.ttf -------------------------------------------------------------------------------- /src/assets/fonts/Poppins-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/src/assets/fonts/Poppins-SemiBold.ttf -------------------------------------------------------------------------------- /src/assets/fonts/Poppins-SemiBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/src/assets/fonts/Poppins-SemiBoldItalic.ttf -------------------------------------------------------------------------------- /src/assets/fonts/Poppins-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/src/assets/fonts/Poppins-Thin.ttf -------------------------------------------------------------------------------- /src/assets/fonts/Poppins-ThinItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/src/assets/fonts/Poppins-ThinItalic.ttf -------------------------------------------------------------------------------- /src/assets/images/ChevronLeft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/src/assets/images/ChevronLeft.png -------------------------------------------------------------------------------- /src/assets/images/ChevronLeft@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/src/assets/images/ChevronLeft@2x.png -------------------------------------------------------------------------------- /src/assets/images/ChevronLeft@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/src/assets/images/ChevronLeft@3x.png -------------------------------------------------------------------------------- /src/assets/images/ChevronRight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/src/assets/images/ChevronRight.png -------------------------------------------------------------------------------- /src/assets/images/ChevronRight@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/src/assets/images/ChevronRight@2x.png -------------------------------------------------------------------------------- /src/assets/images/ChevronRight@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/src/assets/images/ChevronRight@3x.png -------------------------------------------------------------------------------- /src/assets/images/Close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/src/assets/images/Close.png -------------------------------------------------------------------------------- /src/assets/images/Close@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/src/assets/images/Close@2x.png -------------------------------------------------------------------------------- /src/assets/images/Close@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/src/assets/images/Close@3x.png -------------------------------------------------------------------------------- /src/assets/images/Share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/src/assets/images/Share.png -------------------------------------------------------------------------------- /src/assets/images/Share@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/src/assets/images/Share@2x.png -------------------------------------------------------------------------------- /src/assets/images/Share@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/src/assets/images/Share@3x.png -------------------------------------------------------------------------------- /src/assets/images/landing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/src/assets/images/landing.png -------------------------------------------------------------------------------- /src/assets/images/landing@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/src/assets/images/landing@2x.png -------------------------------------------------------------------------------- /src/assets/images/landing@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/src/assets/images/landing@3x.png -------------------------------------------------------------------------------- /src/assets/images/x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/src/assets/images/x.png -------------------------------------------------------------------------------- /src/assets/images/x@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/src/assets/images/x@2x.png -------------------------------------------------------------------------------- /src/assets/images/x@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i1skn/ironbelly/0b3bb276390a99fe6ec7ff764c5d1a5aa9df8cc6/src/assets/images/x@3x.png -------------------------------------------------------------------------------- /src/common/logger.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Ironbelly Devs 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { store } from 'src/common/redux' 18 | export const log = ( 19 | e: Error | { message: string }, 20 | showToUser = false, 21 | ) => { 22 | if (!(e instanceof Error) && e.message) { 23 | e = new Error(e.message) 24 | } 25 | 26 | if (showToUser && e.message) { 27 | store.dispatch({ 28 | type: 'TOAST_SHOW', 29 | text: e.message, 30 | }) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/common/migrations.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Ironbelly Devs 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { MAINNET_DEFAULT_NODE, MAINNET_API_SECRET } from 'src/modules/settings' 18 | import { store } from 'src/common/redux' 19 | export const migrations = { 20 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 21 | 0: (state: any) => { 22 | return { 23 | ...state, 24 | settings: { 25 | ...state.settings, 26 | checkNodeApiHttpAddr: 27 | state.settings.checkNodeApiHttpAddr === 28 | 'http://grinnode.cycle42.com:23413' 29 | ? MAINNET_DEFAULT_NODE 30 | : state.settings.checkNodeApiHttpAddr, 31 | }, 32 | } 33 | }, 34 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 35 | 1: (state: any) => { 36 | const unsafeNode = 37 | state.settings.checkNodeApiHttpAddr === 'http://grinnode.cycle42.com:3413' 38 | if (unsafeNode) { 39 | // yeah, a side effect 40 | store.dispatch({ type: 'SET_API_SECRET', apiSecret: MAINNET_API_SECRET }) 41 | } 42 | return { 43 | ...state, 44 | settings: { 45 | ...state.settings, 46 | checkNodeApiHttpAddr: unsafeNode 47 | ? MAINNET_DEFAULT_NODE 48 | : state.settings.checkNodeApiHttpAddr, 49 | }, 50 | } 51 | }, 52 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 53 | 2: (state: any) => { 54 | const oldNode = 55 | state.settings.checkNodeApiHttpAddr === 'https://node.ironbelly.app' 56 | return { 57 | ...state, 58 | settings: { 59 | ...state.settings, 60 | checkNodeApiHttpAddr: oldNode 61 | ? MAINNET_DEFAULT_NODE 62 | : state.settings.checkNodeApiHttpAddr, 63 | }, 64 | } 65 | }, 66 | } 67 | -------------------------------------------------------------------------------- /src/common/sideEffects.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Ironbelly Devs 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { Store, Action, Dispatch } from 'src/common/types' 18 | 19 | type ProbablyAction = Action | null | undefined 20 | type Effect = (a: Action, s: Store) => ProbablyAction | Promise 21 | type Effects = { 22 | [x: string]: Effect 23 | } 24 | 25 | const isAction = (o: ProbablyAction): boolean => { 26 | return !!o?.type 27 | } 28 | 29 | export const createMiddleware = (effects: Effects) => (store: Store) => ( 30 | next: Dispatch, 31 | ) => (action: Action) => { 32 | const effect = effects[action.type] 33 | if (effect) { 34 | const result = effect(action, store) 35 | 36 | if (result instanceof Promise) { 37 | result.then((res) => res && isAction(res) && store.dispatch(res)) 38 | } else if (result && isAction(result)) { 39 | store.dispatch(result) 40 | } 41 | } 42 | 43 | return next(action) 44 | } 45 | -------------------------------------------------------------------------------- /src/components/CardTitle.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Ironbelly Devs 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import React, { useCallback } from 'react' 18 | import { 19 | TouchableOpacity, 20 | StatusBar, 21 | Text, 22 | View, 23 | ViewProps, 24 | } from 'react-native' 25 | import FeatherIcon from 'react-native-vector-icons/Feather' 26 | import { isAndroid } from 'src/common' 27 | import { 28 | useFocusEffect, 29 | NavigationProp, 30 | ParamListBase, 31 | } from '@react-navigation/native' 32 | import { 33 | slightlyTransparent, 34 | styleSheetFactory, 35 | useThemedStyles, 36 | } from 'src/themes' 37 | 38 | type Props = { 39 | title: string 40 | subTitle?: string 41 | navigation: NavigationProp 42 | style?: ViewProps['style'] 43 | } 44 | 45 | const themedStyles = styleSheetFactory(theme => ({ 46 | cardTitle: { 47 | paddingVertical: 16, 48 | justifyContent: 'center', 49 | flexDirection: 'row', 50 | backgroundColor: theme.surface, 51 | }, 52 | container: { 53 | flexDirection: 'column', 54 | }, 55 | chevron: { 56 | position: 'absolute', 57 | paddingLeft: 16, 58 | top: 0, 59 | left: 0, 60 | }, 61 | title: { 62 | fontSize: 18, 63 | textAlign: 'center', 64 | fontWeight: '500', 65 | color: theme.onBackground, 66 | }, 67 | subTitle: { 68 | fontSize: 14, 69 | textAlign: 'center', 70 | color: slightlyTransparent(theme.onBackground), 71 | }, 72 | })) 73 | 74 | export default ({ title, subTitle, navigation, style }: Props) => { 75 | if (isAndroid) { 76 | return null 77 | } 78 | const [styles, theme, themeName] = useThemedStyles(themedStyles) 79 | 80 | useFocusEffect( 81 | useCallback(() => { 82 | if (themeName === 'light') { 83 | StatusBar.setBarStyle('light-content') 84 | } 85 | return () => { 86 | if (themeName === 'light') { 87 | StatusBar.setBarStyle('dark-content') 88 | } 89 | } 90 | }, []), 91 | ) 92 | 93 | return ( 94 | 95 | 96 | { 100 | navigation.goBack() 101 | }}> 102 | 107 | 108 | 109 | {title} 110 | {subTitle && {subTitle}} 111 | 112 | 113 | 114 | ) 115 | } 116 | -------------------------------------------------------------------------------- /src/components/CopyButton.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Ironbelly Devs 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import React from 'react' 18 | import { useDispatch } from 'react-redux' 19 | import Clipboard from '@react-native-clipboard/clipboard' 20 | import { TouchableOpacity, Platform } from 'react-native' 21 | import FontAwesome5Icons from 'react-native-vector-icons/FontAwesome5' 22 | import { Text } from 'src/components/CustomFont' 23 | import { styleSheetFactory, useThemedStyles } from 'src/themes' 24 | 25 | function CopyButton({ 26 | subject, 27 | content, 28 | }: { 29 | subject: string 30 | content: string 31 | }) { 32 | const [styles] = useThemedStyles(themedStyles) 33 | const dispatch = useDispatch() 34 | const copyToClipboard = (s: string, subject: string) => { 35 | return () => { 36 | Clipboard.setString(s) 37 | dispatch({ 38 | type: 'TOAST_SHOW', 39 | text: subject + ' was copied', 40 | }) 41 | } 42 | } 43 | 44 | return ( 45 | 46 | 47 | Copy 48 | 49 | 50 | ) 51 | } 52 | 53 | const themedStyles = styleSheetFactory(theme => ({ 54 | slatepackHeaderCopy: { 55 | fontWeight: Platform.select({ android: '700', ios: '500' }), 56 | color: theme.link, 57 | fontSize: 16, 58 | }, 59 | icon: { 60 | color: theme.link, 61 | }, 62 | })) 63 | 64 | export default CopyButton 65 | -------------------------------------------------------------------------------- /src/components/CopyHeader.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Ironbelly Devs 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import React from 'react' 18 | import { View, Platform } from 'react-native' 19 | import CopyButton from 'src/components/CopyButton' 20 | import { Text } from 'src/components/CustomFont' 21 | import { styleSheetFactory, useThemedStyles } from 'src/themes' 22 | 23 | type Props = { 24 | content?: string 25 | label: string 26 | } 27 | 28 | function CopyHeader({ content, label }: Props) { 29 | const [styles] = useThemedStyles(themedStyles) 30 | return ( 31 | 32 | {label} 33 | {(content && ) || null} 34 | 35 | ) 36 | } 37 | 38 | const themedStyles = styleSheetFactory((theme) => ({ 39 | copyPasteContent: { 40 | flexDirection: 'row', 41 | justifyContent: 'space-between', 42 | marginVertical: 8, 43 | }, 44 | copyPasteContentTitle: { 45 | fontWeight: Platform.select({ android: '700', ios: '500' }), 46 | fontSize: 16, 47 | color: theme.onBackground, 48 | }, 49 | })) 50 | 51 | export default CopyHeader 52 | -------------------------------------------------------------------------------- /src/components/Header.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Ironbelly Devs 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import React, { Component } from 'react' 18 | import styled from 'styled-components/native' 19 | import { Text } from 'src/components/CustomFont' 20 | import HeaderSpan from 'src/components/HeaderSpan' 21 | const Body = styled.View` 22 | height: 69; 23 | width: 100%; 24 | flex-direction: row; 25 | padding: 35px 16px 14px 16px; 26 | align-items: center; 27 | ` 28 | const Left = styled.TouchableOpacity` 29 | flex-direction: row; 30 | align-items: center; 31 | justify-content: flex-end; 32 | ` 33 | const LeftIcon = styled.Image` 34 | height: 20; 35 | width: 20; 36 | ` 37 | const LeftText = styled(Text)` 38 | font-size: 18; 39 | margin-top: 2; 40 | margin-left: 6; 41 | line-height: 20; 42 | ` 43 | const Title = styled.View` 44 | width: 100%; 45 | position: absolute; 46 | top: 30; 47 | left: 16; 48 | align-items: center; 49 | ` 50 | const TitleText = styled(Text)` 51 | font-size: 20; 52 | font-weight: 600; 53 | ` 54 | type Props = { 55 | leftIcon?: number 56 | leftText?: string 57 | leftAction?: () => void 58 | title?: string 59 | } 60 | export default class Header extends Component { 61 | render() { 62 | const { leftIcon, leftText, leftAction, title } = this.props 63 | return ( 64 | 65 | 66 | 67 | 68 | <TitleText>{title}</TitleText> 69 | 70 | 71 | {leftIcon && } 72 | {leftText && {leftText}} 73 | 74 | 75 | 76 | ) 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/components/HeaderSpan.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Ironbelly Devs 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { Platform, Dimensions } from 'react-native' 18 | import colors from 'src/common/colors' 19 | import styled from 'styled-components/native' 20 | 21 | export default styled.View<{ bgColor?: string }>` 22 | background-color: ${(props) => props.bgColor ?? colors.surface}; 23 | height: ${() => 24 | Platform.OS === 'ios' && 25 | Dimensions.get('window').height === 812 && 26 | Dimensions.get('window').width === 375 27 | ? '32px' 28 | : Platform.OS === 'ios' && 29 | Dimensions.get('window').height === 896 && 30 | Dimensions.get('window').width === 414 31 | ? '32px' 32 | : '0'}; 33 | ` 34 | -------------------------------------------------------------------------------- /src/components/InputContentRow.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Ironbelly Devs 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import React from 'react' 18 | import { StyleSheet, View } from 'react-native' 19 | import PasteButton, { SetFunction } from 'src/components/PasteButton' 20 | import ScanQRCodeButton from 'src/components/ScanQRCodeButton' 21 | import { RootStackParamList } from 'src/modules/navigation' 22 | 23 | type Props = { 24 | nextScreen: RootStackParamList['ScanQRCode']['nextScreen'] 25 | label: string 26 | setFunction: SetFunction 27 | nextScreenParams?: RootStackParamList['ScanQRCode']['nextScreenParams'] 28 | } 29 | 30 | function InputContentRow({ 31 | setFunction, 32 | nextScreen, 33 | label, 34 | nextScreenParams, 35 | }: Props) { 36 | return ( 37 | 38 | 39 | 44 | 45 | ) 46 | } 47 | 48 | const styles = StyleSheet.create({ 49 | content: { 50 | flexDirection: 'row', 51 | justifyContent: 'space-around', 52 | marginVertical: 16, 53 | marginHorizontal: 16, 54 | }, 55 | }) 56 | 57 | export default InputContentRow 58 | -------------------------------------------------------------------------------- /src/components/Notice.tsx: -------------------------------------------------------------------------------- 1 | import React, { FunctionComponent } from 'react' 2 | import { Text, TextProps, View } from 'react-native' 3 | import { 4 | slightlyTransparent, 5 | styleSheetFactory, 6 | useThemedStyles, 7 | } from 'src/themes' 8 | const themedStyles = styleSheetFactory((theme) => ({ 9 | container: { 10 | backgroundColor: theme.surface, 11 | marginTop: 16, 12 | borderRadius: 8, 13 | }, 14 | text: { 15 | padding: 8, 16 | fontSize: 16, 17 | lineHeight: 24, 18 | color: slightlyTransparent(theme.onSurface), 19 | textAlign: 'center', 20 | }, 21 | })) 22 | 23 | const Notice: FunctionComponent = ({ children }) => { 24 | const [styles] = useThemedStyles(themedStyles) 25 | return ( 26 | 27 | {children} 28 | 29 | ) 30 | } 31 | 32 | export default Notice 33 | -------------------------------------------------------------------------------- /src/components/NumericInput.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Ironbelly Devs 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import React from 'react' 18 | import { Text, TextInput } from 'src/components/CustomFont' 19 | import { StyleProp, TextStyle, View } from 'react-native' 20 | import { styleSheetFactory, useThemedStyles } from 'src/themes' 21 | type Props = { 22 | units?: string 23 | placeholder?: string 24 | maxLength: number 25 | value: string 26 | onChange: (value: string) => void 27 | autoFocus: boolean 28 | style?: StyleProp 29 | } 30 | 31 | function NumericInput(props: Props) { 32 | const [styles] = useThemedStyles(themedStyles) 33 | const { 34 | units, 35 | maxLength, 36 | style, 37 | onChange, 38 | value, 39 | autoFocus, 40 | placeholder, 41 | } = props 42 | return ( 43 | 44 | {units && {units}} 45 | 54 | {units && {units}} 55 | 56 | ) 57 | } 58 | 59 | const themedStyles = styleSheetFactory((theme) => ({ 60 | layout: { 61 | flexDirection: 'row', 62 | justifyContent: 'flex-start', 63 | flexGrow: 1, 64 | alignItems: 'center', 65 | }, 66 | spacer: { 67 | color: theme.onBackground, 68 | fontSize: 36, 69 | height: 58, 70 | lineHeight: 58, 71 | }, 72 | hiddenSpacer: { 73 | color: theme.background, 74 | fontSize: 36, 75 | height: 58, 76 | lineHeight: 58, 77 | }, 78 | input: { 79 | fontSize: 36, 80 | color: theme.onBackground, 81 | height: 68, 82 | textAlignVertical: 'center', 83 | }, 84 | })) 85 | 86 | export default NumericInput 87 | -------------------------------------------------------------------------------- /src/components/PasteButton.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Ironbelly Devs 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import React from 'react' 18 | import Clipboard from '@react-native-clipboard/clipboard' 19 | import { TouchableOpacity, Platform } from 'react-native' 20 | import FontAwesome5Icons from 'react-native-vector-icons/FontAwesome5' 21 | import { Text } from 'src/components/CustomFont' 22 | import { styleSheetFactory, useThemedStyles } from 'src/themes' 23 | 24 | export type SetFunction = (s: string) => void 25 | 26 | type Props = { 27 | setFunction: SetFunction 28 | } 29 | function PasteButton({ setFunction }: Props) { 30 | const [styles] = useThemedStyles(themedStyles) 31 | const pasteToClipboard = () => { 32 | Clipboard.getString().then(setFunction) 33 | } 34 | 35 | return ( 36 | 37 | 38 | Paste 39 | 40 | 41 | ) 42 | } 43 | 44 | const themedStyles = styleSheetFactory(theme => ({ 45 | button: { 46 | fontWeight: Platform.select({ android: '700', ios: '500' }), 47 | color: theme.link, 48 | fontSize: 16, 49 | }, 50 | icon: { 51 | color: theme.link, 52 | }, 53 | })) 54 | 55 | export default PasteButton 56 | -------------------------------------------------------------------------------- /src/components/ScanQRCodeButton.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Ironbelly Devs 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import React from 'react' 18 | import { TouchableOpacity, Platform } from 'react-native' 19 | import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons' 20 | 21 | import { Text } from 'src/components/CustomFont' 22 | import { NavigationProp, useNavigation } from '@react-navigation/native' 23 | import { RootStackParamList } from 'src/modules/navigation' 24 | import { styleSheetFactory, useThemedStyles } from 'src/themes' 25 | 26 | function ScanQRCodeButton({ 27 | nextScreen, 28 | nextScreenParams, 29 | label, 30 | }: { 31 | nextScreen: RootStackParamList['ScanQRCode']['nextScreen'] 32 | nextScreenParams?: RootStackParamList[RootStackParamList['ScanQRCode']['nextScreen']] 33 | label: string 34 | }) { 35 | const [styles] = useThemedStyles(themedStyles) 36 | const navigation = useNavigation>() 37 | const scan = () => { 38 | navigation.navigate('ScanQRCode', { 39 | nextScreen, 40 | nextScreenParams, 41 | label, 42 | }) 43 | } 44 | 45 | return ( 46 | 47 | 48 | Scan QR{' '} 49 | 54 | 55 | 56 | ) 57 | } 58 | 59 | const themedStyles = styleSheetFactory(theme => ({ 60 | slatepackHeaderCopy: { 61 | fontWeight: Platform.select({ android: '700', ios: '500' }), 62 | color: theme.link, 63 | fontSize: 16, 64 | }, 65 | icon: { 66 | color: theme.link, 67 | }, 68 | })) 69 | 70 | export default ScanQRCodeButton 71 | -------------------------------------------------------------------------------- /src/components/SectionTitle.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Ironbelly Devs 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import React from 'react' 18 | import { View, Platform } from 'react-native' 19 | import { Text } from 'src/components/CustomFont' 20 | import { styleSheetFactory, useThemedStyles } from 'src/themes' 21 | 22 | type Props = { 23 | title: string 24 | } 25 | 26 | function SectionTitle({ title }: Props) { 27 | const [styles] = useThemedStyles(themedStyles) 28 | return ( 29 | 30 | {title} 31 | 32 | ) 33 | } 34 | 35 | const themedStyles = styleSheetFactory((theme) => ({ 36 | container: { 37 | flexDirection: 'row', 38 | justifyContent: 'space-between', 39 | marginVertical: 8, 40 | }, 41 | title: { 42 | fontWeight: Platform.select({ android: '700', ios: '700' }), 43 | fontSize: 16, 44 | color: theme.onBackground, 45 | }, 46 | })) 47 | 48 | export default SectionTitle 49 | -------------------------------------------------------------------------------- /src/components/ShareButton.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Ironbelly Devs 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // Been used previously for sharing files and not in use right now. 18 | // Can be used for sharing Slatepack messages if Copy/QR would not be enough 19 | import React from 'react' 20 | import { TouchableOpacity, Platform } from 'react-native' 21 | import FontAwesome5Icons from 'react-native-vector-icons/FontAwesome5' 22 | import { Text } from 'src/components/CustomFont' 23 | import { styleSheetFactory, useThemedStyles } from 'src/themes' 24 | 25 | function ShareButton({ onClick }: { onClick: () => void }) { 26 | const [styles] = useThemedStyles(themedStyles) 27 | return ( 28 | 29 | 30 | Share 31 | 32 | 33 | ) 34 | } 35 | 36 | const themedStyles = styleSheetFactory((theme) => ({ 37 | slatepackHeaderCopy: { 38 | fontWeight: Platform.select({ android: '700', ios: '500' }), 39 | color: theme.link, 40 | fontSize: 16, 41 | }, 42 | icon: { 43 | color: theme.link, 44 | }, 45 | })) 46 | 47 | export default ShareButton 48 | -------------------------------------------------------------------------------- /src/components/ShareRow.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Ironbelly Devs 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import React from 'react' 18 | import { View } from 'react-native' 19 | import CopyButton from 'src/components/CopyButton' 20 | import ShowQRCodeButton from 'src/components/ShowQRCodeButton' 21 | import { styleSheetFactory, useThemedStyles } from 'src/themes' 22 | 23 | type Props = { 24 | content?: string 25 | label: string 26 | } 27 | 28 | function ShareRow({ content, label }: Props) { 29 | const [styles] = useThemedStyles(themedStyles) 30 | if (!content) { 31 | return null 32 | } 33 | return ( 34 | 35 | 36 | 37 | 38 | ) 39 | } 40 | 41 | const themedStyles = styleSheetFactory(() => ({ 42 | content: { 43 | flexDirection: 'row', 44 | justifyContent: 'space-around', 45 | marginVertical: 16, 46 | }, 47 | })) 48 | 49 | export default ShareRow 50 | -------------------------------------------------------------------------------- /src/components/ShowQRCodeButton.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Ironbelly Devs 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import React from 'react' 18 | import { TouchableOpacity, Platform } from 'react-native' 19 | import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons' 20 | 21 | import { Text } from 'src/components/CustomFont' 22 | import { useNavigation } from '@react-navigation/native' 23 | import { styleSheetFactory, useThemedStyles } from 'src/themes' 24 | 25 | function ShowQRCodeButton({ 26 | label, 27 | content, 28 | }: { 29 | label: string 30 | content: string 31 | }) { 32 | const [styles] = useThemedStyles(themedStyles) 33 | const navigation = useNavigation() 34 | const show = (content: string, label: string) => { 35 | return () => { 36 | navigation.navigate('ShowQRCode', { 37 | content, 38 | label, 39 | }) 40 | } 41 | } 42 | 43 | return ( 44 | 45 | 46 | Show QR{' '} 47 | 48 | 49 | 50 | ) 51 | } 52 | 53 | const themedStyles = styleSheetFactory((theme) => ({ 54 | slatepackHeaderCopy: { 55 | fontWeight: Platform.select({ android: '700', ios: '500' }), 56 | color: theme.link, 57 | fontSize: 16, 58 | }, 59 | icon: { 60 | color: theme.link, 61 | }, 62 | })) 63 | 64 | export default ShowQRCodeButton 65 | -------------------------------------------------------------------------------- /src/components/Textarea.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Ironbelly Devs 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import React from 'react' 18 | import ReactNative, { TextInputProps, View, ViewProps } from 'react-native' 19 | import { TextInput, Text } from 'src/components/CustomFont' 20 | import { styleSheetFactory, useThemedStyles } from 'src/themes' 21 | type Props = TextInputProps & { 22 | title?: string; 23 | getRef?: (instance: ReactNative.TextInput | null) => void; 24 | containerStyle?: ViewProps['style']; 25 | }; 26 | 27 | function Textarea(props: Props) { 28 | const [styles] = useThemedStyles(themedStyles) 29 | const { title, getRef, containerStyle, style, ...passProps } = props 30 | return ( 31 | 32 | {title && {title}} 33 | 39 | 40 | ) 41 | } 42 | 43 | const themedStyles = styleSheetFactory(theme => ({ 44 | input: { 45 | paddingTop: 16, 46 | paddingBottom: 16, 47 | paddingHorizontal: 16, 48 | backgroundColor: theme.surface, 49 | color: theme.onSurface, 50 | borderRadius: 8, 51 | fontSize: 18, 52 | fontWeight: '400', 53 | flex: 1, 54 | }, 55 | title: { 56 | fontWeight: 500, 57 | fontSize: 16, 58 | marginBottom: 8, 59 | }, 60 | })) 61 | 62 | export default Textarea 63 | -------------------------------------------------------------------------------- /src/documents/legal-disclaimer-ios.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Ironbelly Devs 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | export default ` 18 | # Warranties and Limitation of Liability 19 | 20 | This app is provided on "AS-IS" basis without warranty of any kind. In no event will the author be liable for any loss or damages arising from or related to your use of this app, including but not limited to loss of or inability to access or transact data, profit or cryptocurrency. 21 | 22 | Without limiting the generality of the foregoing, the author takes no responsibility for and will not be liable for any financial or other loss or damage arising from or related to the use of this app, including but not limited to any of the following: 23 | 24 | * Financial loss due to Wallet access being "Brute-forced". 25 | * Financial loss due to data loss. 26 | * Financial loss due to forgotten mnemonics(paper keys) or passwords. 27 | * Financial loss due to inability to transact. 28 | * Financial loss due to errors calculating network fees. 29 | * Financial loss due to incorrectly constructed transactions or mistyped addresses. 30 | 31 | # Your Compliance with Applicable Laws 32 | 33 | You represent and warrant that you are using this app in accordance with applicable law, and not for any purpose not in compliance with applicable law, including but not limited to illegal gambling, fraud, money laundering or terrorist activities. 34 | 35 | # Changes to this app 36 | 37 | The author may add or remove functions or features of this app. You can stop using this app at any time. 38 | 39 | # Responsibility for Mnemonics(Paper Keys), Passwords and Catastrophic Impact of Their Loss 40 | 41 | If you use this app to create a Wallet, the software will use an algorithm to generate a random 24-word phrase as a seed to a BIP32 hierarchical wallet. This 24-word phrase is called a mnemonic(paper key) and if reproduced exactly stores all the information needed to recover your Wallet if access through a password or other authentication means is lost or otherwise not available. 42 | 43 | The author does not store, have access to, or have any way or means of recovering mnemonics(paper keys), passwords or private keys. 44 | 45 | It is your responsibility to keep your mnemonic(paper key) secure. You should not provide it to anyone, including the author. 46 | 47 | If you permanently forget or lose your mnemonic(paper key), you will NEVER be able to recover any cryptocurrency in your Wallet, and you will suffer a complete, irrecoverable and catastrophic loss of all Digital Assets in your Wallet. 48 | 49 | It is your responsibility to safeguard and retain your mnemonic(paper key). The author has no responsibility and will not be liable for any loss or damage you suffer from the loss or misappropriation of your mnemonic(paper key). 50 | ` 51 | -------------------------------------------------------------------------------- /src/documents/receive-from-another-person.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Ironbelly Devs 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | export default ` 18 | # Step 0: Find a Sender 19 | 20 | If you want to receive some Grin, you need to find someone who wants to send some Grin first. We will call this person "Sender". 21 | 22 | # Step 1: Sender initiate the transaction 23 | 24 | On the main screen Sender needs to press "Send", then enter an amount, choose fee, enter an optional message, choose "Share as a file" and then share dialog would appear automatically. The app has generated a partial transaction file, which needs to be signed by a recipient (you). Sender now needs to share this file in any convinient (better secure) way, so you can open it on your phone. 25 | 26 | # Step 2: Receive a partial transaction 27 | 28 | When you've received the file from Sender, open it, press on Share icon and choose "Copy to Ironbelly". 29 | 30 | This will open the app, where you could check the amount and accept the transaction. If accepted, Ironbelly would sign the file and ask you to share it back with Sender. Do that and sit tight, we are not done yet! 31 | 32 | # Step 3: Finalizing and posting to the chain 33 | 34 | When Sender have received the file from you, she would open it, press on Share icon and choose "Copy to Ironbelly". 35 | 36 | This will open the app, where Sender could check and post the transaction. If posted, it would take a couple of minutes until it appear in the chain. 37 | 38 | # Step 4: Wait 10 confirmations 39 | 40 | After the transaction has appeared in the chain it is still very fresh and Ironbelly would wait for 10 confirmations (10 - 20min) until it can be used. After that the funds are officially yours! 41 | # 42 | ` 43 | -------------------------------------------------------------------------------- /src/mocks.ts: -------------------------------------------------------------------------------- 1 | import moment from 'moment' 2 | export const mockRustTransaction = ( 3 | id: number, 4 | type: string, 5 | amountCredited: string, 6 | amountDebited: string, 7 | fee: string, 8 | txSlateId: string, 9 | ) => ({ 10 | amount_credited: amountCredited, 11 | amount_debited: amountDebited, 12 | confirmation_ts: moment().format(), 13 | confirmed: true, 14 | creation_ts: moment().format(), 15 | fee, 16 | id, 17 | kernel_excess: null, 18 | kernel_lookup_min_height: null, 19 | num_inputs: 0, 20 | num_outputs: 1, 21 | parent_key_id: '0200000000000000000000000000000000', 22 | payment_proof: null, 23 | reverted_after: null, 24 | stored_tx: null, 25 | ttl_cutoff_height: null, 26 | tx_slate_id: txSlateId, 27 | tx_type: type, // 'TxReceived', 28 | }) 29 | 30 | export const mockedRustTransactions: { [key: string]: unknown } = { 31 | slateId1: mockRustTransaction( 32 | 0, 33 | 'TxReceived', 34 | '123438749', 35 | '0', 36 | '0', 37 | 'slateId1', 38 | ), 39 | '6ef39b6d-ce3c-4a22-a536-cea395dc4b62': mockRustTransaction( 40 | 1, 41 | 'TxSent', 42 | '0', 43 | '123438749', 44 | '8000000', 45 | '6ef39b6d-ce3c-4a22-a536-cea395dc4b62', 46 | ), 47 | } 48 | -------------------------------------------------------------------------------- /src/modules/app.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Ironbelly Devs 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { Epic, combineEpics } from 'redux-observable' 18 | import { filter, mapTo } from 'rxjs/operators' 19 | import { Action } from 'src/common/types' 20 | import { RootState } from 'src/common/redux' 21 | import { of, interval } from 'rxjs' 22 | 23 | const REFRESH_TXS_INTERVAL = 10 * 1000 // 10 sec 24 | 25 | export type State = { 26 | legalAccepted: boolean 27 | } 28 | export const initialState: State = { 29 | legalAccepted: false, 30 | } 31 | 32 | export const appReducer = ( 33 | state: State = initialState, 34 | action: Action, 35 | ): State => { 36 | switch (action.type) { 37 | case 'ACCEPT_LEGAL': 38 | return { 39 | ...state, 40 | legalAccepted: action.value, 41 | } 42 | default: 43 | return state 44 | } 45 | } 46 | 47 | const refreshTxsPeriodicallyEpic: Epic = ( 48 | _, 49 | state$, 50 | ) => 51 | interval(REFRESH_TXS_INTERVAL).pipe( 52 | filter( 53 | () => 54 | state$.value.wallet.isOpened && 55 | !state$.value.wallet.walletScan.inProgress, 56 | ), 57 | mapTo({ 58 | type: 'TX_LIST_REQUEST', 59 | showLoader: false, 60 | refreshFromNode: true, 61 | }), 62 | ) 63 | 64 | const checkBiometryEpic: Epic = () => { 65 | return of({ 66 | type: 'CHECK_BIOMETRY_REQUEST', 67 | }) 68 | } 69 | 70 | export const appEpic: Epic = combineEpics( 71 | checkBiometryEpic, 72 | refreshTxsPeriodicallyEpic, 73 | ) 74 | -------------------------------------------------------------------------------- /src/modules/balance.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Ironbelly Devs 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { mapRustBalance } from 'src/common' 18 | import { Action, Balance } from 'src/common/types' 19 | export type State = Balance 20 | const initialState: State = { 21 | amountAwaitingConfirmation: '0', 22 | amountCurrentlySpendable: '0', 23 | amountImmature: '0', 24 | amountLocked: '0', 25 | lastConfirmedHeight: '0', 26 | minimumConfirmations: '0', 27 | total: '0', 28 | } 29 | export const reducer = (state: State = initialState, action: Action): State => { 30 | switch (action.type) { 31 | case 'TX_LIST_SUCCESS': 32 | return { ...state, ...mapRustBalance(action.balance) } 33 | 34 | default: 35 | return state 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/modules/currency-rates.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Ironbelly Devs 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { Action, Store, currencyRatesRequestAction } from 'src/common/types' 18 | import { currencyList } from 'src/common' 19 | export type State = { 20 | rates: Record 21 | inProgress: boolean 22 | lastUpdated: number 23 | disabled: boolean 24 | } 25 | export const initialState: State = { 26 | rates: {}, 27 | inProgress: false, 28 | lastUpdated: 0, 29 | disabled: false, 30 | } 31 | export const reducer = (state: State = initialState, action: Action): State => { 32 | switch (action.type) { 33 | case 'CURRENCY_RATES_REQUEST': 34 | return { ...state, inProgress: true } 35 | 36 | case 'CURRENCY_RATES_SUCCESS': 37 | return { 38 | ...state, 39 | rates: action.rates.grin, 40 | inProgress: false, 41 | lastUpdated: Date.now(), 42 | } 43 | case 'CURRENCY_RATES_TOGGLE': 44 | return { 45 | ...state, 46 | disabled: !state.disabled, 47 | } 48 | 49 | case 'CURRENCY_RATES_FAILURE': 50 | return { ...state, inProgress: false } 51 | 52 | default: 53 | return state 54 | } 55 | } 56 | export const sideEffects = { 57 | ['CURRENCY_RATES_REQUEST']: async ( 58 | _action: currencyRatesRequestAction, 59 | store: Store, 60 | ) => { 61 | try { 62 | const rates = await fetch( 63 | `https://api.coingecko.com/api/v3/simple/price?ids=grin&vs_currencies=${currencyList 64 | .map((c) => c.code) 65 | .join(',')}`, 66 | ).then((data) => data.json()) 67 | store.dispatch({ 68 | type: 'CURRENCY_RATES_SUCCESS', 69 | rates, 70 | }) 71 | } catch (error) { 72 | store.dispatch({ 73 | type: 'CURRENCY_RATES_FAILURE', 74 | message: error.message, 75 | }) 76 | } 77 | }, 78 | } 79 | -------------------------------------------------------------------------------- /src/modules/toaster.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Ironbelly Devs 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { Action } from 'src/common/types' 18 | export type State = { 19 | text: string 20 | duration: number 21 | } 22 | const initialState: State = { 23 | text: '', 24 | duration: 2000, 25 | } 26 | export const reducer = (state: State = initialState, action: Action): State => { 27 | switch (action.type) { 28 | case 'TOAST_SHOW': 29 | return { ...state, ...action } 30 | 31 | case 'TOAST_CLEAR': { 32 | return { ...initialState } 33 | } 34 | 35 | default: 36 | return state 37 | } 38 | } 39 | export const sideEffects = {} 40 | -------------------------------------------------------------------------------- /src/modules/tx/receive.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Ironbelly Devs 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { PayloadAction, createSlice } from '@reduxjs/toolkit' 18 | import { catchError, map, mergeMap } from 'rxjs/operators' 19 | import { from, EMPTY } from 'rxjs' 20 | import { RootState } from 'src/common/redux' 21 | import { Epic, combineEpics, ofType } from 'redux-observable' 22 | import { Action, valueof } from 'src/common/types' 23 | import WalletBridge from 'src/bridges/wallet' 24 | 25 | export type State = { 26 | address: string | undefined 27 | } 28 | export const initialState: State = { 29 | address: undefined, 30 | } 31 | 32 | const txReceiveSlice = createSlice({ 33 | name: 'txReceive', 34 | initialState, 35 | reducers: { 36 | setAddress: (state, action: PayloadAction) => { 37 | state.address = action.payload 38 | }, 39 | }, 40 | }) 41 | 42 | export const txReceiveReducer = txReceiveSlice.reducer 43 | export const txReceiveActions = txReceiveSlice.actions 44 | export type TxReceiveActions = valueof 45 | 46 | export const startHttpListenEpic: Epic = (action$) => 47 | action$.pipe( 48 | ofType('SET_WALLET_OPEN'), 49 | mergeMap(() => 50 | from(WalletBridge.startListenWithHttp('0.0.0.0:3415')).pipe( 51 | map( 52 | (address: string) => txReceiveActions.setAddress(address) as Action, 53 | ), 54 | catchError((error) => { 55 | console.log(error) 56 | return EMPTY 57 | }), 58 | ), 59 | ), 60 | ) 61 | 62 | export const stopHttpListenEpic: Epic = (action$) => 63 | action$.pipe( 64 | ofType('CLOSE_WALLET', 'WALLET_DESTROY_SUCCESS'), 65 | mergeMap(async () => { 66 | await WalletBridge.stopListenWithHttp() 67 | return txReceiveActions.setAddress(undefined) as Action 68 | }), 69 | ) 70 | 71 | export const txReceiveEpic: Epic = combineEpics( 72 | startHttpListenEpic, 73 | stopHttpListenEpic, 74 | ) 75 | 76 | export const grinAddressSelector = (state: RootState) => state.txReceive.address 77 | -------------------------------------------------------------------------------- /src/screens/License.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Ironbelly Devs 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import React from 'react' 18 | import { ScrollView } from 'react-native' 19 | import { Text } from 'src/components/CustomFont' 20 | import { NavigationProps } from 'src/common/types' 21 | import { styleSheetFactory, useThemedStyles } from 'src/themes' 22 | 23 | type Props = NavigationProps<'License'> 24 | 25 | const License = ({ route }: Props) => { 26 | const [styles] = useThemedStyles(themedStyles) 27 | const { licenseText } = route?.params 28 | return ( 29 | 33 | {licenseText} 34 | 35 | ) 36 | } 37 | 38 | const themedStyles = styleSheetFactory((theme) => ({ 39 | scrollView: { 40 | flexGrow: 1, 41 | padding: 16, 42 | }, 43 | licence: { 44 | paddingBottom: 32, 45 | color: theme.onBackground, 46 | }, 47 | })) 48 | 49 | export default License 50 | -------------------------------------------------------------------------------- /src/screens/Licenses.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Ironbelly Devs 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import React from 'react' 18 | import IonicIcon from 'react-native-vector-icons/Ionicons' 19 | import { Text } from 'src/components/CustomFont' 20 | import licenses from '../../licenses.json' 21 | import { FlatList, TouchableOpacity, StyleSheet } from 'react-native' 22 | import { useNavigation } from '@react-navigation/native' 23 | import { 24 | slightlyTransparent, 25 | styleSheetFactory, 26 | useThemedStyles, 27 | } from 'src/themes' 28 | 29 | // import { NavigationProps } from 'src/common/types' 30 | // type Props = NavigationProps<'Licenses'> 31 | 32 | type ItemProps = {title: string; licenceId: number}; 33 | 34 | const Item = ({ title, licenceId }: ItemProps) => { 35 | const [styles] = useThemedStyles(themedStyles) 36 | const navigation = useNavigation() 37 | const onPress = (licenceId: number) => { 38 | const licenseText = (licenses.licenses as Record)[ 39 | licenceId 40 | ] 41 | return () => navigation.navigate('License', { licenseText }) 42 | } 43 | return ( 44 | 45 | 46 | {title} 47 | 48 | 53 | 54 | ) 55 | } 56 | 57 | function renderItem({ item }: {item: string}) { 58 | const licenceId = (licenses.packages as Record)[item] 59 | return 60 | } 61 | 62 | const Licenses = () => { 63 | const [styles] = useThemedStyles(themedStyles) 64 | const packages = Object.keys(licenses.packages) 65 | packages.sort() 66 | return ( 67 | item} 74 | /> 75 | ) 76 | } 77 | 78 | const themedStyles = styleSheetFactory(theme => ({ 79 | container: { 80 | paddingHorizontal: 16, 81 | }, 82 | item: { 83 | height: 48, 84 | flexDirection: 'row', 85 | alignItems: 'center', 86 | }, 87 | chevron: { 88 | color: slightlyTransparent(theme.onBackground), 89 | lineHeight: 30, 90 | }, 91 | itemTitle: { 92 | flex: 1, 93 | color: theme.onBackground, 94 | }, 95 | })) 96 | 97 | export default Licenses 98 | -------------------------------------------------------------------------------- /src/screens/ScanQRCode.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Ironbelly Devs 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import React, { useEffect, useState } from 'react' 18 | import { ActivityIndicator, StyleSheet, Text, View } from 'react-native' 19 | import colors from 'src/common/colors' 20 | import { NavigationProps } from 'src/common/types' 21 | import CardTitle from 'src/components/CardTitle' 22 | import { BarCodeScanner, PermissionStatus } from 'expo-barcode-scanner' 23 | 24 | type Props = NavigationProps<'ScanQRCode'> 25 | 26 | function ScanQRCode({ route, navigation }: Props) { 27 | const { label, nextScreen, nextScreenParams } = route.params 28 | const [hasPermission, setHasPermission] = useState(null) 29 | const [scanned, setScanned] = useState(false) 30 | useEffect(() => { 31 | ;(async () => { 32 | const { status } = await BarCodeScanner.requestPermissionsAsync() 33 | setHasPermission(status === PermissionStatus.GRANTED) 34 | })() 35 | }, []) 36 | 37 | const handleBarCodeScanned = ({ data }: { data: string }) => { 38 | setScanned(true) 39 | navigation.navigate(nextScreen, { ...nextScreenParams, qrContent: data }) 40 | } 41 | 42 | const inner = () => { 43 | if (hasPermission === null) { 44 | return 45 | } 46 | if (hasPermission === false) { 47 | return No access to camera 48 | } 49 | return ( 50 | 53 | ) 54 | } 55 | 56 | return ( 57 | <> 58 | 59 | {inner()} 60 | 61 | ) 62 | } 63 | 64 | const styles = StyleSheet.create({ 65 | container: { 66 | flex: 1, 67 | alignItems: 'center', 68 | justifyContent: 'center', 69 | }, 70 | viewFinder: { 71 | ...StyleSheet.absoluteFillObject, 72 | }, 73 | status: { 74 | fontSize: 24, 75 | textAlign: 'center', 76 | }, 77 | }) 78 | 79 | export default ScanQRCode 80 | -------------------------------------------------------------------------------- /src/screens/Settings/Support.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Ironbelly Devs 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import React, { useState } from 'react' 18 | import { Linking, ScrollView, View } from 'react-native' 19 | import { SafeAreaView } from 'react-native-safe-area-context' 20 | import { Button, Link, Text } from 'src/components/CustomFont' 21 | import { Currency, Dispatch, NavigationProps } from 'src/common/types' 22 | import { RootState } from 'src/common/redux' 23 | import { State as CurrencyRatesState } from 'src/modules/currency-rates' 24 | import { 25 | slightlyTransparent, 26 | styleSheetFactory, 27 | useThemedStyles, 28 | } from 'src/themes' 29 | type DispatchProps = { 30 | currency: Currency 31 | requestCurrencyRates: () => void 32 | setCurrency: (currency: Currency) => void 33 | currencyRates: CurrencyRatesState 34 | } 35 | 36 | type Props = NavigationProps<'SettingsSupport'> & DispatchProps 37 | 38 | export default function CurrencyList(props: Props) { 39 | const [styles] = useThemedStyles(themedStyles) 40 | return ( 41 | 42 | Can I cancel transaction? 43 | 44 | If the transaction has not been sent to the network yet, you can just 45 | swipe it left to cancel. Otherwise it's impossible to revert it! 46 | 47 | 48 | While depositing funds to exchange, I've forgotten to specify a memo. 49 | Can you help? 50 | 51 | 52 | Unfortunately no. Please contact the exchange support, only they could 53 | help you in this situation. In any case, DO NOT repair or destroy the 54 | wallet in Settings. In this case you would loose history of the 55 | transactions and the data, which could help exchange to identify your 56 | transactions. 57 | 58 | Still have questions? 59 | 60 | You can visit {' '} 61 | or in 62 | Telegram. 63 | 64 | 65 | ) 66 | } 67 | 68 | const themedStyles = styleSheetFactory(theme => ({ 69 | container: { 70 | flexGrow: 1, 71 | backgroundColor: theme.background, 72 | padding: 16, 73 | }, 74 | header: { 75 | fontWeight: '600', 76 | fontSize: 24, 77 | color: theme.onBackground, 78 | }, 79 | text: { 80 | paddingTop: 8, 81 | paddingBottom: 32, 82 | fontSize: 17, 83 | color: theme.onBackground, 84 | lineHeight: 24, 85 | }, 86 | smallText: { 87 | paddingTop: 8, 88 | paddingBottom: 32, 89 | fontSize: 14, 90 | textAlign: 'center', 91 | color: slightlyTransparent(theme.onSurface), 92 | }, 93 | })) 94 | -------------------------------------------------------------------------------- /src/screens/ShowQRCode.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Ironbelly Devs 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import React from 'react' 18 | import colors from 'src/common/colors' 19 | import { View, StyleSheet, Dimensions } from 'react-native' 20 | import QRCode from 'react-native-qrcode-svg' 21 | import { NavigationProps } from 'src/common/types' 22 | import CardTitle from 'src/components/CardTitle' 23 | 24 | type Props = NavigationProps<'ShowQRCode'> 25 | 26 | function ScanQRCode({ route, navigation }: Props) { 27 | const { label, content } = route.params 28 | const width = Dimensions.get('window').width - 32 29 | return ( 30 | <> 31 | 32 | 33 | 34 | 35 | 36 | ) 37 | } 38 | 39 | const styles = StyleSheet.create({ 40 | container: { 41 | flex: 1, 42 | backgroundColor: colors.white, 43 | alignItems: 'center', 44 | justifyContent: 'center', 45 | }, 46 | label: { 47 | fontSize: 24, 48 | }, 49 | }) 50 | 51 | export default ScanQRCode 52 | -------------------------------------------------------------------------------- /src/screens/TxIncompleteSend/TxIncompleteSend.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Ironbelly Devs 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import React, { useEffect } from 'react' 18 | import BigNumber from 'bignumber.js' 19 | import { View } from 'react-native' 20 | import { Text } from 'src/components/CustomFont' 21 | import CardTitle from 'src/components/CardTitle' 22 | import { Tx } from 'src/common/types' 23 | import { NavigationProps } from 'src/common/types' 24 | import SlateCreated from 'src/screens/TxIncompleteSend/SlateCreated' 25 | import SlateNotCreated from 'src/screens/TxIncompleteSend/SlateNotCreated' 26 | import { hrGrin } from 'src/common' 27 | import { styleSheetFactory, useThemedStyles } from 'src/themes' 28 | 29 | interface OwnProps { 30 | tx: Tx 31 | } 32 | 33 | type Props = NavigationProps<'TxIncompleteSend'> & OwnProps 34 | 35 | const TxIncompleteSend = ({ navigation, route }: Props) => { 36 | console.log(route) 37 | const [styles] = useThemedStyles(themedStyles) 38 | const tx = route?.params?.tx 39 | const title = tx 40 | ? `Sending ${hrGrin(new BigNumber(tx.amount).abs())}` 41 | : `Send` 42 | const subTitle = tx && `fee: ${hrGrin(tx.fee)}` 43 | 44 | useEffect(() => { 45 | navigation.setParams({ title, subTitle }) 46 | }, [title, subTitle]) 47 | 48 | return ( 49 | <> 50 | 56 | 57 | {tx?.slateId ? ( 58 | 59 | ) : ( 60 | 61 | )} 62 | 63 | 64 | ) 65 | } 66 | 67 | export function androidHeaderTitle( 68 | params: NavigationProps<'TxIncompleteSend'>['route']['params'], 69 | ) { 70 | const [styles] = useThemedStyles(themedStyles) 71 | return ( 72 | 73 | {params?.title} 74 | {params?.subTitle && ( 75 | {params?.subTitle} 76 | )} 77 | 78 | ) 79 | } 80 | 81 | const themedStyles = styleSheetFactory(theme => ({ 82 | androidHeaderTitle: { 83 | fontSize: 21, 84 | color: theme.onBackground, 85 | }, 86 | androidHeaderSubTitle: { 87 | color: theme.onBackground, 88 | fontSize: 12, 89 | }, 90 | container: { 91 | flexGrow: 1, 92 | }, 93 | })) 94 | 95 | export default TxIncompleteSend 96 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@tsconfig/react-native/tsconfig.json", 3 | "compilerOptions": { 4 | "target": "esnext", 5 | "module": "commonjs", 6 | "lib": ["es6", "dom"], 7 | "allowJs": true, 8 | "jsx": "react-native", 9 | "noEmit": true, 10 | "isolatedModules": true, 11 | "strict": true, 12 | "moduleResolution": "node", 13 | "baseUrl": ".", 14 | "allowSyntheticDefaultImports": true, 15 | "esModuleInterop": true, 16 | "resolveJsonModule": true, 17 | "skipLibCheck": true 18 | }, 19 | "include": ["src"], 20 | "exclude": [ 21 | "node_modules", 22 | "babel.config.js", 23 | "metro.config.js", 24 | "jest.config.js" 25 | ] 26 | } 27 | --------------------------------------------------------------------------------