diff --git a/.circleci/config.yml b/.circleci/config.yml
deleted file mode 100644
index 1a9e3af..0000000
--- a/.circleci/config.yml
+++ /dev/null
@@ -1,61 +0,0 @@
-# .circleci/config.yml
-
-version: 2.1
-
-orbs:
- node: circleci/node@4.0.0
-
-jobs:
- build_testnet:
- macos:
- xcode: "12.1" # Specify the Xcode version to use
- working_directory: /Users/distiller/project
- environment:
- FL_OUTPUT_DIR: output
- FASTLANE_LANE: beta
- steps:
- - checkout
-
- - node/install:
- node-version: "10.16.3"
- install-yarn: true
- # Download and cache dependencies
- # - restore_cache:
- # keys:
- # - v1-dependencies-{{ checksum "package.json" }}
- # # fallback to using the latest cache if no exact match is found
- # - v1-dependencies-
-
- - run: cp env/default.json.example env/default.json
-
- - run: yarn cache clean && yarn install --network-concurrency 1
-
- # - save_cache:
- # paths:
- # - node_modules
- # key: v1-dependencies-{{ checksum "package.json" }}
-
- - run: cd ios && bundle install
-
- - run: cd ios && bundle exec pod install
-
- - run:
- name: Fastlane
- command: cd ios && export BUILD_NUMBER=${CIRCLE_BUILD_NUM} && export VERSION_NUMBER=4.2 && bundle exec fastlane $FASTLANE_LANE
-
- - store_artifacts:
- path: ios/output
- - store_test_results:
- path: ios/output/scan
-
-workflows:
- version: 2
- build_testnet_and_mainnet:
- jobs:
- - build_testnet:
- filters:
- branches:
- only:
- - main
- - dev
- - feature_postlaunch_optin
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 51a8c0f..1dd6295 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,21 @@ All notable changes to this project will be documented in this file.
The changelog format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
+## [v1.3.0][v1.3.0] - 1-Nov-2021
+
+### Fixed
+- Fix invalid accounts generated when importing private key instead mnemonics [#232](https://github.com/symbol/mobile-wallet/issues/232)
+- Fix node list should not be hardcoded [#235](https://github.com/symbol/mobile-wallet/issues/235)
+- Fix not able to send transaction with encrypted message [#236](https://github.com/symbol/mobile-wallet/issues/236)
+- Hide news feed [#242](https://github.com/symbol/mobile-wallet/issues/242)
+- Update explorer and faucet url. [#252](https://github.com/symbol/mobile-wallet/pull/252)
+
+### Added
+- Add Multisig multi-level support [#223](https://github.com/symbol/mobile-wallet/issues/223)
+- Add harvesting verification if account importance is above zero [#234](https://github.com/symbol/mobile-wallet/issues/234)
+- Display current account importance in Harvesting Page [#239](https://github.com/symbol/mobile-wallet/issues/239)
+- Add Jenkins pipeline setup [#247](https://github.com/symbol/mobile-wallet/pull/247)
+
## [v1.2][v1.2] - 6-Oct-2021
### Fixed
@@ -11,4 +26,5 @@ The changelog format is based on [Keep a Changelog](https://keepachangelog.com/e
- Fix harvesting status [#134](https://github.com/symbol/mobile-wallet/issues/134)
- Minor translations update.
-[v1.2]: https://github.com/symbol/mobile-wallet/releases/tag/1.2
\ No newline at end of file
+[v1.2]: https://github.com/symbol/mobile-wallet/releases/tag/1.2
+[v1.3.0]: https://github.com/symbol/mobile-wallet/releases/tag/1.3.0
diff --git a/Jenkinsfile b/Jenkinsfile
new file mode 100644
index 0000000..1fef9fd
--- /dev/null
+++ b/Jenkinsfile
@@ -0,0 +1,113 @@
+pipeline {
+ agent { label 'macos' }
+
+ options {
+ skipStagesAfterUnstable()
+ }
+
+ parameters {
+ string(name: 'VERSION_NUMBER', defaultValue: '4.4.2', description: 'Version Number')
+ string(name: 'BUILD_NUMBER', defaultValue: '59', description: 'Build Number')
+ string(name: 'DEPLOY_BETA_BRANCH', defaultValue: 'dev', description: 'Deploy Beta Branch Name')
+ choice(
+ name: 'TARGET_OS',
+ choices: ['All', 'IOS', 'Android'],
+ description: 'Target Environment'
+ )
+ }
+
+ environment {
+ RUNNING_ON_CI = 'true'
+ VERSION_NUMBER = "${params.VERSION_NUMBER}"
+ BUILD_NUMBER = "${params.BUILD_NUMBER}"
+ DEPLOY_BETA_BRANCH = "${params.DEPLOY_BETA_BRANCH}"
+ TARGET_OS = "${params.TARGET_OS}"
+ MATCH_GIT_BASIC_AUTHORIZATION = credentials('GHUB_CREDS_SECRET')
+ MATCH_PASSWORD = credentials('MATCH_PASSWORD')
+ FASTLANE_KEYCHAIN = 'fastlane.keychain'
+ FASTLANE_KEYCHAIN_PASSWORD = credentials("FASTLANE_KEYCHAIN_PASSWORD")
+ APP_STORE_CONNECT_API_KEY_KEY_ID = credentials("APP_STORE_CONNECT_API_KEY_KEY_ID")
+ APP_STORE_CONNECT_API_KEY_ISSUER_ID = credentials("APP_STORE_CONNECT_API_KEY_ISSUER_ID")
+ APP_STORE_CONNECT_API_KEY_KEY = credentials("APP_STORE_CONNECT_API_KEY_KEY")
+ }
+
+ stages {
+ stage('Install') {
+ steps {
+ withCredentials([file(credentialsId: 'ENV_FILE_ZIP', variable: 'default_env_zip')]) {
+ sh "cp $default_env_zip default_whitelist_zip.zip"
+ }
+ script {
+ unzip zipFile: 'default_whitelist_zip.zip', quiet: true
+ def jsonWhitelist = readJSON file: 'default_whitelist.json'
+ def json = readJSON file: 'env/default.json.example'
+ json.optInWhiteList = jsonWhitelist.optInWhiteList
+ writeJSON file: 'env/default.json', json: json
+ }
+ sh "rm -f default_whitelist_zip.zip && rm -f default_whitelist.json"
+ // Run yarn install for the dependencies
+ sh "yarn cache clean && yarn install --network-concurrency 1"
+ sh "npx jetify" // for android
+ }
+ }
+
+ stage('Build') {
+ parallel {
+ stage('Build - IOS') {
+ when {
+ expression {
+ BRANCH_NAME == DEPLOY_BETA_BRANCH && (TARGET_OS == 'All' || TARGET_OS == 'IOS')
+ }
+ }
+ steps {
+ sh "cd ios && bundle install"
+ sh "cd ios && bundle exec pod install"
+ }
+ }
+ stage('Build - Android') {
+ when {
+ expression {
+ TARGET_OS == 'All' || TARGET_OS == 'Android'
+ }
+ }
+ steps {
+ // copy key.properties and copy keystore file
+ withCredentials([file(credentialsId: 'ANDROID_KEY_PROPERTIES', variable: 'android_key_properties'),
+ file(credentialsId: 'ANDROID_KEY_PROPERTIES_STORE_FILE', variable: 'release_keystore')]) {
+ sh 'cp $android_key_properties ./android/app/key.properties'
+ sh 'cp $release_keystore ./android/app/release.keystore'
+ sh "cd android && ./gradlew assembleProdRelease -PBUILD_NUMBER=${BUILD_NUMBER}"
+ sh "echo 'Build completed and .apk file is generated. Version:${VERSION_NUMBER}, Build:${BUILD_NUMBER}'"
+ }
+ }
+ }
+ }
+ }
+
+ stage ('Test') {
+ steps {
+ sh "echo 'Currently there are no tests to run!'"
+ }
+ }
+
+ // deploy to testnet
+ stage ('Deploy IOS - Alpha version') {
+ when {
+ expression {
+ BRANCH_NAME == DEPLOY_BETA_BRANCH && (TARGET_OS == 'All' || TARGET_OS == 'IOS')
+ }
+ }
+ steps {
+ sh 'cd ios && export APP_STORE_CONNECT_API_KEY_KEY_ID=${APP_STORE_CONNECT_API_KEY_KEY_ID} && export APP_STORE_CONNECT_API_KEY_ISSUER_ID=${APP_STORE_CONNECT_API_KEY_ISSUER_ID} && export APP_STORE_CONNECT_API_KEY_KEY=${APP_STORE_CONNECT_API_KEY_KEY} && export FASTLANE_KEYCHAIN=${FASTLANE_KEYCHAIN} && export FASTLANE_KEYCHAIN_PASSWORD=${FASTLANE_KEYCHAIN_PASSWORD} && export RUNNING_ON_CI=${RUNNING_ON_CI} && export BUILD_NUMBER=${BUILD_NUMBER} && export VERSION_NUMBER=${VERSION_NUMBER} && bundle exec fastlane beta'
+ sh "echo 'Deployed to TestFlight. Version:${VERSION_NUMBER}, Build:${BUILD_NUMBER}'"
+ }
+ }
+ }
+ post {
+ always {
+ archiveArtifacts artifacts: 'android/app/build/outputs/apk/prod/release/*.apk', allowEmptyArchive: true
+ archiveArtifacts artifacts: 'ios/output/*.ipa', allowEmptyArchive: true
+ cleanWs()
+ }
+ }
+}
diff --git a/README.md b/README.md
index e1dc8b0..74f18c4 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,6 @@
Official Android and iOS applications for NEM2(a.k.a Catapult).
-[![CircleCI](https://circleci.com/gh/hatioin/nem-catapult-wallet.svg?style=svg&circle-token=8a16be5d725e06b1380904c8024e6622b6193e86)](https://circleci.com/gh/hatioin/nem-catapult-wallet)
## Getting Started
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 33fcc9a..04d1565 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -102,14 +102,14 @@ def enableProguardInReleaseBuilds = false
* The preferred build flavor of JavaScriptCore.
*
* For example, to use the international variant, you can use:
- * `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
+ * `def jscFlavor = 'org.webkit:android-jsc:+''
*
* The international variant includes ICU i18n library and necessary data
* allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
* give correct results when using with locales other than en-US. Note that
* this variant is about 6MiB larger per architecture than default.
*/
-def jscFlavor = 'org.webkit:android-jsc:+'
+def jscFlavor = 'org.webkit:android-jsc-intl:+'
/**
* Whether to enable the Hermes VM.
@@ -119,6 +119,16 @@ def jscFlavor = 'org.webkit:android-jsc:+'
* and the benefits of using Hermes will therefore be sharply reduced.
*/
def enableHermes = project.ext.react.get("enableHermes", false);
+def keystoreProperties = new Properties()
+def keyPropertiesFilePath = 'key.properties'
+def keystorePropertiesFile = file(keyPropertiesFilePath)
+if (keystorePropertiesFile.exists()) {
+ println "${keyPropertiesFilePath} file exists."
+ keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
+ println "storeFile is ${keystoreProperties['storeFile']}"
+} else {
+ println "${keyPropertiesFilePath} file not found!"
+}
android {
compileSdkVersion rootProject.ext.compileSdkVersion
@@ -144,12 +154,12 @@ android {
}
}
signingConfigs {
- debug {
- storeFile file('debug.keystore')
- storePassword 'android'
- keyAlias 'androiddebugkey'
- keyPassword 'android'
- }
+ config {
+ storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
+ storePassword keystoreProperties['storePassword']
+ keyAlias keystoreProperties['keyAlias']
+ keyPassword keystoreProperties['keyPassword']
+ }
}
flavorDimensions "version"
productFlavors {
@@ -166,12 +176,12 @@ android {
}
buildTypes {
debug {
- signingConfig signingConfigs.debug
+ signingConfig signingConfigs.config
}
release {
// Caution! In production, you need to generate your own keystore file.
// see https://facebook.github.io/react-native/docs/signed-apk-android.
- signingConfig signingConfigs.debug
+ signingConfig signingConfigs.config
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
}
diff --git a/android/app/key.properties b/android/app/key.properties
new file mode 100644
index 0000000..e41c5ee
--- /dev/null
+++ b/android/app/key.properties
@@ -0,0 +1,4 @@
+storeFile=debug.keystore
+storePassword=android
+keyAlias=androiddebugkey
+keyPassword=android
\ No newline at end of file
diff --git a/android/gradle.properties b/android/gradle.properties
index 027ef9d..cbae841 100644
--- a/android/gradle.properties
+++ b/android/gradle.properties
@@ -19,3 +19,4 @@
android.useAndroidX=true
android.enableJetifier=true
+org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
\ No newline at end of file
diff --git a/env/default.json.example b/env/default.json.example
index 0aafdcb..caeb433 100644
--- a/env/default.json.example
+++ b/env/default.json.example
@@ -1,12 +1,15 @@
{
"sessionTimeoutInSeconds": 10,
"marketCurrencyName": "nem",
- "newsURL": "https://nemflash.io/feed",
"explorerURL": {
- "testnet": "http://explorer.testnet.symboldev.network/",
- "mainnet": "http://explorer.symbolblockchain.io/"
+ "testnet": "https://testnet.symbol.fyi/",
+ "mainnet": "https://symbol.fyi/"
},
- "faucetURL": "http://faucet.testnet.symboldev.network/",
+ "statisticsServiceURL": {
+ "testnet": "https://testnet.symbol.services/",
+ "mainnet": "https://symbol.services/"
+ },
+ "faucetURL": "https://testnet.symbol.tools/",
"aboutURL": "https://nem.io",
"currencies": {
"USD": "usd",
@@ -29,15 +32,6 @@
"http://hugealice2.nem.ninja",
"http://hachi.nem.ninja",
"http://alice2.nem.ninja"
- ],
- "nodes": [
- "http://ngl-api-501.symbolblockchain.io:3000",
- "http://ngl-api-601.symbolblockchain.io:3000",
- "http://ngl-api-401.symbolblockchain.io:3000",
- "http://ngl-api-001.symbolblockchain.io:3000",
- "http://ngl-api-101.symbolblockchain.io:3000",
- "http://ngl-api-301.symbolblockchain.io:3000",
- "http://ngl-api-201.symbolblockchain.io:3000"
]
},
"testnet": {
@@ -45,15 +39,6 @@
"http://hugetestalice2.nem.ninja",
"http://hugetestalice.nem.ninja",
"http://medalice2.nem.ninja"
- ],
- "nodes": [
- "http://ngl-dual-001.testnet.symboldev.network:3000",
- "http://ngl-dual-101.testnet.symboldev.network:3000",
- "http://ngl-dual-201.testnet.symboldev.network:3000",
- "http://ngl-dual-301.testnet.symboldev.network:3000",
- "http://ngl-dual-401.testnet.symboldev.network:3000",
- "http://ngl-dual-501.testnet.symboldev.network:3000",
- "http://ngl-dual-601.testnet.symboldev.network:3000"
]
}
},
diff --git a/ios/Gemfile.lock b/ios/Gemfile.lock
index 5553d4d..a343385 100644
--- a/ios/Gemfile.lock
+++ b/ios/Gemfile.lock
@@ -12,6 +12,7 @@ GEM
algoliasearch (1.27.5)
httpclient (~> 2.8, >= 2.8.3)
json (>= 1.5.1)
+ artifactory (3.0.15)
atomos (0.1.3)
aws-eventstream (1.1.0)
aws-partitions (1.358.0)
@@ -93,9 +94,10 @@ GEM
faraday_middleware (1.0.0)
faraday (~> 1.0)
fastimage (2.2.0)
- fastlane (2.156.1)
+ fastlane (2.181.0)
CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.3, < 3.0.0)
+ artifactory (~> 3.0)
aws-sdk-s3 (~> 1.0)
babosa (>= 1.0.3, < 2.0.0)
bundler (>= 1.12.0, < 3.0.0)
@@ -116,6 +118,7 @@ GEM
jwt (>= 2.1.0, < 3)
mini_magick (>= 4.9.4, < 5.0.0)
multipart-post (~> 2.0.0)
+ naturally (~> 2.2)
plist (>= 3.1.0, < 4.0.0)
rubyzip (>= 2.0.0, < 3.0.0)
security (= 0.1.3)
@@ -240,4 +243,4 @@ DEPENDENCIES
fastlane
BUNDLED WITH
- 2.1.2
+ 2.2.28
diff --git a/ios/NEMCatapultWallet/Info.plist b/ios/NEMCatapultWallet/Info.plist
index 7d6072e..1e505b8 100644
--- a/ios/NEMCatapultWallet/Info.plist
+++ b/ios/NEMCatapultWallet/Info.plist
@@ -21,11 +21,11 @@
CFBundlePackageType
APPL
CFBundleShortVersionString
- 1
+ 4.4.2
CFBundleSignature
????
CFBundleVersion
- 1
+ 58
LSRequiresIPhoneOS
NSAppTransportSecurity
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index 3f023e8..1305a0f 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -498,7 +498,7 @@ SPEC CHECKSUMS:
React-RCTVibration: a49a1f42bf8f5acf1c3e297097517c6b3af377ad
ReactCommon: 198c7c8d3591f975e5431bec1b0b3b581aa1c5dd
ReactNativeNavigation: aefc8debafb4a374575adafb44a3352b9d5b618a
- RealmJS: 0f2a5db56ff20f2feab9543f57e348575e40b508
+ RealmJS: d1afbd12be13d7b455327adceaf2a2aea5f22e1a
rn-fetch-blob: f525a73a78df9ed5d35e67ea65e79d53c15255bc
RNBackgroundFetch: 8dbb63141792f1473e863a0797ffbd5d987af2fc
RNCAsyncStorage: b03032fdbdb725bea0bd9e5ec5a7272865ae7398
diff --git a/ios/SymbolWallet.xcodeproj/project.pbxproj b/ios/SymbolWallet.xcodeproj/project.pbxproj
index b9e0a07..84e5df8 100644
--- a/ios/SymbolWallet.xcodeproj/project.pbxproj
+++ b/ios/SymbolWallet.xcodeproj/project.pbxproj
@@ -371,7 +371,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = 8;
+ CURRENT_PROJECT_VERSION = 58;
DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = W594P93ZB8;
ENABLE_TESTABILITY = NO;
@@ -418,7 +418,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = 16;
+ CURRENT_PROJECT_VERSION = 58;
DEVELOPMENT_TEAM = W594P93ZB8;
GCC_NO_COMMON_BLOCKS = NO;
HEADER_SEARCH_PATHS = (
@@ -450,7 +450,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = com.nemgrouplimited.symbolwallet;
PRODUCT_NAME = Symbol;
- PROVISIONING_PROFILE_SPECIFIER = "match AppStore com.nemgrouplimited.symbolwallet";
+ PROVISIONING_PROFILE_SPECIFIER = "match AppStore com.nemgrouplimited.symbolwallet 1634392395";
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
};
diff --git a/ios/fastlane/Appfile b/ios/fastlane/Appfile
index c89465b..6b46927 100644
--- a/ios/fastlane/Appfile
+++ b/ios/fastlane/Appfile
@@ -1,5 +1,4 @@
app_identifier("com.nemgrouplimited.symbolwallet") # The bundle identifier of your app
-apple_id("acarrera@peersyst.com") # Your Apple email address
itc_team_id("122014636") # App Store Connect Team ID
team_id("W594P93ZB8") # Developer Portal Team ID
diff --git a/ios/fastlane/Fastfile b/ios/fastlane/Fastfile
index 2f3e0f8..0bc2a69 100644
--- a/ios/fastlane/Fastfile
+++ b/ios/fastlane/Fastfile
@@ -15,10 +15,18 @@
default_platform(:ios)
+def ensure_temp_keychain(name, password)
+ delete_keychain(
+ name: name
+ ) if File.exist? File.expand_path("~/Library/Keychains/#{name}-db")
+ create_keychain(
+ name: name,
+ password: password,
+ unlock: true,
+ timeout: false
+ )
+end
platform :ios do
- before_all do
- setup_circle_ci
- end
desc "Push a new beta build to TestFlight"
lane :beta do |options|
increment_build_number(
@@ -29,8 +37,17 @@ platform :ios do
version_number: ENV["VERSION_NUMBER"],
xcodeproj: "SymbolWallet.xcodeproj"
)
+ ensure_temp_keychain(ENV["FASTLANE_KEYCHAIN"], ENV["FASTLANE_KEYCHAIN_PASSWORD"])
+ setup_jenkins(force: true, keychain_path: ENV["FASTLANE_KEYCHAIN"], keychain_password: ENV["FASTLANE_KEYCHAIN_PASSWORD"], add_keychain_to_search_list: true)
+ #, set_default_keychain: true
+ app_store_connect_api_key(
+ key_id: ENV['APP_STORE_CONNECT_API_KEY_KEY_ID'],
+ issuer_id: ENV['APP_STORE_CONNECT_API_KEY_ISSUER_ID'],
+ key_content: ENV['APP_STORE_CONNECT_API_KEY_KEY'],
+ is_key_content_base64: true
+ )
match(type: "appstore")
build_app(workspace: "SymbolWallet.xcworkspace", scheme: "Symbol")
upload_to_testflight
end
-end
+end
\ No newline at end of file
diff --git a/ios/fastlane/Matchfile b/ios/fastlane/Matchfile
index ea3f118..95e7043 100644
--- a/ios/fastlane/Matchfile
+++ b/ios/fastlane/Matchfile
@@ -1,11 +1,11 @@
-git_url("git@github.com:Peersyst/symbol-wallet-credentials.git")
+git_url("https://github.com/symbol/mobile-wallet-credentials.git")
+git_branch("master")
storage_mode("git")
type("appstore") # The default type, can be: appstore, adhoc, enterprise or development
app_identifier("com.nemgrouplimited.symbolwallet") # The bundle identifier of your app
-username("acarrera@peersyst.com") # Your Apple email address
# app_identifier(["tools.fastlane.app", "tools.fastlane.app2"])
# username("user@fastlane.tools") # Your Apple Developer Portal username
diff --git a/package-lock.json b/package-lock.json
index 0dbb7f3..f7f8961 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "symbol-mobile-wallet",
- "version": "1.2",
+ "version": "1.3.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index 865b664..cfb475a 100644
--- a/package.json
+++ b/package.json
@@ -1,11 +1,11 @@
{
"name": "symbol-mobile-wallet",
- "version": "1.2",
+ "version": "1.3.0",
"private": true,
"scripts": {
"git-info": "echo export default \"{ version: '$(git describe --tags `git rev-list --tags --max-count=1`)' };\" > src/shared/_git_commit.js",
"android": "react-native run-android",
- "ios": "react-native run-ios",
+ "ios": "react-native run-ios --scheme Symbol",
"start": "yarn git-info; react-native start",
"dev": "react-native start",
"reconnect": "adb reverse tcp:8081 tcp:8081",
@@ -110,7 +110,7 @@
"symbol-paper-wallets": "^1.0.2",
"symbol-post-launch-optin-module": "1.0.1",
"symbol-qr-library": "0.14.1-alpha-202103081047",
- "symbol-sdk": "1.0.0",
+ "symbol-sdk": "1.0.2-alpha-202108061451",
"timers-browserify": "^1.0.1",
"tls-browserify": "^0.2.2",
"tty-browserify": "0.0.0",
diff --git a/src/App.js b/src/App.js
index 41c7a53..eae2d9e 100644
--- a/src/App.js
+++ b/src/App.js
@@ -48,7 +48,6 @@ const initStore = async () => {
await store.dispatchAction({ type: 'network/initState' });
} catch {}
// store.dispatchAction({ type: 'market/loadMarketData' });
- store.dispatchAction({ type: 'news/loadNews' });
store.dispatchAction({ type: 'addressBook/loadAddressBook' });
};
diff --git a/src/components/atoms/Warning/index.js b/src/components/atoms/Warning/index.js
index 0ee6dd6..76f6184 100644
--- a/src/components/atoms/Warning/index.js
+++ b/src/components/atoms/Warning/index.js
@@ -9,23 +9,17 @@ import { View, Alert } from 'react-native';
import translate from "@src/locales/i18n";
type Props = {
- onIgnore: () => void,
hideWarning: () => void,
message: string,
- okButtonText: string,
};
const Warning = (props: Props) => {
- const { onIgnore, message, okButtonText, hideWarning } = props;
+ const { message, hideWarning } = props;
const invalidAlert = () => {
Alert.alert(
translate('Shared.Warning.warning'),
message,
[
- {
- text: okButtonText,
- onPress: () => onIgnore(),
- },
{
text: translate('Shared.Warning.cancelModalButton'),
onPress: () => hideWarning(),
diff --git a/src/components/controls/ReadMoreLink.js b/src/components/controls/ReadMoreLink.js
new file mode 100644
index 0000000..4ba9a97
--- /dev/null
+++ b/src/components/controls/ReadMoreLink.js
@@ -0,0 +1,56 @@
+import React, { Component } from 'react';
+import { TouchableOpacity, StyleSheet, Linking } from 'react-native';
+import { Text, Section, Col, Row } from '@src/components';
+import GlobalStyles from '../../styles/GlobalStyles';
+import translate from '@src/locales/i18n';
+
+const styles = StyleSheet.create({
+ link: {
+ fontSize: 12,
+ color: GlobalStyles.color.BLUE,
+ textDecorationLine: 'underline',
+ },
+});
+interface Props {
+ url: string;
+ title: string;
+}
+export default class ReadMoreLink extends Component {
+ onPress(url: string) {
+ Linking.openURL(url);
+ }
+
+ render = () => {
+ const title = this.props.title;
+ if (title) {
+ return (
+
+
+ {title}
+
+
+
+ this.onPress(this.props.url)}>
+
+ {translate('news.readMore')}
+
+
+
+
+
+ );
+ } else {
+ return (
+
+
+ this.onPress(this.props.url)}>
+
+ {translate('news.readMore')}
+
+
+
+
+ );
+ }
+ };
+}
diff --git a/src/components/molecules/BasicAlert.js b/src/components/molecules/BasicAlert.js
new file mode 100644
index 0000000..0455974
--- /dev/null
+++ b/src/components/molecules/BasicAlert.js
@@ -0,0 +1,25 @@
+ import React from 'react';
+
+ import { View, Alert } from 'react-native';
+
+ type Action = {
+ text: string,
+ onPress: () => void
+ }
+
+ type Props = {
+ title: string,
+ message: string,
+ actions: Action[]
+ };
+
+ export default BasicAlert = (props: Props) => {
+ const { title, message, actions } = props;
+ return (
+
+ {
+ Alert.alert(title,message,actions,{ cancelable: true })
+ }
+
+ )
+ };
\ No newline at end of file
diff --git a/src/components/molecules/MultisigFilter.js b/src/components/molecules/MultisigFilter.js
index 22b43cf..53db80a 100644
--- a/src/components/molecules/MultisigFilter.js
+++ b/src/components/molecules/MultisigFilter.js
@@ -10,6 +10,9 @@ type Props = {
};
class MultisigFilter extends Component {
+ formatAddress = address => {
+ return address.substring(0, 6) + '...' + address.substring(address.length - 3, address.length);
+ };
render() {
const { cosignatoryOf, selectedAccountAddress, selected, onSelect, ...rest } = this.props;
const allMultisigAccounts = [
@@ -20,7 +23,7 @@ class MultisigFilter extends Component {
})),
];
- return ;
+ return ;
}
}
diff --git a/src/components/molecules/index.js b/src/components/molecules/index.js
index e82197c..cd10467 100644
--- a/src/components/molecules/index.js
+++ b/src/components/molecules/index.js
@@ -1,3 +1,4 @@
export TitleBar from './TitleBar';
export OptionsMenu from './OptionsMenu';
-export EmptyListMessage from './EmptyListMessage';
\ No newline at end of file
+export EmptyListMessage from './EmptyListMessage';
+export BasicAlert from './BasicAlert';
\ No newline at end of file
diff --git a/src/components/organisms/New.js b/src/components/organisms/New.js
deleted file mode 100644
index bca3c9a..0000000
--- a/src/components/organisms/New.js
+++ /dev/null
@@ -1,100 +0,0 @@
-import React, { Component } from 'react';
-import { View, Image, StyleSheet, Linking, TouchableOpacity } from 'react-native';
-import { Text, Row, Col, } from '@src/components';
-import GlobalStyles from '@src/styles/GlobalStyles';
-import TextLink from '@src/components/atoms/TextLink';
-import Card from '@src/components/atoms/Card';
-import translate from "@src/locales/i18n";
-
-const styles = StyleSheet.create({
- root: {
- width: '100%',
- borderRadius: 6,
- backgroundColor: GlobalStyles.color.WHITE
- },
- content: {
- marginTop:0
- },
- title: {
- fontFamily: 'NotoSans-SemiBold',
- fontWeight: '600',
- fontSize: 14,
- lineHeight: 20,
- marginBottom: 6
- },
- date: {
- fontSize: 12,
- },
- source: {
- fontSize: 12,
- fontStyle: 'italic'
- },
- body: {
- fontFamily: 'NotoSans-Light',
- fontSize: 12,
- },
- link: {
- fontSize: 12,
- color: GlobalStyles.color.BLUE,
- textDecorationLine: 'underline'
- },
-});
-
-type Props = {
- title: string,
- body: string,
- contentSnippet: string,
- url: string,
- publicationDate: string,
- creator: string,
-};
-
-export default class New extends Component {
- onPress() {
- Linking.openURL(this.props.url);
- }
-
- render() {
- return (
- this.onPress(this.props.url)} style={styles.root}>
-
-
-
- {this.props.title}
-
-
-
-
- {this.props.publicationDate}
-
-
- blog.nem.io
-
-
-
-
-
-
- {this.props.body}
-
-
-
-
-
- this.onPress()}>
-
- {translate('news.readMore')}
-
-
-
-
- {/*
- {this.props.title}
-
-
- {this.props.publicationDate}
- */}
-
- );
- }
-}
diff --git a/src/components/organisms/transaction/AggregateTransaction.js b/src/components/organisms/transaction/AggregateTransaction.js
index aee9100..41da9cb 100644
--- a/src/components/organisms/transaction/AggregateTransaction.js
+++ b/src/components/organisms/transaction/AggregateTransaction.js
@@ -11,19 +11,21 @@ import { showPasscode } from '@src/utils/passcode';
import translate from '@src/locales/i18n';
import { getFinanceBotPublicKeys } from '@src/config/environment';
import Icon from '@src/components/controls/Icon';
-import { TransactionType, UInt64, AggregateTransaction as SdkAggregateTransaction, TransactionHttp } from 'symbol-sdk';
+import { TransactionType, UInt64, AggregateTransaction as SdkAggregateTransaction } from 'symbol-sdk';
import TransactionService from '@src/services/TransactionService';
+import _ from 'lodash';
+import { Router } from '@src/Router';
type Props = {
transaction: AggregateTransactionModel,
};
class AggregateTransaction extends BaseTransactionItem {
- state: {
+ state = {
fullTransaction: null,
};
- componentDidMount() {
+ async componentDidMount() {
const { selectedNode, transaction } = this.props;
TransactionService.getTransaction(transaction.hash, selectedNode).then(async tx => {
this.setState({ fullTransaction: tx });
@@ -65,18 +67,39 @@ class AggregateTransaction extends BaseTransactionItem {
showPasscode(this.props.componentId, () => {
const { transaction } = this.props;
store.dispatchAction({ type: 'transfer/signAggregateBonded', payload: transaction }).then(_ => {
+ this.showCosignatureMessage(translate('notification.newCosignatureAdded'));
store.dispatchAction({ type: 'transaction/changeFilters', payload: {} });
});
});
}
+ // check if the transaction needs to be Signed from current signer
needsSignature = () => {
if (this.isPostLaunchOptIn()) return false;
- const { transaction, selectedAccount, isMultisig } = this.props;
+ const { transaction, selectedAccount, isMultisig, cosignatoryOf } = this.props;
const accountPubKey = getPublicKeyFromPrivateKey(selectedAccount.privateKey);
- return !isMultisig && transaction.cosignaturePublicKeys.indexOf(accountPubKey) === -1 && transaction.status !== 'confirmed';
+ const cosignerAddresses = transaction.innerTransactions.map((t) => t.signerAddress);
+ const cosignRequired = cosignerAddresses.find((c) => {
+ if (c) {
+ return (
+ (cosignatoryOf && cosignatoryOf.some((address) => address === c))
+ );
+ }
+ return false;
+ });
+ return !isMultisig && (((transaction.cosignaturePublicKeys.indexOf(accountPubKey) === -1 && transaction.status !== 'confirmed'))|| (this.hasMissSignatures() && cosignRequired!==undefined));
};
+ // check if the transaction misses cosignatories
+ hasMissSignatures=()=> {
+ const {transaction}= this.props;
+ return (
+ transaction?.transactionInfo != null &&
+ transaction?.transactionInfo.merkleComponentHash !== undefined &&
+ transaction?.transactionInfo.merkleComponentHash.startsWith('000000000000')
+ );
+ }
+
renderAction = () => {
if (this.needsSignature()) {
return (
@@ -87,6 +110,14 @@ class AggregateTransaction extends BaseTransactionItem {
}
};
+ // show notification for transaction signing
+ showCosignatureMessage = (message: string) => {
+ Router.showMessage({
+ message: message,
+ type: 'success',
+ });
+ };
+
renderDetails = () => {
const { transaction, isLoading, isMultisig } = this.props;
const table = { innerTxs: transaction.innerTransactions.length };
@@ -123,4 +154,5 @@ export default connect(state => ({
isMultisig: state.account.isMultisig,
network: state.network.selectedNetwork.type,
address: state.account.selectedAccountAddress,
+ cosignatoryOf: state.account.cosignatoryOf,
}))(AggregateTransaction);
diff --git a/src/components/settings/SettingsNodeSelector.js b/src/components/settings/SettingsNodeSelector.js
index cfd815c..3ce86d2 100644
--- a/src/components/settings/SettingsNodeSelector.js
+++ b/src/components/settings/SettingsNodeSelector.js
@@ -6,7 +6,6 @@ import PopupModal from '@src/components/molecules/PopupModal';
import {Dropdown, Text, Section, Row, ManagerHandler, Input, Button} from '@src/components';
import { connect } from 'react-redux';
import store from '@src/store';
-import { getNodes } from '@src/config/environment';
import GlobalStyles from '@src/styles/GlobalStyles';
import ConfirmModal from "@src/components/molecules/ConfirmModal";
@@ -147,16 +146,15 @@ class SettingsNodeSelector extends Component {
}
render = () => {
+ const { isModalOpen, error, loading, selectedTab, isConfirmModalOpen } = this.state;
+ const { selectedNode, selectedNetwork, testnetNodes, mainnetNodes } = this.props;
+
const nodes = {
- mainnet: getNodes('mainnet').map(node => ({ value: node, label: node })),
- testnet: getNodes('testnet').map(node => ({ value: node, label: node })),
+ mainnet: mainnetNodes.map(node => ({ value: node, label: node })),
+ testnet: testnetNodes.map(node => ({ value: node, label: node })),
custom: [],
};
- const { isModalOpen, error, loading, selectedTab, isConfirmModalOpen } = this.state;
- const { selectedNode, selectedNetwork } = this.props;
- const list = nodes[selectedTab];
-
return (
'' + index + 'nodes'}
/>
@@ -270,4 +268,6 @@ class SettingsNodeSelector extends Component {
export default connect(state => ({
selectedNode: state.network.selectedNetwork ? state.network.selectedNetwork.node : '',
selectedNetwork: state.network.selectedNetwork ? state.network.selectedNetwork.type : '',
+ testnetNodes: state.network.testnetNodes || [],
+ mainnetNodes: state.network.mainnetNodes || [],
}))(SettingsNodeSelector);
diff --git a/src/config/environment.js b/src/config/environment.js
index 966d4a3..c2ccb77 100644
--- a/src/config/environment.js
+++ b/src/config/environment.js
@@ -5,8 +5,8 @@
import {
sessionTimeoutInSeconds,
marketCurrencyName,
- newsURL,
explorerURL,
+ statisticsServiceURL,
faucetURL,
aboutURL,
currencies,
@@ -22,9 +22,9 @@ import {
optInWhiteList,
nglFinanceBot,
} from 'react-native-env-json';
-import { NetworkType } from "symbol-sdk";
+import { NetworkType } from 'symbol-sdk';
import { languageNames } from '@src/locales/i18n';
-import type {AppNetworkType} from "@src/storage/models/NetworkModel";
+import type { AppNetworkType } from '@src/storage/models/NetworkModel';
// Session timeout
const getSessionTimeoutInMillis = (): number => {
@@ -36,16 +36,16 @@ const getMarketCurrencyLabel = (): string => {
return marketCurrencyName;
};
-// News URL
-const getNewsURL = (): string => {
- return newsURL;
-};
-
// Explorer URL
const getExplorerURL = (network: AppNetworkType): string => {
return explorerURL[network];
};
+// Statistics Service URL
+const getStatisticsServiceURL = (network: AppNetworkType): string => {
+ return statisticsServiceURL[network];
+};
+
// Explorer URL
const getFaucetUrl = (): string => {
return faucetURL;
@@ -115,14 +115,13 @@ const isCustomNode = (nodeType: string): boolean => {
// Network info
const getNetworkInfo = (nodeType: string): Object => {
- console.log(networks)
const networkConfig = networks[nodeType];
// use mainnet as fallback config
return networkConfig !== undefined ? networkConfig : networks.MAINNET;
};
const getOptinEnv = (): string => {
- return optinEnv
+ return optinEnv;
};
const getNISNodes = (network: 'mainnet' | 'testnet' = 'testnet'): string[] => {
@@ -133,10 +132,6 @@ const getDefaultNetworkType = (): NetworkType => {
return defaultNetworkType;
};
-const getNodes = (network: 'mainnet' | 'testnet' = 'testnet'): string[] => {
- return networks[network].nodes;
-};
-
const getNativeMosaicId = (): string[] => {
return nativeMosaicId;
};
@@ -149,11 +144,16 @@ const getFinanceBotPublicKeys = (network: 'mainnnet' | 'testnet' = 'testnet'): s
return nglFinanceBot[network];
};
+const getHarvestingPrerequisitesUrl = (): string => {
+ const prerequisitesURL = 'https://docs.symbolplatform.com/guides/harvesting/activating-delegated-harvesting-wallet.html#prerequisites';
+ return prerequisitesURL;
+};
+
export {
getSessionTimeoutInMillis,
getMarketCurrencyLabel,
- getNewsURL,
getExplorerURL,
+ getStatisticsServiceURL,
getFaucetUrl,
getAboutURL,
getCurrencyList,
@@ -173,8 +173,8 @@ export {
getOptinEnv,
getNISNodes,
getDefaultNetworkType,
- getNodes,
getNativeMosaicId,
getWhitelistedPublicKeys,
getFinanceBotPublicKeys,
+ getHarvestingPrerequisitesUrl,
};
diff --git a/src/config/index.js b/src/config/index.js
index 8a20294..ad6bd22 100644
--- a/src/config/index.js
+++ b/src/config/index.js
@@ -1,16 +1,6 @@
export * as environment from './environment';
export const menuItems = [
- {
- text: 'menu.news',
- iconName: 'news',
- name: 'news',
- },
- {
- text: 'menu.mosaics',
- iconName: 'mosaics',
- name: 'mosaics',
- },
{
text: 'menu.home',
iconName: 'home',
@@ -21,6 +11,11 @@ export const menuItems = [
iconName: 'history',
name: 'history',
},
+ {
+ text: 'menu.mosaics',
+ iconName: 'mosaics',
+ name: 'mosaics',
+ },
{
text: 'menu.harvest',
iconName: 'harvest',
diff --git a/src/locales/translations/en.json b/src/locales/translations/en.json
index ba04e15..cf36cb7 100644
--- a/src/locales/translations/en.json
+++ b/src/locales/translations/en.json
@@ -35,7 +35,6 @@
"title": "Import Wallet",
"content": "Import your Wallet by entering your mnemonics in order.",
"button": "Import",
- "ignoreWarning": "Ignore Warning",
"cancelModalButton": "Cancel",
"error": {
"invalidMnemonic": "Invalid Mnemonic",
@@ -480,7 +479,11 @@
"optInTitle": "Post-launch Opt-in",
"optInDescription": "Press here to access the dashboard",
"pendingSignatureTitle": "Pending signature",
- "pendingSignatureDescription": "There is a transaction pending awaiting signature"
+ "pendingSignatureDescription": "There is a transaction pending awaiting signature",
+ "alertTitle":"Error",
+ "alertActionCreateWallet": "Create New",
+ "alertActionCancel": "Cancel",
+ "alertInvalidMnemonicMessage": "This profile does not have a valid mnemonic phrase. Please create a new profile and transfer your funds as soon as possible."
},
"mosaics": {
"title": "Mosaics"
@@ -524,9 +527,11 @@
"INPROGRESS_DEACTIVATION": "Deactivation in progress",
"harvetingIntroTitle": "Start harvesting to earn a block rewards",
"minBalanceRequirement": "Insufficient balance, the account needs to hold at least %{balance} to start delegated harvesting.",
+ "nonZeroImportanceRequirement": "Your account cannot start delegated harvesting while importance is equal to 0. Importance recalculation might take up to 12h.",
"KEYS_LINKED": "Keys linked",
"viewLinkedKeys": "View Linked Keys",
- "linkedNode": "Linked Node"
+ "linkedNode": "Linked Node",
+ "Importance": "Importance score"
},
"sidebar": {
"seed": "Seed account",
@@ -579,6 +584,7 @@
"newUnconfirmed": "New unconfirmed transaction!",
"newConfirmed": "New confirmed transaction!",
"newAggregate": "New aggregate transaction!",
+ "newCosignatureAdded":"Cosignature received!",
"noMosaicPresent": "There is no mosaic '%{mosaicName}' present in this account"
},
"addressBook": {
diff --git a/src/locales/translations/es.json b/src/locales/translations/es.json
index a0eaf15..c7c9420 100644
--- a/src/locales/translations/es.json
+++ b/src/locales/translations/es.json
@@ -35,7 +35,6 @@
"title": "Importar Wallet",
"content": "Importa tu Wallet Symbol al ingresar las palabras nemónicas en el orden correcto.",
"button": "Importar",
- "ignoreWarning": "Ignorar la advertencia",
"cancelModalButton": "Cancelar",
"error": {
"invalidMnemonic": "Nemónica inválida",
@@ -471,7 +470,11 @@
"optInTitle": "Opt-in",
"optInDescription": "El proceso de opt-in post lanzamiento se abirá pronto. Por favor comprueba nuevas versiones después del lanzamiento de Symbol.",
"pendingSignatureTitle": "Firma pendiente",
- "pendingSignatureDescription": "Hay una transacción pendiente a la espera de la firma"
+ "pendingSignatureDescription": "Hay una transacción pendiente a la espera de la firma",
+ "alertTitle":"Error",
+ "alertActionCreateWallet": "Crear nuevo",
+ "alertActionCancel": "Cancelar",
+ "alertInvalidMnemonicMessage": "Este perfil no está asociado a una frase nemónica válida. Por favor crea un nuevo perfil y transfiere tus fondos lo antes posible."
},
"mosaics": {
"title": "Mosaics"
@@ -514,9 +517,11 @@
"INPROGRESS_DEACTIVATION": "Desactivación en curso",
"harvetingIntroTitle": "Comienza a cosechar para ganar recompensas en bloque",
"minBalanceRequirement": "Para cosechar, la cuenta necesita un saldo de por lo menos %{balance}",
+ "nonZeroImportanceRequirement": "Su cuenta no puede iniciar la recolección delegada mientras la importancia sea igual a 0. El recálculo de la importancia puede demorar hasta 12 horas.",
"KEYS_LINKED": "Llaves enlazadas",
"viewLinkedKeys": "Ver las llaves enlazadas",
- "linkedNode": "Nodo enlazado"
+ "linkedNode": "Nodo enlazado",
+ "Importance": "Puntuación de importancia"
},
"sidebar": {
"seed": "Cuenta semillero",
@@ -568,6 +573,7 @@
"newUnconfirmed": "Nueva transacción sin confirmar!",
"newConfirmed": "Nueva transacción confirmada!",
"newAggregate": "Nueva transacción agregada!",
+ "newCosignatureAdded":"Firma recibida!",
"noMosaicPresent": "El mosaico '%{mosaicName}' no esta presente en esta cuenta"
},
diff --git a/src/locales/translations/it.json b/src/locales/translations/it.json
index d86e255..4e29340 100644
--- a/src/locales/translations/it.json
+++ b/src/locales/translations/it.json
@@ -35,7 +35,6 @@
"title": "Importa portafoglio",
"content": "Importa il tuo portafoglio inserendo il tuo mnemonico.",
"button": "Importare",
- "ignoreWarning": "Ignora l'avviso",
"cancelModalButton": "Annulla",
"error": {
"invalidMnemonic": "Mnemonico non valido",
@@ -470,7 +469,11 @@
"optInTitle": "Opt-In",
"optInDescription": "Il processo di attivazione (Opt-in) si aprirà dopo il lancio della blockchain di Symbol. Attendi la nuova versione del portafoglio.",
"pendingSignatureTitle": "In attesa di firma",
- "pendingSignatureDescription": "C'è una transazione in attesa di firma"
+ "pendingSignatureDescription": "C'è una transazione in attesa di firma",
+ "alertTitle":"Errore",
+ "alertActionCreateWallet": "Creare un nuovo account",
+ "alertActionCancel": "Annulla",
+ "alertInvalidMnemonicMessage": "Questo profilo non ha una frase mnemonica valida. Trasferisci il tuo XYM su un altro account il prima possibile."
},
"mosaics": {
"title": "Mosaico"
@@ -513,9 +516,11 @@
"INPROGRESS_DEACTIVATION": "Disattivazione in corso ",
"harvetingIntroTitle": "Inizia a Harvesting per guadagnare ricompense di blocchi",
"minBalanceRequirement": "Saldo insufficiente sull'account, poiché deve essere presente almeno %{balance} per avviare la delegated harvesting.",
+ "nonZeroImportanceRequirement": "Il tuo account non può avviare la raccolta delegata mentre l'importanza è uguale a 0. Il ricalcolo dell'importanza potrebbe richiedere fino a 12 ore.",
"viewLinkedKeys": "Visualizzazione delle chiavi correlate",
"linkedNode": "Nodo correlato (noda)",
- "KEYS_LINKED": "Chiavi correlate"
+ "KEYS_LINKED": "Chiavi correlate",
+ "Importance": "Punteggio di importanza"
},
"sidebar": {
"seed": "Account seed frase",
diff --git a/src/locales/translations/ja.json b/src/locales/translations/ja.json
index 084be47..9e09602 100644
--- a/src/locales/translations/ja.json
+++ b/src/locales/translations/ja.json
@@ -34,7 +34,6 @@
"title": "ウォレットのインポート",
"content": "正しい順序でニーモニックを入力して、ウォレットをインポートします。",
"button": "インポート",
- "ignoreWarning": "警告を無視する",
"cancelModalButton": "キャンセル",
"error": {
"invalidMnemonic": "ニーモニックが無効です",
@@ -475,7 +474,11 @@
"optInTitle": "オプトイン",
"optInDescription": "Symbolローンチ後のオプトインはこちらから",
"pendingSignatureTitle": "ペンディング署名",
- "pendingSignatureDescription": "署名待ちのペンディングトランザクションがあります"
+ "pendingSignatureDescription": "署名待ちのペンディングトランザクションがありま",
+ "alertTitle":"エラーが発生しました",
+ "alertActionCreateWallet": "新規作成",
+ "alertActionCancel": "キャンセル",
+ "alertInvalidMnemonicMessage": "このプロファイルには、有効なニーモニックフレーズがありません。新しいプロファイルを作成し、XYMを出来るだけ早く転送してください。"
},
"mosaics": {
"title": "モザイク"
@@ -519,9 +522,11 @@
"INPROGRESS_DEACTIVATION": "無効化(進行中)",
"harvetingIntroTitle": "ブロック報酬を獲得するためハーベストを開始",
"minBalanceRequirement": "残高が不十分です。委任ハーベスティングを開始するには、アカウントに少なくとも%{balance}を保有している必要があります。",
+ "nonZeroImportanceRequirement": "重要度が0の場合、アカウントは委任された収穫を開始できません。重要度の再計算には最大12時間かかる場合があります.",
"KEYS_LINKED": "リンクされた鍵",
"viewLinkedKeys": "リンクされたキーを表示",
- "linkedNode": "リンクされたノード"
+ "linkedNode": "リンクされたノード",
+ "Importance": "重要度スコア"
},
"sidebar": {
"seed": "シードアカウント",
@@ -573,6 +578,7 @@
"newUnconfirmed": "新しい未承認トランザクションがあります!",
"newConfirmed": "New confirmed transaction!",
"newAggregate": "New aggregate transaction!",
+ "newCosignatureAdded":"連署名を受信!",
"noMosaicPresent": "このアカウントにはモザイク「%{mosaicName}」はありません。"
},
"addressBook": {
diff --git a/src/locales/translations/pl.json b/src/locales/translations/pl.json
index 8471b78..0d9cd4a 100644
--- a/src/locales/translations/pl.json
+++ b/src/locales/translations/pl.json
@@ -33,7 +33,6 @@
"title": "Zaimportuj Portfel",
"content": "Zaimportuj konto, wprowadzając mnemoniki w odpowiedniej kolejności.",
"button": "Zaimportuj",
- "ignoreWarning": "Zignoruj Ostrzeżenie",
"cancelModalButton": "Anuluj",
"error": {
"invalidMnemonic": "Niepoprawny Mnemonik",
@@ -380,6 +379,8 @@
"registerButton": "Zarejestruj Konto Delegowane",
"startHarvestingButton": "Rozpocznij Zbieranie",
"stopHarvestingButton": "Zatrzymaj Zbieranie",
+ "minBalanceRequirement": "Niewystarczające saldo, konto musi zawierać co najmniej %{balance}, aby rozpocząć delegowane zbieranie.",
+ "nonZeroImportanceRequirement": "Twoje konto nie może rozpocząć delegowanych zbiorów, gdy ważność jest równa 0. Ponowne obliczenie ważności może potrwać do 12 godzin.",
"urlError": "Nie można otworzyć linku"
},
"RegisterAccount": {
diff --git a/src/locales/translations/ru.json b/src/locales/translations/ru.json
index c0bfa52..b55ef80 100644
--- a/src/locales/translations/ru.json
+++ b/src/locales/translations/ru.json
@@ -35,7 +35,6 @@
"title": "Импортировать кошелек",
"content": "Импортируйте свой кошелек, введя кодовую фразу (мнемонику).",
"button": "Импортировать",
- "ignoreWarning": "Игнорировать предупреждение",
"cancelModalButton": "Отмена",
"error": {
"invalidMnemonic": "Недействительная мнемоника",
@@ -434,14 +433,6 @@
"name": "Имя",
"seedIndex": "Индекс Сид аккаунта ",
- "namespaceId": "Идентификатор Пространств имен",
- "namespace": "Пространство имен",
- "phone": "Телефон",
- "email": "Email",
- "label": "Лейбл",
- "notes": "Заметка",
- "seedIndex": "Сид Индекс Аккаунт ",
-
"vrfPublicKey": "Связанный публичный Vrf ключ",
"vrfPrivateKey": "Связанный приватный Vrf ключ",
"remotePublicKey": "Связанный удаленный публичный ключ",
@@ -488,7 +479,11 @@
"optInTitle": "Пост Лаунч Опт-Ин",
"optInDescription": "Нажмите здесь, чтобы получить доступ к дашборд",
"pendingSignatureTitle": "Ожидает подписания",
- "pendingSignatureDescription": "Имеется транзакция, которая ожидает подписи"
+ "pendingSignatureDescription": "Имеется транзакция, которая ожидает подписи",
+ "alertTitle":"Ошибка",
+ "alertActionCreateWallet": "Создать новый аккаунт",
+ "alertActionCancel": "Отмена",
+ "alertInvalidMnemonicMessage": "В этом профиле нет действующей мнемонической фразы. Пожалуйста, как можно скорее переведите свои XYM на другой аккаунт."
},
"mosaics": {
"title": "Мозаика"
@@ -532,9 +527,11 @@
"INPROGRESS_DEACTIVATION": "Деактивация в процессе",
"harvetingIntroTitle": "Активируйте харвестинг, чтобы зарабатывать награды за новые блоки",
"minBalanceRequirement": "Недостаточный баланс на аккаунте. Должно быть не менее %{balance}, для того чтобы начать делегированный харвестинг.",
+ "nonZeroImportanceRequirement": "Ваша учетная запись не может начать делегированный сбор урожая, пока важность равна 0. Пересчет важности может занять до 12 часов.",
"KEYS_LINKED": "Ключи связанны",
"viewLinkedKeys": "Просмотр связанных ключей",
- "linkedNode": "Связанная нода"
+ "linkedNode": "Связанная нода",
+ "Importance": "оценка важности"
},
"sidebar": {
"seed": "Cид-фраза аккаунта",
@@ -587,6 +584,7 @@
"newUnconfirmed": "Новая неподтвержденная транзакция!",
"newConfirmed": "Новая подтвержденная транзакция!",
"newAggregate": "Новая агрегированная транзакция!",
+ "newCosignatureAdded":"Подпись получена!",
"noMosaicPresent": "В этом аккаунте '%{mosaicName}' нет мозаики"
},
"addressBook": {
diff --git a/src/locales/translations/uk.json b/src/locales/translations/uk.json
index 331d28b..21888e2 100644
--- a/src/locales/translations/uk.json
+++ b/src/locales/translations/uk.json
@@ -35,7 +35,6 @@
"title": "Імпортувати гаманець",
"content": "Імпортуйте свій гаманець, ввівши кодову фразу (мнемоніку).",
"button": "Імпортувати",
- "ignoreWarning": "Ігнорувати попередження",
"cancelModalButton": "Скасувати",
"error": {
"invalidMnemonic": "Неправильна мнемоніка",
diff --git a/src/locales/translations/zh.json b/src/locales/translations/zh.json
index 01a3561..b86adbc 100644
--- a/src/locales/translations/zh.json
+++ b/src/locales/translations/zh.json
@@ -34,7 +34,6 @@
"title": "导入钱包",
"content": "按顺序输入助记词",
"button": "导入",
- "ignoreWarning": "忽略警告",
"cancelModalButton": "取消",
"error": {
"invalidMnemonic": "助记词无效",
@@ -466,7 +465,11 @@
"optInTitle": "选择加入",
"optInDescription": "发布后的Opt-in即将开放。 Symbol启动后,请重新检查是否有新版本",
"pendingSignatureTitle": "待定签名",
- "pendingSignatureDescription": "有一笔交易正在等待签名"
+ "pendingSignatureDescription": "有一笔交易正在等待签名",
+ "alertTitle":"错误",
+ "alertActionCreateWallet": "创建新账户",
+ "alertActionCancel": "取消",
+ "alertInvalidMnemonicMessage": "此配置文件没有有效的助记词。请尽快将您的 XYM 转移到另一个帐户。"
},
"mosaics": {
"title": "马赛克"
@@ -509,9 +512,11 @@
"INPROGRESS_DEACTIVATION": "停用正在进行中",
"harvetingIntroTitle": "开始收获,赚取区块奖励",
"minBalanceRequirement": "余额不足,帐户需要持有至少 %{balance}才能开始进行委派的收获。",
+ "nonZeroImportanceRequirement": "当重要性等于 0 时,您的帐户无法开始委托收获。重要性重新计算可能需要长达 12 小时.",
"KEYS_LINKED": "关联的钥匙",
"viewLinkedKeys": "查看已链接的钥匙",
- "linkedNode": "已链接的节点"
+ "linkedNode": "已链接的节点",
+ "Importance": "重要性得分"
},
"sidebar": {
"seed": "种子帐户",
diff --git a/src/screens/Dashboard.js b/src/screens/Dashboard.js
index a07fc40..d0420fe 100644
--- a/src/screens/Dashboard.js
+++ b/src/screens/Dashboard.js
@@ -2,15 +2,14 @@ import React, { Component } from 'react';
import { StyleSheet, View } from 'react-native';
import { menuItems } from '@src/config';
import { NavigationMenu, GradientBackground } from '@src/components';
-import Home from './Home';
-import History from './History';
-import Harvest from './Harvest';
-import News from '@src/screens/News';
+import NodeDownOverlay from '@src/components/organisms/NodeDownOverlay';
+import Home from '@src/screens/Home';
+import History from '@src/screens/History';
+import Harvest from '@src/screens/Harvest';
import Mosaics from '@src/screens/Mosaics';
import Sidebar from '@src/screens/Sidebar';
import { Router } from '@src/Router';
import store from '@src/store';
-import NodeDownOverlay from '@src/components/organisms/NodeDownOverlay';
import { connect } from 'react-redux';
const styles = StyleSheet.create({
@@ -59,9 +58,6 @@ class Dashboard extends Component {
case 'mosaics':
Tab = Mosaics;
break;
- case 'news':
- Tab = News;
- break;
case 'harvest':
Tab = Harvest;
break;
diff --git a/src/screens/EnterMnemonics/index.js b/src/screens/EnterMnemonics/index.js
index a0b30b6..7ede63c 100644
--- a/src/screens/EnterMnemonics/index.js
+++ b/src/screens/EnterMnemonics/index.js
@@ -180,11 +180,6 @@ class EnterMnemonics extends Component {
// Router go to pre-dashboard
};
- forceCreate = async () => {
- this.setState({ showWarning: false });
- this.createWallet();
- };
-
hideWarning = () => {
this.setState({ showWarning: false });
};
@@ -199,9 +194,7 @@ class EnterMnemonics extends Component {
{showWarning && (
)}
diff --git a/src/screens/Harvest.js b/src/screens/Harvest.js
index 72bbccc..0fc91d7 100644
--- a/src/screens/Harvest.js
+++ b/src/screens/Harvest.js
@@ -1,15 +1,15 @@
import React, { Component } from 'react';
import { StyleSheet, Text as NativeText, TouchableOpacity, View } from 'react-native';
-import { Section, ImageBackground, GradientBackground, Text, TitleBar, NodeDropdown, Button, Col, Row } from '@src/components';
+import { Section, GradientBackground, Text, TitleBar, NodeDropdown, Button, Row } from '@src/components';
import GlobalStyles from '@src/styles/GlobalStyles';
import { connect } from 'react-redux';
import HarvestingService from '@src/services/HarvestingService';
import store from '@src/store';
import { showPasscode } from '@src/utils/passcode';
import translate from '@src/locales/i18n';
-import Trunc from '@src/components/organisms/Trunc';
-import {Router} from "@src/Router";
-
+import { Router } from '@src/Router';
+import ReadMoreLink from '@src/components/controls/ReadMoreLink';
+import { getHarvestingPrerequisitesUrl } from '@src/config/environment';
const styles = StyleSheet.create({
showButton: {
textAlign: 'right',
@@ -73,7 +73,8 @@ class Harvest extends Component {
isLoading: false,
};
- componentDidMount() {
+
+ async componentDidMount() {
const { selectedAccount, nodes } = this.props;
if (selectedAccount.harvestingNode) {
for (let node of nodes) {
@@ -98,6 +99,7 @@ class Harvest extends Component {
label: `http://${node.url}:3000`,
}));
};
+
onSelectHarvestingNode = node => {
const url = node;
@@ -154,9 +156,24 @@ class Harvest extends Component {
};
render() {
- const { status, totalBlockCount, totalFeesEarned, onOpenMenu, onOpenSettings, balance, minRequiredBalance, nativeMosaicNamespace, harvestingModel, selectedAccount } = this.props;
+ const {
+ status,
+ totalBlockCount,
+ totalFeesEarned,
+ onOpenMenu,
+ onOpenSettings,
+ balance,
+ minRequiredBalance,
+ nativeMosaicNamespace,
+ harvestingModel,
+ selectedAccount,
+ accountImportance
+ } = this.props;
const { selectedNodeUrl, isLoading } = this.state;
const notEnoughBalance = balance < minRequiredBalance;
+ const notEnoughBalanceTitle = translate('harvest.minBalanceRequirement', { balance: minRequiredBalance + ' ' + nativeMosaicNamespace })
+ const zeroImportanceTitle = translate('harvest.nonZeroImportanceRequirement')
+ const url = getHarvestingPrerequisitesUrl();
let statusStyle;
switch (status) {
case 'ACTIVE':
@@ -212,6 +229,14 @@ class Harvest extends Component {
{totalFeesEarned.toString()}
+
+
+ {translate('harvest.Importance')}:
+
+
+ {accountImportance}
+
+
{status !== 'INACTIVE' && (
this.onViewLinkedKeysClick()} style={{ textAlign: 'right', width: '100%' }}>
@@ -239,7 +264,7 @@ class Harvest extends Component {
)}
- {!notEnoughBalance && status === 'INACTIVE' && (<>
+ {!notEnoughBalance && status === 'INACTIVE' && accountImportance !== '0%' && (<>
)}
+
{notEnoughBalance && (
-
- {translate('harvest.minBalanceRequirement', { balance: minRequiredBalance + ' ' + nativeMosaicNamespace })}
-
+
)}
+
+
+ {!notEnoughBalance && accountImportance == '0%' && (
+
+ )}
+
@@ -306,4 +336,8 @@ export default connect(state => ({
totalFeesEarned: state.harvesting.harvestedBlockStats.totalFeesEarned,
harvestingModel: state.harvesting.harvestingModel,
nodes: state.harvesting.nodes,
+ selectedNode: state.network.selectedNetwork ? state.network.selectedNetwork.node : '',
+ selectedAccountAddress: state.account.selectedAccountAddress,
+ networkCurrencyDivisibility: state.network.selectedNetwork.currencyDivisibility,
+ accountImportance: state.harvesting.accountImportance,
}))(Harvest);
diff --git a/src/screens/Home.js b/src/screens/Home.js
index 623c71b..28b9d35 100644
--- a/src/screens/Home.js
+++ b/src/screens/Home.js
@@ -1,5 +1,5 @@
import React, { Component } from 'react';
-import {StyleSheet, ScrollView, TouchableOpacity, View, RefreshControl, FlatList} from 'react-native';
+import { StyleSheet, ScrollView, TouchableOpacity, View, RefreshControl, FlatList } from 'react-native';
import {
Section,
GradientBackground,
@@ -10,14 +10,15 @@ import {
Row,
Icon,
TitleBar,
- ListItem
+ ListItem,
+ ListContainer,
+ BasicAlert
} from '@src/components';
import { Router } from '@src/Router';
import { connect } from 'react-redux';
import store from '@src/store';
-import ListContainer from "@src/components/backgrounds/ListContainer";
-import GlobalStyles from "@src/styles/GlobalStyles";
-import translate from "@src/locales/i18n";
+import GlobalStyles from '@src/styles/GlobalStyles';
+import translate from '@src/locales/i18n';
const styles = StyleSheet.create({
transactionPreview: {
@@ -60,7 +61,7 @@ type Props = {
type State = {};
class Home extends Component {
- state = { isSidebarShown: false };
+ state = { isSidebarShown: false, showWarning: false};
reload = () => {
store.dispatchAction({ type: 'account/loadAllData' });
@@ -86,6 +87,13 @@ class Home extends Component {
);
}
+ componentDidMount = () => {
+ // If wallet created by words mnemonic not equal 24, show warning message.
+ if (store.getState().wallet.mnemonic.split(' ').length !== 24){
+ this.setState({showWarning: true})
+ }
+ };
+
render = () => {
const {
pendingSignature,
@@ -98,7 +106,8 @@ class Home extends Component {
isLoading,
isMultisig
} = this.props;
- const {} = this.state;
+
+ const { showWarning } = this.state;
const notifications = [];
notifications.push({ title: translate('home.optInTitle'), description: translate('home.optInDescription' ), handler: () => Router.goToOptInWelcome({}, this.props.componentId)});
@@ -114,6 +123,22 @@ class Home extends Component {
fade={true}
titleBar={ onOpenMenu()} onSettings={() => onOpenSettings()}/>}
>
+ {showWarning && Router.goToCreateOrImport({}),
+ },
+ {
+ text: translate('home.alertActionCancel'),
+ onPress: () => {
+ this.setState({ showWarning: false });
+ },
+ }
+ ]}
+ />}
diff --git a/src/screens/Mosaics.js b/src/screens/Mosaics.js
index c8af4e7..a2370b4 100644
--- a/src/screens/Mosaics.js
+++ b/src/screens/Mosaics.js
@@ -29,8 +29,8 @@ class Mosaics extends Component {
);
};
- refresh = () => {
- store.dispatchAction({ type: 'account/loadBalance' });
+ refresh = async() => {
+ await store.dispatchAction({ type: 'account/loadBalance' });
};
render() {
diff --git a/src/screens/News.js b/src/screens/News.js
deleted file mode 100644
index d658bdb..0000000
--- a/src/screens/News.js
+++ /dev/null
@@ -1,90 +0,0 @@
-import React, { Component } from 'react';
-import { RefreshControl, StyleSheet, View, FlatList } from 'react-native';
-import { GradientBackground, ListContainer, ListItem, TitleBar } from '@src/components';
-import New from '@src/components/organisms/New';
-import GlobalStyles from '@src/styles/GlobalStyles';
-import { connect } from 'react-redux';
-import store from '@src/store';
-import translate from "@src/locales/i18n";
-
-const styles = StyleSheet.create({
- list: {
- marginBottom: 10,
- },
- inner: {
- borderRadius: 6,
- backgroundColor: GlobalStyles.color.WHITE,
- }
-});
-
-type Props = {};
-type State = {};
-
-class News extends Component {
- constructor(props: {}) {
- super(props);
- }
-
- refresh = () => {
- store.dispatchAction({type: 'news/loadNews'});
- }
-
- renderNewsItem = (item) => {
- return
-
-
- }
-
- render() {
- const { news, onOpenMenu, onOpenSettings, isLoading } = this.props;
- const dataManager = {isLoading};
-
- return (
- onOpenMenu()}
- onSettings={() => onOpenSettings()}
- />}
- >
-
-
- '' + index + 'news'}
- refreshControl={
- this.refresh()}
- />
- }
- />
-
- {/*
- {news.map(this.renderNewsItem)}
- */}
-
-
- );
- }
-}
-
-export default connect(state => ({
- news: state.news.news,
- isLoading: state.news.isLoading
-}))(News);
diff --git a/src/screens/Send.js b/src/screens/Send.js
index 613a199..1152f3c 100644
--- a/src/screens/Send.js
+++ b/src/screens/Send.js
@@ -68,7 +68,6 @@ class Send extends Component {
if(message)
this.onMessageChange(message);
- this.updateMaxFee();
};
verify = () => {
@@ -197,10 +196,11 @@ class Send extends Component {
);
};
- onAddressChange = recipientAddress => {
+ onAddressChange = async recipientAddress => {
const { network } = this.props;
const showAddressError = !isAddressValid(recipientAddress, network);
this.setState({ recipientAddress, showAddressError, isEncrypted: false });
+ await this.updateMaxFee();
};
onAmountChange = async val => {
@@ -229,7 +229,7 @@ class Send extends Component {
}
- this.updateMaxFee();
+ await this.updateMaxFee();
this.verifyAmount();
};
@@ -265,7 +265,7 @@ class Send extends Component {
message.slice(0, 1024);
}
await this.setState({ message, isEncrypted });
- this.updateMaxFee();
+ await this.updateMaxFee();
};
onMessageEncryptedChange = async isEncrypted => {
@@ -291,12 +291,12 @@ class Send extends Component {
this.setState({isEncrypted: false});
}
- this.updateMaxFee();
+ await this.updateMaxFee();
};
- onFeeChange(fee) {
+ onFeeChange = async fee => {
this.setState({ fee });
- this.updateMaxFee();
+ await this.updateMaxFee();
};
render = () => {
diff --git a/src/screens/WalletLoading/index.js b/src/screens/WalletLoading/index.js
index 58bceec..222f73f 100644
--- a/src/screens/WalletLoading/index.js
+++ b/src/screens/WalletLoading/index.js
@@ -22,7 +22,10 @@ class WalletLoading extends Component {
} else {
store.dispatchAction({type: 'wallet/saveWallet'}).then(_ => {
Router.goToDashboard({})
- });
+ })
+ .finally(() => {
+ Router.goToDashboard({})
+ })
}
};
diff --git a/src/services/AccountService.js b/src/services/AccountService.js
index 658054e..5cdd4cf 100644
--- a/src/services/AccountService.js
+++ b/src/services/AccountService.js
@@ -1,13 +1,24 @@
-import { AccountHttp, Account, Address, NetworkType, Mosaic, MosaicHttp, NamespaceHttp, MultisigHttp, MosaicId, UInt64 } from 'symbol-sdk';
-import {ExtendedKey, MnemonicPassPhrase, Network, Wallet} from 'symbol-hd-wallets';
-import type { AccountModel, AccountOriginType } from '@src/storage/models/AccountModel';
+import {
+ AccountHttp,
+ Account,
+ Address,
+ NetworkType,
+ Mosaic,
+ MosaicHttp,
+ NamespaceHttp,
+ MultisigHttp,
+ MosaicId,
+ UInt64,
+} from 'symbol-sdk';
+import { ExtendedKey, MnemonicPassPhrase, Network, Wallet } from 'symbol-hd-wallets';
+import type { AccountModel, AccountOriginType, MultisigAccountInfo } from '@src/storage/models/AccountModel';
import type { MnemonicModel } from '@src/storage/models/MnemonicModel';
import type { AppNetworkType, NetworkModel } from '@src/storage/models/NetworkModel';
import type { MosaicModel } from '@src/storage/models/MosaicModel';
import { AccountSecureStorage } from '@src/storage/persistence/AccountSecureStorage';
import MosaicService from '@src/services/MosaicService';
import { SymbolPaperWallet } from 'symbol-paper-wallets';
-import {getAccountIndexFromDerivationPath} from "@src/utils/format";
+import { getAccountIndexFromDerivationPath } from '@src/utils/format';
export default class AccountService {
/**
@@ -272,4 +283,55 @@ export default class AccountService {
return btoa(Uint8ToString(bytes));
}
+
+ // get signers for current account
+ static getSigners(
+ currentAccountAddress: Address,
+ multisigAccountGraph?: Map,
+ level?: number,
+ childMinApproval?: number,
+ childMinRemoval?: number
+ ) {
+ let currentMultisigAccountInfo: MultisigAccountInfo;
+ if (level === undefined) {
+ for (const [l, levelAccounts] of multisigAccountGraph) {
+ for (const levelAccount of levelAccounts) {
+ if (levelAccount.accountAddress.equals(currentAccountAddress)) {
+ currentMultisigAccountInfo = levelAccount;
+ level = l;
+ break;
+ }
+ }
+ }
+ } else {
+ for (const levelAccount of multisigAccountGraph.get(level)) {
+ if (levelAccount.accountAddress.equals(currentAccountAddress)) {
+ currentMultisigAccountInfo = levelAccount;
+ }
+ }
+ }
+ const currentSigner = {
+ address: currentAccountAddress,
+ multisig: currentMultisigAccountInfo?.isMultisig() || false,
+ requiredCosigApproval: Math.max(childMinApproval || 0, currentMultisigAccountInfo?.minApproval || 0),
+ requiredCosigRemoval: Math.max(childMinRemoval || 0, currentMultisigAccountInfo?.minRemoval || 0),
+ };
+
+ const parentSigners = [];
+ if (currentMultisigAccountInfo?.multisigAddresses) {
+ for (const parentSignerAddress of currentMultisigAccountInfo.multisigAddresses) {
+ parentSigners.push(
+ ...this.getSigners(
+ parentSignerAddress,
+ multisigAccountGraph,
+ level - 1,
+ currentSigner.requiredCosigApproval,
+ currentSigner.requiredCosigRemoval
+ )
+ );
+ }
+ currentSigner.parentSigners = parentSigners.filter(ps => currentMultisigAccountInfo.multisigAddresses.some(msa => msa.equals(ps.address)));
+ }
+ return [currentSigner, ...parentSigners];
+ }
}
diff --git a/src/services/FetchTransactionService.js b/src/services/FetchTransactionService.js
index 40c43a9..78780b3 100644
--- a/src/services/FetchTransactionService.js
+++ b/src/services/FetchTransactionService.js
@@ -79,7 +79,8 @@ export default class FetchTransactionService {
rawAddress: string,
page: number,
directionFilter: DirectionFilter,
- network: NetworkModel
+ network: NetworkModel,
+ cosignatoryOf: []
): Promise {
const transactionHttp = new TransactionHttp(network.node);
const address = Address.createFromRawAddress(rawAddress);
@@ -110,7 +111,19 @@ export default class FetchTransactionService {
transactionHttp.search(partialSearchCriteria).toPromise(),
transactionHttp.search(unconfirmedSearchCriteria).toPromise(),
]);
- allTransactions = [...unconfirmedTransactions.data, ...partialTransactions.data, ...confirmedTransactions.data];
+
+ let multisigPartialSearchCriteria = partialSearchCriteria;
+ for(const cosigner of cosignatoryOf){
+ multisigPartialSearchCriteria.address = Address.createFromRawAddress(cosigner);
+ const multisigTransactions = await transactionHttp.search(multisigPartialSearchCriteria).toPromise();
+ for(const transaction of multisigTransactions.data){
+ if(!partialTransactions.data.some((tx)=>transaction.transactionInfo.hash === tx.transactionInfo.hash)){
+ partialTransactions.data.push(transaction);
+ }
+ }
+ };
+
+ allTransactions = [...partialTransactions.data, ...unconfirmedTransactions.data, ...confirmedTransactions.data];
} else {
const confirmedTxs = await transactionHttp.search(confirmedSearchCriteria).toPromise();
allTransactions = confirmedTxs.data;
diff --git a/src/services/HarvestingService.js b/src/services/HarvestingService.js
index c6a8101..e7e483b 100644
--- a/src/services/HarvestingService.js
+++ b/src/services/HarvestingService.js
@@ -218,6 +218,23 @@ export default class HarvestingService {
},
];
}
+ static async getAccountImportance(node: string, accountAddress: string, networkCurrencyDivisibility, selectedNode){
+ try{
+ const accountHttp = new AccountHttp(node);
+ const accountInfo = await accountHttp.getAccountInfo(Address.createFromRawAddress(accountAddress)).toPromise();
+ if(!accountInfo){
+ return '0%'
+ }
+ const networkInfo = await NetworkService.getNetworkModelFromNode(selectedNode);
+ if (!networkCurrencyDivisibility || !networkInfo.totalChainImportance) {
+ return 'N/A';
+ }
+ return {networkInfo: networkInfo, importance: accountInfo.importance.compact()};
+ }catch(err){
+ console.log(err);
+ return;
+ }
+ }
/**
* Creates and links the keys
diff --git a/src/services/ListenerService.js b/src/services/ListenerService.js
index afd2b8c..c5fa7b4 100644
--- a/src/services/ListenerService.js
+++ b/src/services/ListenerService.js
@@ -1,9 +1,9 @@
-import {Address, IListener, Listener, RepositoryFactoryHttp} from 'symbol-sdk';
+import { Address, Listener, RepositoryFactoryHttp } from 'symbol-sdk';
import type { NetworkModel } from '@src/storage/models/NetworkModel';
import { Router } from '@src/Router';
import store from '@src/store';
import translate from '@src/locales/i18n';
-import {CommonHelpers} from "@src/utils/commonHelpers";
+import { CommonHelpers } from '@src/utils/commonHelpers';
export default class ListenerService {
network: NetworkModel;
@@ -60,11 +60,11 @@ export default class ListenerService {
});
};
- addConfirmed = (rawAddress: string) => {
+ addConfirmed = (rawAddress: string, isMultisig: boolean) => {
console.log('Adding confirmed listener: ' + rawAddress);
const address = Address.createFromRawAddress(rawAddress);
this.listener
- .confirmed(address)
+ .confirmed(address, undefined, isMultisig)
//.pipe(filter(transaction => transaction.transactionInfo !== undefined))
.subscribe(() => {
this.showMessage(translate('notification.newConfirmed'), 'success');
@@ -72,11 +72,11 @@ export default class ListenerService {
});
};
- addUnconfirmed = (rawAddress: string) => {
+ addUnconfirmed = (rawAddress: string, isMultisig: boolean) => {
console.log('Adding unconfirmed listener: ' + rawAddress);
const address = Address.createFromRawAddress(rawAddress);
this.listener
- .unconfirmedAdded(address)
+ .unconfirmedAdded(address, undefined, isMultisig)
//.pipe(filteser(transaction => transaction.transactionInfo !== undefined))
.subscribe(() => {
this.showMessage(translate('notification.newUnconfirmed'), 'warning');
@@ -84,6 +84,15 @@ export default class ListenerService {
});
};
+ addPartial = (rawAddress: string, isMultisig: boolean) => {
+ console.log('Adding unconfirmed listener: ' + rawAddress);
+ const address = Address.createFromRawAddress(rawAddress);
+ this.listener.aggregateBondedAdded(address, undefined, isMultisig).subscribe(() => {
+ this.showMessage(translate('notification.newAggregate'), 'warning');
+ store.dispatchAction({ type: 'account/loadAllData' });
+ });
+ };
+
showMessage = (message: string, type: 'danger' | 'warning' | 'success' = 'success') => {
Router.showMessage({
message: message,
diff --git a/src/services/NetworkService.js b/src/services/NetworkService.js
index 34725d6..aab7f3b 100644
--- a/src/services/NetworkService.js
+++ b/src/services/NetworkService.js
@@ -1,10 +1,19 @@
import {ChainHttp, NetworkConfiguration, NetworkHttp, NetworkType, NodeHttp, RepositoryFactoryHttp, TransactionFees} from 'symbol-sdk';
-import type { NetworkModel } from '@src/storage/models/NetworkModel';
+import type { NetworkModel, AppNetworkType } from '@src/storage/models/NetworkModel';
import { durationStringToSeconds } from '@src/utils/format';
import { timeout } from 'rxjs/operators';
+import { getStatisticsServiceURL } from '@src/config/environment'
const REQUEST_TIMEOUT = 5000;
+// Statistics service nodes endpoint filters
+export type NodeFilters = 'preferred' | 'suggested';
+export interface NodeSearchCriteria{
+ nodeFilter: NodeFilters,
+ limit: 30
+}
+
+
export default class NetworkService {
/**
* Get network model from node
@@ -55,6 +64,7 @@ export default class NetworkService {
epochAdjustment: parseInt(networkProps.network.epochAdjustment),
transactionFees: transactionFees,
defaultDynamicFeeMultiplier: networkProps.chain.defaultDynamicFeeMultiplier || 1000,
+ totalChainImportance: networkProps.chain.totalChainImportance
};
}
@@ -103,4 +113,46 @@ export default class NetworkService {
return false;
}
}
+
+ /**
+ * Gets node list from statistics service
+ * @param networkType 'mainnet | testnet'
+ * @param nodeSearchCriteria NodeSearchCriteria
+ */
+ static async getNodeList(networkType: AppNetworkType, {limit, nodeFilter}: NodeSearchCriteria) {
+ return new Promise(resolve => {
+ fetch(`${getStatisticsServiceURL(networkType)}nodes?filter=${nodeFilter}&limit=${limit}`)
+ .then(response => response.json())
+ .then((responseData)=> {
+ resolve(responseData)
+ })
+ .catch(e => {
+ resolve([])
+ console.log(e)
+ });
+ });
+ }
+
+ /**
+ * Gets nodes urls
+ * @param networkType 'mainnet | testnet'
+ */
+ static async getSelectorNodeList(networkType: AppNetworkType) {
+ const nodeSearchCriteria = {
+ nodeFilter: 'suggested',
+ limit: 30
+ }
+
+ const nodes = await NetworkService.getNodeList(networkType, nodeSearchCriteria) || [];
+ let nodeUrls = [];
+
+ for (const node of nodes) {
+ const { apiStatus } = node;
+ if (apiStatus) {
+ nodeUrls.push(apiStatus.restGatewayUrl)
+ }
+ }
+
+ return nodeUrls;
+ }
}
diff --git a/src/services/TransactionService.js b/src/services/TransactionService.js
index 9a5dfc2..3cdceea 100644
--- a/src/services/TransactionService.js
+++ b/src/services/TransactionService.js
@@ -72,8 +72,8 @@ export default class TransactionService {
signer: AccountModel,
networkModel: NetworkModel
): TransferTransaction {
- const recipientAddress = Address.createFromRawAddress(transaction.recipientAddress);
const networkType = networkModel.type === 'testnet' ? NetworkType.TEST_NET : NetworkType.MAIN_NET;
+ const recipientAddress = Address.createFromRawAddress(transaction.recipientAddress);
const mosaics = [new Mosaic(new MosaicId(transaction.mosaics[0].mosaicId), UInt64.fromUint(transaction.mosaics[0].amount))];
if (!transaction.messageEncrypted) {
@@ -88,7 +88,7 @@ export default class TransactionService {
);
} else {
const signerAccount = Account.createFromPrivateKey(signer.privateKey, networkType);
- const repositoryFactory = await new RepositoryFactoryHttp(networkModel.node);
+ const repositoryFactory = new RepositoryFactoryHttp(networkModel.node);
const accountHttp = repositoryFactory.createAccountRepository();
try {
const accountInfo = await accountHttp.getAccountInfo(recipientAddress).toPromise();
diff --git a/src/storage/models/NetworkModel.js b/src/storage/models/NetworkModel.js
index 574eff3..9291ebf 100644
--- a/src/storage/models/NetworkModel.js
+++ b/src/storage/models/NetworkModel.js
@@ -15,4 +15,5 @@ export interface NetworkModel {
epochAdjustment: number;
transactionFees: TransactionFees;
defaultDynamicFeeMultiplier: number;
+ totalChainImportance: number
}
diff --git a/src/store/account.js b/src/store/account.js
index a0f135f..376bccf 100644
--- a/src/store/account.js
+++ b/src/store/account.js
@@ -1,6 +1,9 @@
import AccountService from '@src/services/AccountService';
-import { from } from 'rxjs';
+import { of } from 'rxjs';
import { GlobalListener } from '@src/store/index';
+import { RepositoryFactoryHttp, Address } from 'symbol-sdk';
+import { map, catchError } from 'rxjs/operators';
+import _ from 'lodash';
export default {
namespace: 'account',
@@ -15,6 +18,7 @@ export default {
accounts: [],
cosignatoryOf: [],
pendingSignature: false,
+ multisigGraphInfo: [],
},
mutations: {
setRefreshingObs(state, payload) {
@@ -45,6 +49,10 @@ export default {
state.account.cosignatoryOf = payload;
return state;
},
+ setMultisigGraphInfo(state, payload) {
+ state.account.multisigGraphInfo = payload;
+ return state;
+ },
},
actions: {
loadAllData: async ({ commit, dispatchAction, state }, reset) => {
@@ -52,17 +60,18 @@ export default {
commit({ type: 'account/setLoading', payload: true });
const address = AccountService.getAddressByAccountModelAndNetwork(state.wallet.selectedAccount, state.network.network);
commit({ type: 'account/setSelectedAccountAddress', payload: address });
- dispatchAction({ type: 'transaction/init' });
+ await dispatchAction({ type: 'account/loadMultisigTree' });
if (reset) {
+ await dispatchAction({ type: 'account/loadCosignatoryOf' });
commit({ type: 'account/setBalance', payload: 0 });
commit({ type: 'account/setOwnedMosaics', payload: [] });
}
+ await dispatchAction({ type: 'account/loadBalance' });
+ await dispatchAction({ type: 'transaction/init' });
if (state.account.refreshingObs) {
state.account.refreshingObs.unsubscribe();
}
- await dispatchAction({type: 'account/loadBalance'});
- dispatchAction({type: 'harvesting/init'});
- dispatchAction({type: 'account/loadCosignatoryOf'});
+ dispatchAction({ type: 'harvesting/init' });
commit({ type: 'account/setLoading', payload: false });
} catch (e) {
commit({ type: 'account/setLoading', payload: false });
@@ -78,13 +87,54 @@ export default {
loadCosignatoryOf: async ({ commit, state }) => {
const address = AccountService.getAddressByAccountModelAndNetwork(state.wallet.selectedAccount, state.network.network);
const msigInfo = await AccountService.getCosignatoryOfByAddress(address, state.network.selectedNetwork);
+ let multisigAccountGraph = state.account.multisigGraphInfo;
+ // find account signers
+ if (multisigAccountGraph !== undefined) {
+ const accountSigners = AccountService.getSigners(Address.createFromRawAddress(address), multisigAccountGraph);
+ let allSigners = [];
+ accountSigners.forEach(signer => {
+ allSigners.push(signer.address.pretty());
+ signer.parentSigners.forEach(parent => {
+ allSigners.push(parent.address.pretty());
+ parent.parentSigners.forEach(topLevel => {
+ allSigners.push(topLevel.address.pretty());
+ });
+ });
+ });
+ allSigners = _.uniq(allSigners);
+ allSigners.forEach(signer => {
+ if (!msigInfo.cosignatoryOf.some(cosignatory => cosignatory == signer) && signer !== address) {
+ msigInfo.cosignatoryOf.push(signer);
+ }
+ });
+ }
for (let cosignatoryOf of msigInfo.cosignatoryOf) {
- GlobalListener.addConfirmed(cosignatoryOf);
- GlobalListener.addUnconfirmed(cosignatoryOf);
+ GlobalListener.addConfirmed(cosignatoryOf, state.account.cosignatoryOf.length > 0);
+ GlobalListener.addUnconfirmed(cosignatoryOf, state.account.cosignatoryOf.length > 0);
+ GlobalListener.addPartial(cosignatoryOf, state.account.cosignatoryOf.length > 0);
}
commit({ type: 'account/setCosignatoryOf', payload: msigInfo.cosignatoryOf });
commit({ type: 'account/setIsMultisig', payload: msigInfo.isMultisig });
},
+ // load multisig tree data
+ loadMultisigTree: async ({ commit, state }) => {
+ const address = AccountService.getAddressByAccountModelAndNetwork(state.wallet.selectedAccount, state.network.network);
+ const repositoryFactory = new RepositoryFactoryHttp(state.network.selectedNode);
+ const multisigRepo = repositoryFactory.createMultisigRepository();
+ await multisigRepo
+ .getMultisigAccountGraphInfo(Address.createFromRawAddress(address))
+ .pipe(
+ map(g => {
+ commit({ type: 'account/setMultisigGraphInfo', payload: g.multisigEntries });
+ return of(g);
+ }),
+ catchError(() => {
+ commit({ type: 'account/setMultisigGraphInfo', payload: undefined });
+ return of([]);
+ })
+ )
+ .toPromise();
+ },
},
};
diff --git a/src/store/harvesting.js b/src/store/harvesting.js
index 06759d9..fe25b7d 100644
--- a/src/store/harvesting.js
+++ b/src/store/harvesting.js
@@ -1,10 +1,9 @@
import { UInt64 } from 'symbol-sdk';
import HarvestingService from '@src/services/HarvestingService';
-import {HarvestingSecureStorage} from "@src/storage/persistence/HarvestingSecureStorage";
+import { HarvestingSecureStorage } from '@src/storage/persistence/HarvestingSecureStorage';
const MIN_REQUIRED_BALANCE = 10000;
-
export type HarvestingStatus = 'ACTIVE' | 'INACTIVE' | 'INPROGRESS_ACTIVATION' | 'INPROGRESS_DEACTIVATION' | 'KEYS_LINKED';
export type HarvestedBlock = {
@@ -31,7 +30,8 @@ const initialState = {
minRequiredBalance: MIN_REQUIRED_BALANCE,
harvestingModel: null,
nodes: HarvestingService.getHarvestingNodeList(),
-}
+ accountImportance: 0,
+};
export default {
namespace: 'harvesting',
@@ -77,33 +77,54 @@ export default {
state.harvesting.nodes = payload;
return state;
},
+ setAccountImportance(state, payload) {
+ state.harvesting.accountImportance = payload;
+ return state;
+ },
},
actions: {
init: async ({ dispatchAction, commit }) => {
- Promise.all([
+ // commit({ type: 'harvesting/setAccountImportance', payload: 0 });
+ await Promise.all([
dispatchAction({ type: 'harvesting/loadState' }),
dispatchAction({ type: 'harvesting/loadHarvestedBlocks' }),
+ dispatchAction({ type: 'harvesting/loadAccountImportance' }),
dispatchAction({ type: 'harvesting/loadHarvestedBlocksStats' }),
dispatchAction({ type: 'harvesting/loadHarvestingModel' }),
dispatchAction({ type: 'harvesting/loadHarvestingNodes' }),
]).catch(e => {
commit({ type: 'harvesting/resetState' });
- })
+ });
},
loadState: async ({ commit, state }) => {
try {
const status = await HarvestingService.getAccountStatus(state.wallet.selectedAccount, state.network.selectedNetwork);
commit({ type: 'harvesting/setStatus', payload: status });
- } catch(e) {
+ } catch (e) {
console.log(e);
commit({ type: 'harvesting/setStatus', payload: 'INACTIVE' });
}
},
+ loadAccountImportance: async ({ commit, state }) => {
+ try {
+ const {importance, networkInfo} = await HarvestingService.getAccountImportance(state.network.selectedNetwork.node, state.account.selectedAccountAddress, state.network.selectedNetwork.currencyDivisibility, state.network.selectedNetwork.node || '');
+ const totalChainImportance = parseInt(networkInfo.totalChainImportance.toString().replace(/'/g, '')) || 0;
+ const relativeImportance = importance > 0 ? importance / totalChainImportance : importance;
+ const formatOptions: Intl.NumberFormatOptions = {
+ maximumFractionDigits: state.network.selectedNetwork.currencyDivisibility,
+ style: 'percent',
+ };
+ commit({ type: 'harvesting/setAccountImportance', payload: relativeImportance.toLocaleString(undefined, formatOptions).toString() });
+ } catch (e) {
+ commit({ type: 'harvesting/setAccountImportance', payload: '0%' });
+ console.log(e);
+ }
+ },
loadHarvestingNodes: async ({ commit, state }) => {
try {
const nodes = await HarvestingService.getPeerNodes(state.network.selectedNetwork);
commit({ type: 'harvesting/setNodes', payload: nodes });
- } catch(e) {
+ } catch (e) {
console.log(e);
commit({ type: 'harvesting/setNodes', payload: HarvestingService.getHarvestingNodeList() });
}
@@ -144,7 +165,7 @@ export default {
harvestingNode: null,
},
});
- } catch(e) {
+ } catch (e) {
console.log(e);
}
dispatchAction({ type: 'harvesting/init' });
diff --git a/src/store/index.js b/src/store/index.js
index 7605c6e..6eb6805 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -6,7 +6,6 @@ import network from '@src/store/network';
import transfer from '@src/store/transfer';
import mosaic from '@src/store/mosaic';
import account from '@src/store/account';
-import news from '@src/store/news';
import harvesting from '@src/store/harvesting';
import addressBook from '@src/store/addressBook';
import ListenerService from '@src/services/ListenerService';
@@ -21,7 +20,6 @@ const modules = {
mosaic,
transfer,
account,
- news,
harvesting,
addressBook,
transaction,
diff --git a/src/store/network.js b/src/store/network.js
index 953fef6..eb475f1 100644
--- a/src/store/network.js
+++ b/src/store/network.js
@@ -1,5 +1,5 @@
import { AsyncCache } from '@src/utils/storage/AsyncCache';
-import {getDefaultNetworkType, getNISNodes, getNodes} from '@src/config/environment';
+import { getDefaultNetworkType, getNISNodes } from '@src/config/environment';
import NetworkService from '@src/services/NetworkService';
import { GlobalListener } from '@src/store/index';
@@ -28,6 +28,8 @@ export default {
transactionFees: {},
defaultDynamicFeeMultiplier: 0,
},
+ mainnetNodes: [],
+ testnetNodes: [],
},
mutations: {
setIsLoaded(state, payload) {
@@ -62,30 +64,65 @@ export default {
state.network.nodeFailedAttempts = payload;
return state;
},
+ setMainnetNodes(state, payload) {
+ state.network.mainnetNodes = payload;
+ return state;
+ },
+ setTestnetNodes(state, payload) {
+ state.network.testnetNodes = payload;
+ return state;
+ },
},
actions: {
- initState: async ({ commit, dispatchAction }) => {
+ initState: async ({ state, commit, dispatchAction }) => {
let selectedNode = await AsyncCache.getSelectedNode();
- if (!selectedNode) {
- const network = getDefaultNetworkType();
- selectedNode = getNodes(network)[0];
+
+ // load nodes list from statistic service
+ await dispatchAction({ type: 'network/loadNodeList' });
+
+ const networkType = getDefaultNetworkType();
+ const nodeList = networkType === 'mainnet' ? state.network.mainnetNodes : state.network.testnetNodes;
+
+ // assign node, if node list available and selectedNode is not set
+ if (nodeList.length && !selectedNode) {
+ const randomIndex = Math.floor(Math.random() * nodeList.length); //NOSONAR
+ selectedNode = nodeList[randomIndex];
+ }
+
+ // If selectedNode exists, set network
+ if (selectedNode) {
+ const network = await NetworkService.getNetworkModelFromNode(selectedNode);
+ try {
+ const nisNodes = getNISNodes(network.type);
+ await dispatchAction({type: 'settings/saveSetSelectedNISNode', payload: nisNodes[0]});
+ } catch {}
+ commit({ type: 'network/setGenerationHash', payload: network.generationHash });
+ commit({ type: 'network/setNetwork', payload: network.type });
+ commit({ type: 'network/setSelectedNode', payload: selectedNode });
+ commit({ type: 'network/setIsLoaded', payload: true });
+ commit({
+ type: 'network/setSelectedNetwork',
+ payload: network,
+ });
+ GlobalListener.setNetwork(network);
}
- const network = await NetworkService.getNetworkModelFromNode(selectedNode);
- try {
- const nisNodes = getNISNodes(network.type);
- await dispatchAction({type: 'settings/saveSetSelectedNISNode', payload: nisNodes[0]});
- } catch {}
- commit({ type: 'network/setGenerationHash', payload: network.generationHash });
- commit({ type: 'network/setNetwork', payload: network.type });
- commit({ type: 'network/setSelectedNode', payload: selectedNode });
- commit({ type: 'network/setIsLoaded', payload: true });
- commit({
- type: 'network/setSelectedNetwork',
- payload: network,
- });
- GlobalListener.setNetwork(network);
await dispatchAction({ type: 'wallet/initState' });
},
+ loadNodeList: async ({ commit }) => {
+ try {
+ // load nodes list from statistic service
+ const [testnetNodes, mainnetNodes] = await Promise.all([
+ NetworkService.getSelectorNodeList('testnet'),
+ NetworkService.getSelectorNodeList('mainnet')
+ ])
+
+ // Assign nodes on the state
+ commit({ type: 'network/setTestnetNodes', payload: testnetNodes });
+ commit({ type: 'network/setMainnetNodes', payload: mainnetNodes });
+ } catch(e) {
+ console.log(e);
+ }
+ },
changeNode: async ({ commit, state, dispatchAction }, payload) => {
const network = await NetworkService.getNetworkModelFromNode(payload);
try {
diff --git a/src/store/news.js b/src/store/news.js
deleted file mode 100644
index ef8e642..0000000
--- a/src/store/news.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import RSSParser from 'rss-parser';
-import { htmlToPlainString, removeRSSContentEnd } from '@src/utils';
-import { formatDate } from '@src/utils/format';
-
-export default {
- namespace: 'news',
- state: {
- isLoading: false,
- news: [],
- },
- mutations: {
- setLoading(state, payload) {
- state.news.isLoading = payload;
- return state;
- },
- setNews(state, payload) {
- state.news.news = payload;
- return state;
- },
- },
- actions: {
- loadNews: async ({ commit }) => {
- commit({ type: 'news/setLoading', payload: true });
- try {
- const response = await fetch('http://rssmix.com/u/11801188/rss.xml');
- const responseText = await response.text();
- const rss = await new RSSParser().parseString(responseText);
- const news = rss.items.map(el => ({
- ...el,
- content: removeRSSContentEnd(htmlToPlainString(el.content)),
- pubDate: formatDate(el.pubDate)
- }));
- commit({ type: 'news/setNews', payload: news});
- } catch (e) {
- console.log('Error loading news');
- commit({ type: 'news/setNews', payload: [] });
- }
- commit({ type: 'news/setLoading', payload: false });
- },
- },
-};
diff --git a/src/store/transaction.js b/src/store/transaction.js
index fb38e9c..b22bc58 100644
--- a/src/store/transaction.js
+++ b/src/store/transaction.js
@@ -81,13 +81,17 @@ export default {
setTimeout(() => {
commit({ type: 'transaction/setLoadingNext', payload: true });
});
+ if((!state.account.cosignatoryOf || !state.account.cosignatoryOf.length) && state.account.multisigGraphInfo !== undefined ){
+ await dispatchAction({ type: 'account/loadCosignatoryOf' });
+ }
const nextPage = state.transaction.page + 1;
const subscription = from(
FetchTransactionService.getTransactionsFromAddress(
state.transaction.addressFilter,
nextPage,
state.transaction.directionFilter,
- state.network.selectedNetwork
+ state.network.selectedNetwork,
+ state.account.cosignatoryOf
)
).subscribe(
transactions => {
diff --git a/src/store/transfer.js b/src/store/transfer.js
index 8d1b1fb..cfb43a0 100644
--- a/src/store/transfer.js
+++ b/src/store/transfer.js
@@ -60,7 +60,7 @@ export default {
const dummyAccount = Account.generateNewAccount(networkType);
const transactionModel = {
type: 'transfer',
- recipientAddress: dummyAccount.address.plain(),
+ recipientAddress: payload.recipientAddress,
messageText: payload.message,
messageEncrypted: payload.messageEncrypted,
mosaics: payload.mosaics,
diff --git a/src/store/wallet.js b/src/store/wallet.js
index e7818bc..826e452 100644
--- a/src/store/wallet.js
+++ b/src/store/wallet.js
@@ -85,12 +85,12 @@ export default {
await AccountSecureStorage.createNewAccount(account);
}
await dispatchAction({ type: 'wallet/reloadAccounts' });
- dispatchAction({ type: 'wallet/loadAccount', payload: state.network.network === 'testnet' ? testnetAccountModel.id : mainnetAccountModel.id });
+ await dispatchAction({ type: 'wallet/loadAccount', payload: state.network.network === 'testnet' ? testnetAccountModel.id : mainnetAccountModel.id });
},
reloadAccounts: async ({ commit, state, dispatchAction }) => {
const accounts = await AccountSecureStorage.getAllAccountsByNetwork(state.network.network);
commit({ type: 'wallet/setAccounts', payload: accounts });
- dispatchAction({ type: 'wallet/loadAccountsBalances' });
+ await dispatchAction({ type: 'wallet/loadAccountsBalances' });
},
loadAccountsBalances: async ({ commit, state }) => {
try {
diff --git a/yarn.lock b/yarn.lock
index fe47199..8230170 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -10233,7 +10233,7 @@ rxjs@^5.4.3:
dependencies:
symbol-observable "1.0.1"
-rxjs@^6.5.2, rxjs@^6.6.0, rxjs@^6.6.3:
+rxjs@^6.5.2, rxjs@^6.6.0, rxjs@^6.6.3, rxjs@^6.6.7:
version "6.6.7"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9"
integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==
@@ -10999,6 +10999,11 @@ symbol-openapi-typescript-fetch-client@0.11.2:
resolved "https://registry.yarnpkg.com/symbol-openapi-typescript-fetch-client/-/symbol-openapi-typescript-fetch-client-0.11.2.tgz#c34b1a2345b567645b802b79b6e8431281a4c938"
integrity sha512-A1MAN8/UWlaCEibBf6zxkduZwDNSvWwLPp6JB0GeYI/FAOrw/9nLyuS/NJQ3siGAUclnuejH1wG7KdUg0/4RSw==
+symbol-openapi-typescript-fetch-client@1.0.1-SNAPSHOT.202106160954:
+ version "1.0.1-SNAPSHOT.202106160954"
+ resolved "https://registry.yarnpkg.com/symbol-openapi-typescript-fetch-client/-/symbol-openapi-typescript-fetch-client-1.0.1-SNAPSHOT.202106160954.tgz#ed0382e54c3c9e72d19f270781949e2c4864a50d"
+ integrity sha512-Aj/lGcQOpBdGSYt5z+0H3o5E75w6llOi+RGS+CRQXF8FqPOIdTuf6KqAoKxCWctGFct3Fii1dDbJPsQrhMFDJg==
+
symbol-paper-wallets@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/symbol-paper-wallets/-/symbol-paper-wallets-1.0.2.tgz#4419834b5e12c9ead0409e1e0a49770917fdce9b"
@@ -11065,6 +11070,32 @@ symbol-sdk@1.0.0:
tweetnacl "^1.0.3"
ws "^7.3.1"
+symbol-sdk@1.0.2-alpha-202108061451:
+ version "1.0.2-alpha-202108061451"
+ resolved "https://registry.yarnpkg.com/symbol-sdk/-/symbol-sdk-1.0.2-alpha-202108061451.tgz#1c2e6f53066fa2667ddaeca326a2a30e0019a2f5"
+ integrity sha512-HH45iZCX8cDDTz4CMSe2PdIAIrTLj5I43AlBYr2k4+SYHS6ZYD2vihQ7RoKjLex+eGz70/JFYmos3RixRQLryw==
+ dependencies:
+ "@js-joda/core" "^3.2.0"
+ bluebird "^3.7.2"
+ catbuffer-typescript "0.1.1"
+ crypto-js "^4.0.0"
+ diff "^4.0.2"
+ futoin-hkdf "^1.3.2"
+ js-sha256 "^0.9.0"
+ js-sha3 "^0.8.0"
+ js-sha512 "^0.8.0"
+ long "^4.0.0"
+ merkletreejs "^0.2.9"
+ minimist "^1.2.5"
+ node-fetch "^2.6.0"
+ ripemd160 "^2.0.2"
+ rxjs "^6.6.7"
+ rxjs-compat "^6.6.3"
+ symbol-openapi-typescript-fetch-client "1.0.1-SNAPSHOT.202106160954"
+ tweetnacl "^1.0.3"
+ utf8 "^2.1.2"
+ ws "^7.3.1"
+
symbol-tree@^3.2.2:
version "3.2.4"
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"
@@ -11650,7 +11681,7 @@ utf-8-validate@^5.0.2:
dependencies:
node-gyp-build "^4.2.0"
-utf8@2.1.2:
+utf8@2.1.2, utf8@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/utf8/-/utf8-2.1.2.tgz#1fa0d9270e9be850d9b05027f63519bf46457d96"
integrity sha1-H6DZJw6b6FDZsFAn9jUZv0ZFfZY=