Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
51dece8b0f | ||
|
|
2452470163 | ||
|
|
edbdb4f239 | ||
|
|
43da3b50de | ||
|
|
a3658de7c2 | ||
|
|
74315ec825 | ||
|
|
4c58f48645 | ||
|
|
c8f4983946 | ||
|
|
ea7fad63a6 | ||
|
|
65352f4253 | ||
|
|
11922b1b02 | ||
|
|
47752593b0 | ||
|
|
8dfaea2bfc | ||
|
|
b288773d15 | ||
|
|
25d9da3144 | ||
|
|
841819d249 | ||
|
|
47fa7f9f0e | ||
|
|
ed2c9e5c41 | ||
|
|
985177dd96 | ||
|
|
95a1a4f9a2 | ||
|
|
e142284713 | ||
|
|
be246413fa | ||
|
|
c7bf1d2ec9 | ||
|
|
48327feb34 | ||
|
|
afa6950f0c | ||
|
|
2adedba064 | ||
|
|
2309998889 | ||
|
|
a8f906a15e | ||
|
|
990d4394af | ||
|
|
66f65052f6 | ||
|
|
9252de79d4 | ||
|
|
a31ef816bd | ||
|
|
2df46e88ce | ||
|
|
050d1966c6 | ||
|
|
b38301efae | ||
|
|
90aa4bad13 | ||
|
|
b6909b132a | ||
|
|
47dede29c3 | ||
|
|
be5ee1a71b | ||
|
|
2b1d612528 | ||
|
|
82315bd349 | ||
|
|
0fa2fe3b32 | ||
|
|
a60d8fa005 | ||
|
|
e5b53991f2 | ||
|
|
8d39fabad7 | ||
|
|
ee6efc5bf8 | ||
|
|
435a9b3cd4 | ||
|
|
e84758440f | ||
|
|
e320d943a6 | ||
|
|
9b0de9f9fb | ||
|
|
dd55faec48 | ||
|
|
c32343671a | ||
|
|
e88351e994 | ||
|
|
2e323be1c3 | ||
|
|
8111ce1ce6 | ||
|
|
f946b7d8fe | ||
|
|
7251b1f763 | ||
|
|
a1aa280cb9 | ||
|
|
a268160ffd | ||
|
|
87187649d1 | ||
|
|
b2ba6aa7ae | ||
|
|
e95dc3932b | ||
|
|
68579a0b86 | ||
|
|
ae447e52c9 | ||
|
|
1d66e071e9 | ||
|
|
e26f9aedb6 | ||
|
|
d83c45cb2f | ||
|
|
b695647acf | ||
|
|
0d179f9d0b | ||
|
|
6e60311ba7 | ||
|
|
a6a7ef040f | ||
|
|
e2637b06a0 | ||
|
|
ec5caf8fe1 | ||
|
|
7428ef8eb7 | ||
|
|
d29edf679e | ||
|
|
175f876101 | ||
|
|
cc4fa53339 | ||
|
|
371262d056 | ||
|
|
cd5a881f32 | ||
|
|
95882ea875 | ||
|
|
3edeae30a0 | ||
|
|
44f7e6a436 | ||
|
|
03033b8d7c | ||
|
|
a25f813f6b | ||
|
|
873ac2a3ee | ||
|
|
ee613b1578 | ||
|
|
6f5adca0cc | ||
|
|
49c4c592f1 | ||
|
|
b5882bf3a4 | ||
|
|
5ad56a9520 | ||
|
|
0afc9908ed | ||
|
|
6c55f6ea53 | ||
|
|
1eef52e286 | ||
|
|
c1644287e1 | ||
|
|
1ceee77b27 | ||
|
|
faea66eed8 | ||
|
|
f211a19eab | ||
|
|
ad9abfb0d8 | ||
|
|
204b0b46ef | ||
|
|
5ddcec777f | ||
|
|
0055d7573b | ||
|
|
92998eb817 | ||
|
|
a11dc52cfe | ||
|
|
b2175a60cd | ||
|
|
9bba6b0c28 | ||
|
|
8865d2a2c5 | ||
|
|
067f1a4fa7 | ||
|
|
15c6b1cef6 | ||
|
|
f49b5a0389 | ||
|
|
5e86263fe3 | ||
|
|
9fce0e2d51 | ||
|
|
6cbabfbe80 | ||
|
|
32c1ca8abf | ||
|
|
31e8904f7a | ||
|
|
1229bedffb | ||
|
|
e69e98182b | ||
|
|
3b71f10d1e | ||
|
|
992eed1bfc | ||
|
|
873b1c40e8 | ||
|
|
7e0171bb9f | ||
|
|
309f652ce6 | ||
|
|
2ba4444ca4 | ||
|
|
826de3ddf0 | ||
|
|
1e4148f2cf | ||
|
|
5827a9702c | ||
|
|
fd11071566 | ||
|
|
7b7d467143 | ||
|
|
170b778dcf | ||
|
|
bc5be9e382 | ||
|
|
6fb91e2e56 | ||
|
|
c29613faed | ||
|
|
7b6ff51186 | ||
|
|
44043a9374 | ||
|
|
e4159028ae | ||
|
|
b6424bdb15 | ||
|
|
9e5a2ac7c5 | ||
|
|
924e69bc7b | ||
|
|
4f025cb9ec | ||
|
|
9902c9351d | ||
|
|
536a6dd877 | ||
|
|
00e702e24f | ||
|
|
7c39f68a1a | ||
|
|
ba9f571c83 | ||
|
|
d12387f4ae | ||
|
|
4bed02e395 | ||
|
|
ee23a50c06 | ||
|
|
7f383fffc9 | ||
|
|
42b421be44 | ||
|
|
121fe3008a | ||
|
|
55fd797707 |
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -1,3 +1,4 @@
|
||||
.eslintrc.js
|
||||
**/build/*
|
||||
**/coverage/*
|
||||
**/node_modules/*
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
const base = require('@polkadot/dev-react/config/eslint');
|
||||
const base = require('@polkadot/dev/config/eslint');
|
||||
|
||||
module.exports = {
|
||||
...base,
|
||||
|
||||
@@ -2,70 +2,15 @@ name: PR
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: Linting
|
||||
runs-on: ubuntu-latest
|
||||
pr:
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [12.x]
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: lint
|
||||
run: |
|
||||
yarn install --frozen-lockfile
|
||||
yarn lint
|
||||
|
||||
test:
|
||||
name: Testing
|
||||
step: ['lint', 'test', 'build', 'docs']
|
||||
name: ${{ matrix.step }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [12.x]
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: test
|
||||
- name: ${{ matrix.step }}
|
||||
run: |
|
||||
yarn install --frozen-lockfile
|
||||
yarn test
|
||||
|
||||
build_code:
|
||||
name: Build Code
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [12.x]
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: build
|
||||
run: |
|
||||
yarn install --frozen-lockfile
|
||||
yarn build
|
||||
|
||||
build_docs:
|
||||
name: Build Docs
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [12.x]
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: build
|
||||
run: |
|
||||
yarn install --frozen-lockfile
|
||||
yarn docs
|
||||
yarn install --immutable | grep -v 'YN0013'
|
||||
yarn ${{ matrix.step }}
|
||||
|
||||
@@ -5,62 +5,30 @@ on:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build_code:
|
||||
name: Build Code
|
||||
if: "! contains(github.event.head_commit.message, '[CI Skip]')"
|
||||
runs-on: ubuntu-latest
|
||||
master:
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [12.x]
|
||||
step: ['build:release', 'docs:release']
|
||||
name: ${{ matrix.step }}
|
||||
if: "! startsWith(github.event.head_commit.message, '[CI Skip]') && github.repository == 'polkadot-js/ui'"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
with:
|
||||
token: ${{ secrets.GH_PAT }}
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: build
|
||||
- name: ${{ matrix.step }}
|
||||
env:
|
||||
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
|
||||
GH_PAGES_SRC: build-docs
|
||||
GH_PAT: ${{ secrets.GH_PAT }}
|
||||
GH_TOKEN: ${{ secrets.GH_PAT }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GH_RELEASE_GITHUB_API_TOKEN: ${{ secrets.GH_PAT }}
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
run: |
|
||||
yarn install --frozen-lockfile
|
||||
yarn polkadot-dev-ghact-build
|
||||
|
||||
build_docs:
|
||||
name: Build Docs
|
||||
if: "! contains(github.event.head_commit.message, '[CI Skip]')"
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [12.x]
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: build
|
||||
env:
|
||||
GH_PAT: ${{ secrets.GH_PAT }}
|
||||
GH_TOKEN: ${{ secrets.GH_PAT }}
|
||||
GH_PAGES_SRC: build-docs
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
yarn install --frozen-lockfile
|
||||
yarn polkadot-dev-ghact-docs
|
||||
yarn install --immutable | grep -v 'YN0013'
|
||||
yarn ${{ matrix.step }}
|
||||
|
||||
dummy:
|
||||
name: Dummy
|
||||
if: "contains(github.event.head_commit.message, '[CI Skip]')"
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [12.x]
|
||||
steps:
|
||||
- name: dummy
|
||||
run: |
|
||||
|
||||
@@ -9,6 +9,10 @@ tmp/
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.npmrc
|
||||
.yarn/*
|
||||
!.yarn/releases
|
||||
!.yarn/plugins
|
||||
.pnp.*
|
||||
cc-test-reporter
|
||||
package-lock.json
|
||||
npm-debug.log*
|
||||
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"editor.tabSize": 2,
|
||||
"files.eol": "\n",
|
||||
"npm.packageManager": "yarn",
|
||||
"eslint.enable": true,
|
||||
"eslint.validate": [
|
||||
"javascript",
|
||||
"typescript",
|
||||
"typescriptreact"
|
||||
]
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
+56
File diff suppressed because one or more lines are too long
+11
@@ -0,0 +1,11 @@
|
||||
enableImmutableInstalls: false
|
||||
|
||||
enableProgressBars: false
|
||||
|
||||
nodeLinker: node-modules
|
||||
|
||||
plugins:
|
||||
- path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.js
|
||||
spec: "@yarnpkg/plugin-interactive-tools"
|
||||
|
||||
yarnPath: .yarn/releases/yarn-rc.js
|
||||
+91
-23
@@ -1,17 +1,77 @@
|
||||
# 0.47.1
|
||||
# CHANGELOG
|
||||
|
||||
## 0.55.1 Jul 2, 2020
|
||||
|
||||
- Better error-handling for invalid FileStore accounts (Thanks to https://github.com/yuhui1208)
|
||||
- Adjust react-qr `Scan*` making `onScan` callbacks required
|
||||
- Rework the react-qr display to use functional components
|
||||
- Bump to `@polkadot/api` 1.21.1
|
||||
- Bump to `@polkadot/util` 2.15.1
|
||||
|
||||
## 0.54.1 Jun 16, 2020
|
||||
|
||||
- Add genesisHash to signer payload (Thanks to https://github.com/hanwencheng)
|
||||
- Allow QR scanning to parse mini keys (Thanks to https://github.com/hanwencheng)
|
||||
- Adjust ordering of available crypto types (native first)
|
||||
- Rename Substrate prefix entry (42) to "generic"
|
||||
- Bump to `@polkadot/api` 1.19.1
|
||||
- Bump to `@polkadot/util` 2.14.1
|
||||
|
||||
## 0.53.1 May 14, 2020
|
||||
|
||||
- Add Ecdsa to the supported crypto types options (Thanks to https://github.com/akru)
|
||||
- Add Egedware to network prefix settings (Thanks to https://github.com/jnaviask)
|
||||
- Add `addMultisig` into keyring (with all options to re-create address)
|
||||
- Bump to `@polkadot/api` 1.14.1
|
||||
- Bump to `@polkadot/util` 2.10.1
|
||||
|
||||
## 0.52.1 Apr 15, 2020
|
||||
|
||||
- **Breaking change** (TypeScript only) The `*.d.ts` files now contain TypeScript 3.8 features, `#private`, which is not usable in older versions
|
||||
- Allow for the encoding of chain-settings via QR (Thanks to https://github.com/hanwencheng)
|
||||
- Enhance checks for ws url in settings (Thanks to https://github.com/kwingram25)
|
||||
- Start of `isAlternative` implementations for identicons to react, react-native & vue (currently only Polkadot sixPoint)
|
||||
- Bump to `@polkadot/api` 1.10 & `@polkadot/util` 2.8
|
||||
- Convert `private <field>` to `#<field>`
|
||||
- Remove internal/duplicated ui-keyring ss58Format mapping, rather set it directly on wrapped keyring
|
||||
|
||||
## 0.51.1 Feb 18, 2020
|
||||
|
||||
- Support formatting of addresses via createPair base on latest upstream keyring
|
||||
- Bump to `@polkadot/api` 1.3.1
|
||||
- Bump to `@polkadot/util` 2.4.1
|
||||
|
||||
## 0.50.1 Feb 16, 2020
|
||||
|
||||
- ui-settings does not expose pre-configured endpoints by default (only local dev node)
|
||||
- Bump to `@polkadot/api` 1.2.1
|
||||
- Bump to `@polkadot/util` 2.3.1
|
||||
|
||||
## 0.49.1 Feb 06, 2020
|
||||
|
||||
- Add resolver for jest requires (tests from src)
|
||||
|
||||
## 0.48.1 Jan 30, 2020
|
||||
|
||||
- Add Westend & Kulupulu, remove Alexander
|
||||
- Update Edgeware wss uri
|
||||
- Change display name for Kusama
|
||||
- Mirror QR scanning display
|
||||
|
||||
## 0.47.1 Nov 29, 2019
|
||||
|
||||
- Support for Kusama CC3 (network endpoints)
|
||||
- Genesis hashes for accounts can now lookup against a range (so CC2-locked accounts will show on CC3)
|
||||
- Language options have been removed from settings (these will be app-specific)
|
||||
- QR display loops now have a timeout decay (slower as it loops)
|
||||
|
||||
# 0.46.1
|
||||
## 0.46.1 Oct 25, 2019
|
||||
|
||||
- Add an example for using React Native (thanks to https://github.com/cameronfr)
|
||||
- Add base documentation for getting started
|
||||
- Add camera access to the setting structure
|
||||
|
||||
# 0.45.1
|
||||
## 0.45.1 Sep 26, 2019
|
||||
|
||||
- Support for Kusama CC2
|
||||
- **Breaking change** The subscription subject for `ui-keyring` does not return a pre-formatted React object anymore. This is SUI-specific, so had limited use and therefore should not even be split into a `react-keyring` component. Rather users of this functionality should construct their own options for their framework.
|
||||
@@ -21,12 +81,12 @@
|
||||
- Adjust `react-identicon` highlights (validators)
|
||||
- Add `example-{react, vue}` highlighting simple use with `ui-keyring`, `ui-settings` & `*-identicon` components
|
||||
|
||||
# 0.44.1
|
||||
## 0.44.1 Sep 12, 2019
|
||||
|
||||
- Update `@polkadot/util` to 1.4.1
|
||||
- Upddate to Babel 7.6
|
||||
|
||||
# 0.43.1
|
||||
## 0.43.1 Sep 10, 2019
|
||||
|
||||
- Add W3F Node for Kusama
|
||||
- Add extended info to ui-settings, i.e. info on each option
|
||||
@@ -34,7 +94,7 @@
|
||||
- ui-keyring now check the genesisHash on all load operations (if supplied)
|
||||
- react-qr is now operational and integrated in the polkadot-js/extension and apps repos
|
||||
|
||||
# 0.42.1
|
||||
## 0.42.1 Aug 24, 2019
|
||||
|
||||
- **Breaking Change** The `@polkadot/ui-identicon` package has been renamed to `@polkadot/react-identicon`
|
||||
- **Breaking change** For `@polkadot/ui-keyring` the stores are now not exported from the index, imports should be changed to either `ui-keyring/stores` or explicitly to `ui-keyring/stores/Extension`
|
||||
@@ -44,7 +104,7 @@
|
||||
- `@polkadot/ui-settings` has UNfrastructure added as an RPC provider for Alex
|
||||
- `@polkadot/ui-settings` exposes a dropdown with address prefix options
|
||||
|
||||
# 0.41.1
|
||||
## 0.41.1 Jun 14, 2019
|
||||
|
||||
- Adapt interface to cater for new `@polkadot/keyring`, where pairs -
|
||||
- expose `address` getter instead of `address()`
|
||||
@@ -56,16 +116,16 @@
|
||||
- Remove previously deprecated kering functions, `createAccount`, `createAccountExternal` & `createAccountMnemonic`
|
||||
- Remove (previously deprecated), `@polkadot/ui-util`, all these functions have been incorporated in `@polkadot/util`
|
||||
|
||||
# 0.40.1
|
||||
## 0.40.1 Jun 04, 2019
|
||||
|
||||
- Address encoding changes, use encoded address instead of supplied
|
||||
|
||||
# 0.39.1
|
||||
## 0.39.1 May 22, 2019
|
||||
|
||||
- Allow for externally injected accounts
|
||||
- @polkadot/util 0.91.1 & @polkadot/api 0.79.1
|
||||
|
||||
# 0.38.1
|
||||
## 0.38.1 May 08, 2019
|
||||
|
||||
- Sorting of keyring addresses
|
||||
- Fix JSON import defaults (previously detection was not working for old accounts)
|
||||
@@ -73,62 +133,70 @@
|
||||
- Ensure only a single instance of ui-keyring is loaded
|
||||
- Adjust short address option display (keyring options)
|
||||
|
||||
# 0.37.1
|
||||
## 0.37.1 Apr 03, 2019
|
||||
|
||||
- Add Emberic Elm (Dried Danta discontinued)
|
||||
- @polkadot/util & @polkadot/api 0.75.1
|
||||
|
||||
# 0.36.1
|
||||
## 0.36.1 Mar 29, 2019
|
||||
|
||||
- Small fixes, latest @polkadot/wasm-* packages
|
||||
|
||||
# 0.35.1
|
||||
## 0.35.1 Mar 29, 2019
|
||||
|
||||
- @polkadot/util & @polkadot/api 0.75.1
|
||||
|
||||
# 0.34.1
|
||||
## 0.34.1 Mar 28, 2019
|
||||
|
||||
- Fix for blake2 in Polkadot identicon generation
|
||||
|
||||
# 0.33.1
|
||||
## 0.33.1 Mar 23, 2019
|
||||
|
||||
- Rename createUri and createExternal to addExternal and addUri
|
||||
- Rename addAccountPair to addPair
|
||||
- Add additional createFromUri function to create pair, but not add it
|
||||
- Latest api, util & util-crypto (this with WASM and JS fallbacks)
|
||||
|
||||
# 0.32.1
|
||||
## 0.32.1 Mar 20, 2019
|
||||
|
||||
- Add createUri to create an account from a path uri
|
||||
- Add createExternal as an alias for createAccountExternal
|
||||
- Deprecate createAccount, createAccountExternal and createAccountMnemonic
|
||||
- Fix styled-component dependencies when used in a non-@polkadot project
|
||||
|
||||
# 0.31.1
|
||||
## 0.31.1 Mar 18, 2019
|
||||
|
||||
- Allow for latest keyring with sr25519 derived support
|
||||
- When using dev mode, it assumes the substrate node has sr25519 derived keys
|
||||
|
||||
# 0.30.1
|
||||
## 0.30.1 Mar 14, 2019
|
||||
|
||||
- Swap to publishing -beta.x on merge (non-breaking testing)
|
||||
|
||||
# 0.29.1
|
||||
## 0.29.1 Mar 13, 2019
|
||||
|
||||
Swap to using a dev HDKD keyring (only available on latest substrate master, only affects nodes running with --dev, normal operation unaffected)
|
||||
|
||||
# 0.28.1
|
||||
## 0.28.1 Feb 21, 2019
|
||||
|
||||
Default Substrate icon is Jdenticon
|
||||
|
||||
# 0.27.1
|
||||
## 0.27.1 Feb 20, 2019
|
||||
|
||||
Replace Charred Cherry with Dried Danta, remove old decimals and token name configs
|
||||
|
||||
# 0.26.1
|
||||
## 0.26.1 Feb 14, 2019
|
||||
|
||||
Add keyring support for sd25519 (schnorrkel)
|
||||
|
||||
# 0.25.1
|
||||
## 0.25.1 Jan 09, 2019
|
||||
|
||||
Add `@polkadot/{keyring,util,util-crypto,types}` as peerDependencies for the various packages as used. Thie should allow less churn on this repo with version bumps, although it does add some extra effort onto the users of these libraries. (But the assumption is that they use these anyway)
|
||||
|
||||
## 0.24.1 Dec 19, 2018
|
||||
|
||||
## 0.23.1 Dec 14, 2018
|
||||
|
||||
## 0.22.1 Dec 05, 2018
|
||||
|
||||
- Split from apps
|
||||
|
||||
+5
-2
@@ -1,5 +1,8 @@
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
const base = require('@polkadot/dev-react/config/babel');
|
||||
// Copyright 2017-2020 @polkadot/ui authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
const base = require('@polkadot/dev/config/babel');
|
||||
|
||||
module.exports = Object.keys(base).reduce((config, key) => {
|
||||
config[key] = base[key];
|
||||
|
||||
@@ -13,7 +13,7 @@ import { u8aToHex } from '@polkadot/util';
|
||||
const accounts = keyring.getAccounts();
|
||||
|
||||
accounts.forEach(({ address, meta, publicKey }) =>
|
||||
console.log(address, JSON.stringify(meta), u8aToHex(publicKey));
|
||||
console.log(address, JSON.stringify(meta), u8aToHex(publicKey))
|
||||
);
|
||||
```
|
||||
|
||||
|
||||
+9
-5
@@ -1,12 +1,16 @@
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const config = require('@polkadot/dev-react/config/jest');
|
||||
// Copyright 2017-2020 @polkadot/ui authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
const config = require('@polkadot/dev/config/jest');
|
||||
|
||||
module.exports = Object.assign({}, config, {
|
||||
moduleNameMapper: {
|
||||
'@polkadot/react-(identicon|qr)(.*)$': '<rootDir>/packages/react-$1/src/$2',
|
||||
'@polkadot/reactnative-(identicon)(.*)$': '<rootDir>/packages/reactnative-$1/src/$2',
|
||||
'@polkadot/ui-(assets|keyring|settings|shared)(.*)$': '<rootDir>/packages/ui-$1/src/$2',
|
||||
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': 'empty/object',
|
||||
'\\.(css|less)$': 'empty/object'
|
||||
}
|
||||
'\\.(css|less)$': 'empty/object',
|
||||
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': 'empty/object'
|
||||
},
|
||||
resolver: './jest.resolver.js'
|
||||
});
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
// Copyright 2017-2020 @polkadot/ui authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
const path = require('path');
|
||||
|
||||
module.exports = function resolver (file, config) {
|
||||
return file.includes('package.json')
|
||||
? path.join(config.basedir.replace('/src', '/'), file)
|
||||
: config.defaultResolver(file, config);
|
||||
};
|
||||
+1
-1
@@ -10,5 +10,5 @@
|
||||
"packages": [
|
||||
"packages/*"
|
||||
],
|
||||
"version": "0.48.1"
|
||||
"version": "0.55.1"
|
||||
}
|
||||
|
||||
+27
-20
@@ -1,40 +1,47 @@
|
||||
{
|
||||
"version": "0.48.1",
|
||||
"repository": "https://github.com/polkadot-js/ui",
|
||||
"author": "Jaco Greeff <jacogr@gmail.com>",
|
||||
"license": "Apache-2",
|
||||
"private": true,
|
||||
"engines": {
|
||||
"yarn": "^1.10.1"
|
||||
},
|
||||
"homepage": ".",
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
],
|
||||
"resolutions": {
|
||||
"babel-core": "^7.0.0-bridge.0",
|
||||
"typescript": "^3.7.5"
|
||||
"babel-core": "^7.0.0-bridge.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "polkadot-dev-build-ts",
|
||||
"build:release": "polkadot-ci-ghact-build",
|
||||
"docs": "polkadot-dev-build-docs",
|
||||
"lint": "eslint --ext .js,.jsx,.ts,.tsx . && tsc --noEmit --pretty",
|
||||
"docs:release": "polkadot-ci-ghact-docs",
|
||||
"lint": "polkadot-dev-run-lint",
|
||||
"clean": "polkadot-dev-clean-build",
|
||||
"demo:identicon:react": "yarn build:ts && webpack-serve --config packages/react-identicon/webpack.config.js --content packages/react-identicon --port 8080",
|
||||
"demo:identicon:vue": "yarn build:ts && webpack-serve --config packages/vue-identicon/webpack.config.js --content packages/vue-identicon --port 8080",
|
||||
"example:rn:packager": "yarn build:split:code && cd packages/exampleReactNative && yarn copy-workspace-packages && yarn start",
|
||||
"demo:identicon:react": "yarn build && webpack-serve --config packages/react-identicon/webpack.config.js --content packages/react-identicon --port 8080",
|
||||
"demo:identicon:vue": "yarn build && webpack-serve --config packages/vue-identicon/webpack.config.js --content packages/vue-identicon --port 8080",
|
||||
"example:rn:packager": "yarn build && cd packages/exampleReactNative && yarn copy-workspace-packages && yarn start",
|
||||
"example:rn:ios": "cd packages/exampleReactNative && cd ios && pod install && cd .. && yarn ios",
|
||||
"example:rn:android": "cd packages/exampleReactNative && yarn android",
|
||||
"example:react": "yarn build:ts && cd packages/example-react && webpack --config webpack.config.js",
|
||||
"example:vue": "yarn build:ts && cd packages/example-vue && webpack --config webpack.config.js",
|
||||
"example:react": "yarn build && cd packages/example-react && webpack --config webpack.config.js",
|
||||
"example:vue": "yarn build && cd packages/example-vue && webpack --config webpack.config.js",
|
||||
"postinstall": "polkadot-dev-yarn-only",
|
||||
"test": "jest --coverage --runInBand",
|
||||
"test:one": "jest"
|
||||
"test": "polkadot-dev-run-test --coverage --runInBand",
|
||||
"test:one": "polkadot-dev-run-test"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.8.3",
|
||||
"@babel/runtime": "^7.8.3",
|
||||
"@polkadot/dev-react": "^0.33.3",
|
||||
"@polkadot/ts": "^0.2.1",
|
||||
"@babel/core": "^7.10.4",
|
||||
"@babel/runtime": "^7.10.4",
|
||||
"@polkadot/dev": "^0.55.18",
|
||||
"@polkadot/ts": "^0.3.27",
|
||||
"@types/jest": "^26.0.3",
|
||||
"babel-plugin-transform-vue-template": "^0.4.2",
|
||||
"empty": "^0.10.1",
|
||||
"react-native": "^0.61.4"
|
||||
}
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
"react-is": "^16.13.1",
|
||||
"react-native": "^0.62.2",
|
||||
"vue-template-compiler": "^2.6.11",
|
||||
"webpack-serve": "^3.2.0"
|
||||
},
|
||||
"version": "0.55.1"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@polkadot/example-react",
|
||||
"version": "0.48.1",
|
||||
"version": "0.55.1",
|
||||
"description": "A very basic example with ui-* & react-* packages",
|
||||
"main": "index.js",
|
||||
"author": "Jaco Greeff <jacogr@gmail.com>",
|
||||
@@ -9,6 +9,6 @@
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.8.3"
|
||||
"@babel/runtime": "^7.10.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Identicon from '@polkadot/react-identicon';
|
||||
import keyring from '@polkadot/ui-keyring';
|
||||
@@ -24,19 +24,27 @@ function App ({ className }: Props): React.ReactElement<Props> | null {
|
||||
const [phrase, setPhrase] = useState<string | null>(null);
|
||||
const [ss58Format, setSS58Format] = useState(42);
|
||||
|
||||
const _onClickNew = (): void => {
|
||||
const phrase = mnemonicGenerate(12);
|
||||
const { address } = keyring.createFromUri(phrase);
|
||||
const _onClickNew = useCallback(
|
||||
(): void => {
|
||||
const phrase = mnemonicGenerate(12);
|
||||
const { address } = keyring.createFromUri(phrase);
|
||||
|
||||
setAddress(keyring.encodeAddress(address, ss58Format));
|
||||
setPhrase(phrase);
|
||||
};
|
||||
const _onChangeSS58Format = ({ currentTarget: { value } }: React.SyntheticEvent<HTMLSelectElement>): void => {
|
||||
setSS58Format(parseInt(value, 10));
|
||||
};
|
||||
setAddress(keyring.encodeAddress(address, ss58Format));
|
||||
setPhrase(phrase);
|
||||
},
|
||||
[ss58Format]
|
||||
);
|
||||
|
||||
const _onChangeSS58Format = useCallback(
|
||||
({ currentTarget: { value } }: React.SyntheticEvent<HTMLSelectElement>): void => {
|
||||
setSS58Format(parseInt(value, 10));
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
useEffect((): void => {
|
||||
_onClickNew();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
useEffect((): void => {
|
||||
@@ -54,13 +62,29 @@ function App ({ className }: Props): React.ReactElement<Props> | null {
|
||||
</section>
|
||||
<section>
|
||||
<label>phrase</label>
|
||||
<textarea cols={40} rows={4} readOnly value={phrase} />
|
||||
<textarea
|
||||
cols={40}
|
||||
readOnly
|
||||
rows={4}
|
||||
value={phrase}
|
||||
/>
|
||||
</section>
|
||||
<section>
|
||||
<label>icons</label>
|
||||
<Identicon className='icon' value={address} />
|
||||
<Identicon className='icon' value={address} theme='polkadot' />
|
||||
<Identicon className='icon' value={address} theme='beachball' />
|
||||
<Identicon
|
||||
className='icon'
|
||||
value={address}
|
||||
/>
|
||||
<Identicon
|
||||
className='icon'
|
||||
theme='polkadot'
|
||||
value={address}
|
||||
/>
|
||||
<Identicon
|
||||
className='icon'
|
||||
theme='beachball'
|
||||
value={address}
|
||||
/>
|
||||
</section>
|
||||
<section>
|
||||
<label>address</label>
|
||||
@@ -68,11 +92,19 @@ function App ({ className }: Props): React.ReactElement<Props> | null {
|
||||
</section>
|
||||
<section>
|
||||
<label>ss58 format</label>
|
||||
<select onChange={_onChangeSS58Format} value={ss58Format}>
|
||||
<select
|
||||
onChange={_onChangeSS58Format}
|
||||
value={ss58Format}
|
||||
>
|
||||
{settings.availablePrefixes
|
||||
.filter((_, index): boolean => index !== 0)
|
||||
.map(({ text, value }): React.ReactNode => (
|
||||
<option key={value} value={value}>{text}</option>
|
||||
<option
|
||||
key={value}
|
||||
value={value}
|
||||
>
|
||||
{text}
|
||||
</option>
|
||||
))
|
||||
}
|
||||
</select>
|
||||
@@ -81,7 +113,9 @@ function App ({ className }: Props): React.ReactElement<Props> | null {
|
||||
);
|
||||
}
|
||||
|
||||
cryptoWaitReady().then((): void => {
|
||||
keyring.loadAll({ ss58Format: 42, type: 'sr25519' });
|
||||
ReactDOM.render(<App />, rootElement);
|
||||
});
|
||||
cryptoWaitReady()
|
||||
.then((): void => {
|
||||
keyring.loadAll({ ss58Format: 42, type: 'sr25519' });
|
||||
ReactDOM.render(<App />, rootElement);
|
||||
})
|
||||
.catch(console.error);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
// Copyright 2017-2020 @polkadot/example-react authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
@@ -11,26 +10,11 @@ module.exports = {
|
||||
devtool: 'cheap-eval-source-map',
|
||||
entry: './src/index.tsx',
|
||||
mode: 'development',
|
||||
output: {
|
||||
chunkFilename: '[name].[chunkhash:8].js',
|
||||
globalObject: '(typeof self !== \'undefined\' ? self : this)',
|
||||
filename: '[name].js',
|
||||
path: path.join(__dirname, 'build')
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
'@polkadot/react-identicon': path.resolve(__dirname, '../react-identicon/build'),
|
||||
'@polkadot/ui-keyring': path.resolve(__dirname, '../ui-keyring/build'),
|
||||
'@polkadot/ui-settings': path.resolve(__dirname, '../ui-settings/build'),
|
||||
'@polkadot/ui-shared': path.resolve(__dirname, '../ui-shared/build')
|
||||
},
|
||||
extensions: ['.js', '.ts', '.tsx']
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(ts|tsx)$/,
|
||||
exclude: /(node_modules)/,
|
||||
test: /\.(ts|tsx)$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'babel-loader',
|
||||
@@ -40,14 +24,29 @@ module.exports = {
|
||||
}
|
||||
]
|
||||
},
|
||||
output: {
|
||||
chunkFilename: '[name].[chunkhash:8].js',
|
||||
filename: '[name].js',
|
||||
globalObject: '(typeof self !== \'undefined\' ? self : this)',
|
||||
path: path.join(__dirname, 'build')
|
||||
},
|
||||
plugins: [
|
||||
new WebpackPluginServe({
|
||||
hmr: false, // switch off, Chrome WASM memory leak
|
||||
liveReload: false, // explict off, overrides hmr
|
||||
progress: false, // since we have hmr off, disable
|
||||
port: 8080,
|
||||
progress: false, // since we have hmr off, disable
|
||||
static: __dirname
|
||||
})
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@polkadot/react-identicon': path.resolve(__dirname, '../react-identicon/build'),
|
||||
'@polkadot/ui-keyring': path.resolve(__dirname, '../ui-keyring/build'),
|
||||
'@polkadot/ui-settings': path.resolve(__dirname, '../ui-settings/build'),
|
||||
'@polkadot/ui-shared': path.resolve(__dirname, '../ui-shared/build')
|
||||
},
|
||||
extensions: ['.js', '.ts', '.tsx']
|
||||
},
|
||||
watch: true
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@polkadot/example-vue",
|
||||
"version": "0.48.1",
|
||||
"version": "0.55.1",
|
||||
"description": "A very basic example with ui-* & vue-* packages",
|
||||
"main": "index.js",
|
||||
"author": "Jaco Greeff <jacogr@gmail.com>",
|
||||
@@ -9,6 +9,6 @@
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.8.3"
|
||||
"@babel/runtime": "^7.10.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,25 @@ function generateAccount (ss58Format: Prefix = 42): Account {
|
||||
}
|
||||
|
||||
const Example = Vue.extend({
|
||||
components: {
|
||||
Identicon
|
||||
},
|
||||
data: function (): Data {
|
||||
return {
|
||||
...generateAccount(),
|
||||
ss58Format: 42,
|
||||
ss58Options
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onClickNew: function (): void {
|
||||
const { address, phrase } = generateAccount(this.ss58Format);
|
||||
|
||||
this.address = address;
|
||||
this.phrase = phrase;
|
||||
}
|
||||
},
|
||||
name: 'Example',
|
||||
template: `
|
||||
<div id="example">
|
||||
<section>
|
||||
@@ -62,25 +81,6 @@ const Example = Vue.extend({
|
||||
</section>
|
||||
</div>
|
||||
`,
|
||||
name: 'Example',
|
||||
components: {
|
||||
Identicon
|
||||
},
|
||||
data: function (): Data {
|
||||
return {
|
||||
...generateAccount(),
|
||||
ss58Format: 42,
|
||||
ss58Options
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onClickNew: function (): void {
|
||||
const { address, phrase } = generateAccount(this.ss58Format);
|
||||
|
||||
this.address = address;
|
||||
this.phrase = phrase;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
ss58Format: function (): void {
|
||||
this.address = keyring.encodeAddress(this.address, this.ss58Format);
|
||||
@@ -88,10 +88,12 @@ const Example = Vue.extend({
|
||||
}
|
||||
});
|
||||
|
||||
cryptoWaitReady().then((): void => {
|
||||
keyring.loadAll({ ss58Format: 42, type: 'sr25519' });
|
||||
cryptoWaitReady()
|
||||
.then((): void => {
|
||||
keyring.loadAll({ ss58Format: 42, type: 'sr25519' });
|
||||
|
||||
new Vue({
|
||||
render: (h): VNode => h(Example)
|
||||
}).$mount('#example');
|
||||
});
|
||||
new Vue({
|
||||
render: (h): VNode => h(Example)
|
||||
}).$mount('#example');
|
||||
})
|
||||
.catch(console.error);
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
// Copyright 2017-2020 @polkadot/example-vue authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const path = require('path');
|
||||
const VueLoaderPlugin = require('vue-loader/lib/plugin');
|
||||
const { WebpackPluginServe } = require('webpack-plugin-serve');
|
||||
@@ -13,12 +11,40 @@ module.exports = {
|
||||
devtool: 'cheap-eval-source-map',
|
||||
entry: './src/index.ts',
|
||||
mode: 'development',
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
exclude: /(node_modules)/,
|
||||
test: /\.(ts|tsx)$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'babel-loader',
|
||||
options: require('../../babel.config.js')
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
loader: 'vue-loader',
|
||||
test: /\.vue$/
|
||||
}
|
||||
]
|
||||
},
|
||||
output: {
|
||||
chunkFilename: '[name].[chunkhash:8].js',
|
||||
globalObject: '(typeof self !== \'undefined\' ? self : this)',
|
||||
filename: '[name].js',
|
||||
globalObject: '(typeof self !== \'undefined\' ? self : this)',
|
||||
path: path.join(__dirname, 'build')
|
||||
},
|
||||
plugins: [
|
||||
new WebpackPluginServe({
|
||||
hmr: false, // switch off, Chrome WASM memory leak
|
||||
liveReload: false, // explict off, overrides hmr
|
||||
port: 8080,
|
||||
progress: false, // since we have hmr off, disable
|
||||
static: __dirname
|
||||
}),
|
||||
new VueLoaderPlugin()
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@polkadot/ui-keyring': path.resolve(__dirname, '../ui-keyring/build'),
|
||||
@@ -28,33 +54,5 @@ module.exports = {
|
||||
},
|
||||
extensions: ['.js', '.ts', '.tsx']
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(ts|tsx)$/,
|
||||
exclude: /(node_modules)/,
|
||||
use: [
|
||||
{
|
||||
loader: 'babel-loader',
|
||||
options: require('../../babel.config.js')
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
test: /\.vue$/,
|
||||
loader: 'vue-loader'
|
||||
}
|
||||
]
|
||||
},
|
||||
plugins: [
|
||||
new WebpackPluginServe({
|
||||
hmr: false, // switch off, Chrome WASM memory leak
|
||||
liveReload: false, // explict off, overrides hmr
|
||||
progress: false, // since we have hmr off, disable
|
||||
port: 8080,
|
||||
static: __dirname
|
||||
}),
|
||||
new VueLoaderPlugin()
|
||||
],
|
||||
watch: true
|
||||
};
|
||||
|
||||
@@ -11,43 +11,48 @@ import settings from '@polkadot/ui-settings';
|
||||
import { mnemonicGenerate, cryptoWaitReady } from '@polkadot/util-crypto';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
scrollView: {
|
||||
backgroundColor: Colors.lighter
|
||||
},
|
||||
body: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access
|
||||
backgroundColor: Colors.white
|
||||
},
|
||||
buttonContainer: {
|
||||
alignItems: 'flex-start',
|
||||
flex: 1,
|
||||
flexDirection: 'column'
|
||||
},
|
||||
mainTitle: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access
|
||||
color: Colors.black,
|
||||
fontSize: 28,
|
||||
fontWeight: '600'
|
||||
},
|
||||
scrollView: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access
|
||||
backgroundColor: Colors.lighter
|
||||
},
|
||||
sectionContainer: {
|
||||
marginTop: 32,
|
||||
paddingHorizontal: 24
|
||||
},
|
||||
sectionTitle: {
|
||||
fontSize: 24,
|
||||
fontWeight: '600',
|
||||
color: Colors.black
|
||||
},
|
||||
mainTitle: {
|
||||
fontSize: 28,
|
||||
fontWeight: '600',
|
||||
color: Colors.black
|
||||
},
|
||||
sectionDescription: {
|
||||
marginTop: 8,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access
|
||||
color: Colors.dark,
|
||||
fontSize: 18,
|
||||
fontWeight: '400',
|
||||
color: Colors.dark
|
||||
marginTop: 8
|
||||
},
|
||||
buttonContainer: {
|
||||
flex: 1,
|
||||
flexDirection: 'column',
|
||||
alignItems: 'flex-start'
|
||||
sectionTitle: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access
|
||||
color: Colors.black,
|
||||
fontSize: 24,
|
||||
fontWeight: '600'
|
||||
}
|
||||
});
|
||||
|
||||
const globalAny = global as unknown as Window;
|
||||
|
||||
export default function App (): React.ReactElement<{}> | null {
|
||||
const [ready, setReady] = useState(false);
|
||||
export default function App (): React.ReactElement | null {
|
||||
const [isReady, setReady] = useState(false);
|
||||
const [address, setAddress] = useState<string | null>(null);
|
||||
const [phrase, setPhrase] = useState<string | null>(null);
|
||||
const [ss58Format, setSS58Format] = useState(42);
|
||||
@@ -65,12 +70,13 @@ export default function App (): React.ReactElement<{}> | null {
|
||||
};
|
||||
|
||||
useEffect((): void => {
|
||||
ready && _onClickNew();
|
||||
}, []);
|
||||
isReady && _onClickNew();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isReady]);
|
||||
|
||||
useEffect((): void => {
|
||||
ready && address && setAddress(keyring.encodeAddress(address, ss58Format));
|
||||
}, [address, ss58Format]);
|
||||
isReady && address && setAddress(keyring.encodeAddress(address, ss58Format));
|
||||
}, [address, isReady, ss58Format]);
|
||||
|
||||
const initialize = async (): Promise<void> => {
|
||||
try {
|
||||
@@ -78,17 +84,21 @@ export default function App (): React.ReactElement<{}> | null {
|
||||
} catch (e) {
|
||||
console.log('Error loading keyring ', e);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
||||
await globalAny.localStorage.init();
|
||||
await cryptoWaitReady();
|
||||
|
||||
setReady(true);
|
||||
_onClickNew();
|
||||
};
|
||||
|
||||
if (!ready) {
|
||||
if (!isReady) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
initialize();
|
||||
}
|
||||
|
||||
if (!ready || !address || !phrase) {
|
||||
if (!isReady || !address || !phrase) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -104,11 +114,17 @@ export default function App (): React.ReactElement<{}> | null {
|
||||
<Text style={styles.mainTitle}>React-Native Example</Text>
|
||||
</View>
|
||||
<View style={styles.sectionContainer}>
|
||||
<Button title='Generate Address' onPress={_onClickNew}></Button>
|
||||
<Button
|
||||
onPress={_onClickNew}
|
||||
title='Generate Address'
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.sectionContainer}>
|
||||
<Text style={styles.sectionTitle}>Phrase</Text>
|
||||
<Text selectable={true} style={styles.sectionDescription}>
|
||||
<Text
|
||||
selectable={true}
|
||||
style={styles.sectionDescription}
|
||||
>
|
||||
{phrase}
|
||||
</Text>
|
||||
</View>
|
||||
@@ -128,8 +144,8 @@ export default function App (): React.ReactElement<{}> | null {
|
||||
.map(({ text, value }): React.ReactNode => (
|
||||
<Button
|
||||
key={value}
|
||||
title={text}
|
||||
onPress={(): void => _onChangeSS58Format(value.toString())}
|
||||
title={text}
|
||||
/>
|
||||
))
|
||||
}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
// Copyright 2017-2020 @polkadot/example-reactnative authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
module.exports = {
|
||||
presets: ['module:metro-react-native-babel-preset']
|
||||
};
|
||||
|
||||
@@ -1,31 +1,27 @@
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
// Copyright 2017-2020 @polkadot/example-reactnative authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
const path = require('path');
|
||||
const getWorkspaces = require('get-yarn-workspaces');
|
||||
const workspaces = getWorkspaces(__dirname).filter(item => {
|
||||
return path.normalize(item) !== path.normalize(__dirname);
|
||||
});
|
||||
let workspacesBuildDirs = workspaces.map(workspace => path.join(workspace, 'build/'));
|
||||
workspacesBuildDirs = workspacesBuildDirs.filter(item => item !== path.join(__dirname, '../reactnative-identicon/build/'));
|
||||
const workspaces = getWorkspaces(__dirname).filter((item) =>
|
||||
path.normalize(item) !== path.normalize(__dirname)
|
||||
);
|
||||
let workspacesBuildDirs = workspaces.map((workspace) => path.join(workspace, 'build/'));
|
||||
|
||||
workspacesBuildDirs = workspacesBuildDirs.filter((item) => item !== path.join(__dirname, '../reactnative-identicon/build/'));
|
||||
|
||||
module.exports = {
|
||||
|
||||
// watch other packages as well as root node_modules
|
||||
watchFolders: [
|
||||
path.resolve(__dirname, '../../node_modules'),
|
||||
...workspacesBuildDirs
|
||||
],
|
||||
|
||||
// remap node packages to react-native packages
|
||||
resolver: {
|
||||
extraNodeModules: {
|
||||
crypto: require.resolve('react-native-crypto'),
|
||||
stream: require.resolve('stream-http'),
|
||||
vm: require.resolve('vm-browserify'),
|
||||
os: require.resolve('os-browserify'),
|
||||
process: require.resolve('process'),
|
||||
os: require.resolve('os-browserify')
|
||||
stream: require.resolve('stream-http'),
|
||||
vm: require.resolve('vm-browserify')
|
||||
}
|
||||
},
|
||||
|
||||
transformer: {
|
||||
getTransformOptions: () => ({
|
||||
transform: {
|
||||
@@ -33,5 +29,10 @@ module.exports = {
|
||||
inlineRequires: false
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
// watch other packages as well as root node_modules
|
||||
watchFolders: [
|
||||
path.resolve(__dirname, '../../node_modules'),
|
||||
...workspacesBuildDirs
|
||||
]
|
||||
};
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
// Copyright 2017-2020 @polkadot/example-react authors & contributors
|
||||
// Copyright 2017-2020 @polkadot/example-reactnative authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
/* eslint-disable no-global-assign */
|
||||
|
||||
import 'fast-text-encoding';
|
||||
import AsyncStorage from '@react-native-community/async-storage';
|
||||
|
||||
@@ -14,26 +16,30 @@ class Storage {
|
||||
init = async () => {
|
||||
const keys = await AsyncStorage.getAllKeys();
|
||||
const data = await AsyncStorage.multiGet(keys);
|
||||
|
||||
data.forEach(this.saveItem.bind(this));
|
||||
this.loading = false;
|
||||
|
||||
return [...data];
|
||||
}
|
||||
|
||||
getItem = key => {
|
||||
getItem = (key) => {
|
||||
return this.dataMap.get(key);
|
||||
}
|
||||
|
||||
setItem = (key, value) => {
|
||||
this.dataMap.set(key, value);
|
||||
|
||||
return AsyncStorage.setItem(key, value);
|
||||
}
|
||||
|
||||
remove = key => {
|
||||
remove = (key) => {
|
||||
this.dataMap.delete(key);
|
||||
|
||||
return AsyncStorage.removeItem(key);
|
||||
}
|
||||
|
||||
saveItem = item => {
|
||||
saveItem = (item) => {
|
||||
this.dataMap.set(item[0], item[1]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "exampleReactNative",
|
||||
"version": "0.48.1",
|
||||
"version": "0.55.1",
|
||||
"private": true,
|
||||
"workspaces": {
|
||||
"nohoist": [
|
||||
@@ -23,28 +23,36 @@
|
||||
"test": "jest"
|
||||
},
|
||||
"dependencies": {
|
||||
"@polkadot/reactnative-identicon": "^0.48.1",
|
||||
"@polkadot/ui-keyring": "^0.48.1",
|
||||
"@polkadot/ui-settings": "^0.48.1",
|
||||
"@react-native-community/async-storage": "^1.7.1",
|
||||
"fast-text-encoding": "^1.0.0",
|
||||
"@polkadot/reactnative-identicon": "0.55.1",
|
||||
"@polkadot/ui-keyring": "0.55.1",
|
||||
"@polkadot/ui-settings": "0.55.1",
|
||||
"@react-native-community/async-storage": "^1.11.0",
|
||||
"fast-text-encoding": "^1.0.3",
|
||||
"get-yarn-workspaces": "^1.0.2",
|
||||
"os-browserify": "^0.3.0",
|
||||
"process": "^0.11.10",
|
||||
"react": "16.12.0",
|
||||
"react-native": "^0.61.4",
|
||||
"react": "16.13.1",
|
||||
"react-native": "^0.62.2",
|
||||
"react-native-crypto": "^2.2.0",
|
||||
"react-native-randombytes": "^3.5.3",
|
||||
"stream-http": "^3.1.0"
|
||||
"stream-http": "^3.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.8.3",
|
||||
"@babel/runtime": "^7.8.3",
|
||||
"@react-native-community/cli-platform-ios": "^3.0.0",
|
||||
"@babel/core": "^7.10.4",
|
||||
"@babel/runtime": "^7.10.4",
|
||||
"@polkadot/keyring": "^2.16.1",
|
||||
"@polkadot/util": "^2.16.1",
|
||||
"@polkadot/util-crypto": "^2.16.1",
|
||||
"@react-native-community/cli-platform-ios": "^4.10.1",
|
||||
"@types/react-test-renderer": "16.9.2",
|
||||
"babel-jest": "^25.1.0",
|
||||
"metro-react-native-babel-preset": "^0.58.0",
|
||||
"react-test-renderer": "16.12.0"
|
||||
"babel-jest": "^26.1.0",
|
||||
"metro-react-native-babel-preset": "^0.60.0",
|
||||
"react-test-renderer": "16.13.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@polkadot/keyring": "*",
|
||||
"@polkadot/util": "*",
|
||||
"@polkadot/util-crypto": "*"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "react-native",
|
||||
|
||||
@@ -12,6 +12,6 @@
|
||||
</head>
|
||||
<body>
|
||||
<div id="demo"></div>
|
||||
<script src="./demo.js"></script>
|
||||
<script src="./build/Demo.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@polkadot/react-identicon",
|
||||
"version": "0.48.1",
|
||||
"version": "0.55.1",
|
||||
"description": "Renders an SVG picture representing an address",
|
||||
"main": "index.js",
|
||||
"author": "Jaco Greeff <jacogr@gmail.com>",
|
||||
@@ -9,23 +9,30 @@
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.8.3",
|
||||
"@polkadot/ui-settings": "^0.48.1",
|
||||
"@polkadot/ui-shared": "^0.48.1",
|
||||
"@types/react-copy-to-clipboard": "^4.3.0",
|
||||
"@babel/runtime": "^7.10.4",
|
||||
"@polkadot/ui-settings": "0.55.1",
|
||||
"@polkadot/ui-shared": "0.55.1",
|
||||
"color": "^3.1.2",
|
||||
"jdenticon": "2.2.0",
|
||||
"react-copy-to-clipboard": "^5.0.2",
|
||||
"styled-components": "^5.0.0"
|
||||
"react-copy-to-clipboard": "^5.0.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@polkadot/keyring": "*",
|
||||
"@polkadot/util": "*",
|
||||
"@polkadot/util-crypto": "*",
|
||||
"react": "*"
|
||||
"react": "*",
|
||||
"react-dom": "*",
|
||||
"react-is": "*",
|
||||
"styled-components": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@polkadot/keyring": "^2.0.1",
|
||||
"@polkadot/util-crypto": "^2.0.1",
|
||||
"@polkadot/keyring": "^2.16.1",
|
||||
"@polkadot/util": "^2.16.1",
|
||||
"@polkadot/util-crypto": "^2.16.1",
|
||||
"@types/react-copy-to-clipboard": "^4.3.0",
|
||||
"@types/react-dom": "^16.9.8",
|
||||
"@types/styled-components": "^5.1.0",
|
||||
"styled-components": "^5.1.1",
|
||||
"xmlserializer": "^0.6.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,13 +20,28 @@ export default class Demo extends React.PureComponent {
|
||||
);
|
||||
}
|
||||
|
||||
return identities.map((value, index): React.ReactNode => (
|
||||
<IdentityIcon
|
||||
key={value.toString()}
|
||||
theme={THEMES[index % THEMES.length] as 'empty'}
|
||||
value={value}
|
||||
/>
|
||||
));
|
||||
return (
|
||||
<div>
|
||||
<div>
|
||||
{identities.map((value, index): React.ReactNode => (
|
||||
<IdentityIcon
|
||||
key={value.toString()}
|
||||
theme={THEMES[index % THEMES.length] as 'empty'}
|
||||
value={value}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div>
|
||||
{THEMES.map((theme): React.ReactNode => (
|
||||
<IdentityIcon
|
||||
key={theme}
|
||||
theme={theme as 'empty'}
|
||||
value='5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,24 +43,20 @@ const Wrapper = styled.div`
|
||||
position: relative;
|
||||
}
|
||||
|
||||
&:before {
|
||||
&.highlight:before {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 0 5px 2px #e0e0e0;
|
||||
content: '';
|
||||
}
|
||||
|
||||
&.highlight:before {
|
||||
box-shadow: 0 0 5px 2px #aaa;
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default class IdentityIcon extends React.PureComponent<Props, State> {
|
||||
class BaseIcon extends React.PureComponent<Props, State> {
|
||||
public state: State = {
|
||||
address: '',
|
||||
publicKey: '0x'
|
||||
@@ -69,10 +65,10 @@ export default class IdentityIcon extends React.PureComponent<Props, State> {
|
||||
private static prefix?: Prefix = undefined;
|
||||
|
||||
public static setDefaultPrefix (prefix: Prefix): void {
|
||||
IdentityIcon.prefix = prefix;
|
||||
BaseIcon.prefix = prefix;
|
||||
}
|
||||
|
||||
public static getDerivedStateFromProps ({ prefix = IdentityIcon.prefix, value }: Props, prevState: State): State | null {
|
||||
public static getDerivedStateFromProps ({ prefix = BaseIcon.prefix, value }: Props, prevState: State): State | null {
|
||||
try {
|
||||
const address = isU8a(value) || isHex(value)
|
||||
? encodeAddress(value, prefix)
|
||||
@@ -110,20 +106,21 @@ export default class IdentityIcon extends React.PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
private getWrapped ({ address, publicKey }: State): React.ReactNode {
|
||||
const { className, isHighlight = false, size = DEFAULT_SIZE, style, theme = settings.icon } = this.props;
|
||||
const { className = '', isAlternative, isHighlight, size = DEFAULT_SIZE, style, theme = settings.icon } = this.props;
|
||||
const Component = !address
|
||||
? Empty
|
||||
: Components[theme === 'default' ? ICON_DEFAULT_HOST : theme] || Fallback;
|
||||
|
||||
return (
|
||||
<Wrapper
|
||||
className={`ui--IdentityIcon ${className}`}
|
||||
className={`ui--IdentityIcon ${className}`}
|
||||
key={address}
|
||||
style={style}
|
||||
>
|
||||
<Component
|
||||
address={address}
|
||||
className={isHighlight ? 'highlight' : ''}
|
||||
isAlternative={isAlternative}
|
||||
publicKey={publicKey}
|
||||
size={size}
|
||||
/>
|
||||
@@ -140,3 +137,9 @@ export default class IdentityIcon extends React.PureComponent<Props, State> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Identicon (props: Props): React.ReactElement<Props> {
|
||||
return <BaseIcon {...props} />;
|
||||
}
|
||||
|
||||
export default React.memo(Identicon);
|
||||
|
||||
@@ -4,29 +4,26 @@
|
||||
|
||||
import { Props } from '../types';
|
||||
|
||||
import React from 'react';
|
||||
import generate from '@polkadot/ui-shared/beachballIcon';
|
||||
import React, { useCallback } from 'react';
|
||||
import { beachballIcon } from '@polkadot/ui-shared';
|
||||
|
||||
export default class Beachball extends React.PureComponent<Props> {
|
||||
public render (): React.ReactNode {
|
||||
const { className, style } = this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`container ${className}`}
|
||||
ref={this.appendIcon}
|
||||
style={style}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
private appendIcon = (node: Element | null): void => {
|
||||
const { address, size } = this.props;
|
||||
|
||||
if (node) {
|
||||
node.appendChild(
|
||||
generate(address, size)
|
||||
function Beachball ({ address, className = '', size, style }: Props): React.ReactElement<Props> {
|
||||
const updateElem = useCallback(
|
||||
(node: HTMLDivElement): void => {
|
||||
node && node.appendChild(
|
||||
beachballIcon(address, { isAlternative: false, size })
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
[address, size]
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`container ${className}`}
|
||||
ref={updateElem}
|
||||
style={style}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(Beachball);
|
||||
|
||||
@@ -6,21 +6,19 @@ import { Props } from '../types';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
export default class Empty extends React.PureComponent<Props> {
|
||||
public render (): React.ReactNode {
|
||||
const { className, size, style } = this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`container ${className}`}
|
||||
style={style}
|
||||
>
|
||||
<svg
|
||||
height={size}
|
||||
viewBox='0 0 64 64'
|
||||
width={size}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
function Empty ({ className = '', size, style }: Props): React.ReactElement<Props> {
|
||||
return (
|
||||
<div
|
||||
className={`container ${className}`}
|
||||
style={style}
|
||||
>
|
||||
<svg
|
||||
height={size}
|
||||
viewBox='0 0 64 64'
|
||||
width={size}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(Empty);
|
||||
|
||||
@@ -7,18 +7,16 @@ import { Props } from '../types';
|
||||
import React from 'react';
|
||||
import jdenticon from 'jdenticon';
|
||||
|
||||
export default class Jdenticon extends React.PureComponent<Props> {
|
||||
public render (): React.ReactNode {
|
||||
const { className, publicKey, size, style } = this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`container ${className}`}
|
||||
style={style}
|
||||
dangerouslySetInnerHTML={ {
|
||||
__html: jdenticon.toSvg(publicKey.substr(2), size)
|
||||
} }
|
||||
/>
|
||||
);
|
||||
}
|
||||
function Jdenticon ({ className = '', publicKey, size, style }: Props): React.ReactElement<Props> {
|
||||
return (
|
||||
<div
|
||||
className={`container ${className}`}
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: jdenticon.toSvg(publicKey.substr(2), size)
|
||||
}}
|
||||
style={style}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(Jdenticon);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright 2018 Paritytech via paritytech/oo7/polkadot-identicon
|
||||
// Copyright 2018 @polkadot/react-identicon authors & contributors
|
||||
// Copyright 2018-2020 @polkadot/react-identicon authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
@@ -16,46 +16,41 @@
|
||||
// - Move constants to file-level
|
||||
// - Overall it is now just a static component, expecting an address as an input value
|
||||
|
||||
import { Props as BaseProps } from '../types';
|
||||
import { Circle } from '@polkadot/ui-shared/icons/types';
|
||||
import { Props } from '../types';
|
||||
|
||||
import React from 'react';
|
||||
import generateIcon, { Circle } from '@polkadot/ui-shared/polkadotIcon';
|
||||
import { polkadotIcon } from '@polkadot/ui-shared';
|
||||
|
||||
interface Props extends BaseProps {
|
||||
sixPoint?: boolean;
|
||||
function renderCircle ({ cx, cy, fill, r }: Circle, key: number): React.ReactNode {
|
||||
return (
|
||||
<circle
|
||||
cx={cx}
|
||||
cy={cy}
|
||||
fill={fill}
|
||||
key={key}
|
||||
r={r}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default class Identicon extends React.PureComponent<Props> {
|
||||
public render (): React.ReactNode {
|
||||
const { address, className, sixPoint, size, style } = this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`container ${className}`}
|
||||
style={style}
|
||||
function Identicon ({ address, className = '', isAlternative = false, size, style }: Props): React.ReactElement<Props> {
|
||||
return (
|
||||
<div
|
||||
className={`container ${className}`}
|
||||
style={style}
|
||||
>
|
||||
<svg
|
||||
height={size}
|
||||
id={address}
|
||||
name={address}
|
||||
viewBox='0 0 64 64'
|
||||
width={size}
|
||||
>
|
||||
<svg
|
||||
id={address}
|
||||
name={address}
|
||||
width={size}
|
||||
height={size}
|
||||
viewBox='0 0 64 64'
|
||||
>
|
||||
{generateIcon(address, sixPoint).map(this.renderCircle)}
|
||||
</svg>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private renderCircle = ({ cx, cy, r, fill }: Circle, key: number): React.ReactNode => {
|
||||
return (
|
||||
<circle
|
||||
key={key}
|
||||
cx={cx}
|
||||
cy={cy}
|
||||
r={r}
|
||||
fill={fill}
|
||||
/>
|
||||
);
|
||||
}
|
||||
{polkadotIcon(address, { isAlternative }).map(renderCircle)}
|
||||
</svg>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(Identicon);
|
||||
|
||||
@@ -1,21 +1,26 @@
|
||||
// Copyright 2018 @polkadot/react-identicon authors & contributors
|
||||
// Copyright 2018-2020 @polkadot/react-identicon authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { Prefix } from '@polkadot/util-crypto/address/types';
|
||||
import React from 'react';
|
||||
|
||||
export interface BaseProps {
|
||||
className?: string;
|
||||
style?: Record<string, string | number>;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
||||
export interface Props extends BaseProps {
|
||||
address: string;
|
||||
isAlternative?: boolean;
|
||||
className?: string;
|
||||
publicKey: string;
|
||||
size: number;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
||||
export interface IdentityProps extends BaseProps {
|
||||
isAlternative?: boolean;
|
||||
isHighlight?: boolean;
|
||||
onCopy?: (value: string) => void;
|
||||
prefix?: Prefix;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const path = require('path');
|
||||
|
||||
const ENV = process.env.NODE_ENV || 'development';
|
||||
@@ -13,27 +12,27 @@ module.exports = {
|
||||
devtool: isProd ? 'source-map' : 'cheap-eval-source-map',
|
||||
entry: './src/Demo.tsx',
|
||||
mode: ENV,
|
||||
output: {
|
||||
path: __dirname,
|
||||
filename: './demo.js'
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
'@polkadot/ui-settings': path.resolve(__dirname, '../ui-settings/build'),
|
||||
'@polkadot/ui-shared': path.resolve(__dirname, '../ui-shared/build')
|
||||
},
|
||||
extensions: ['.js', '.jsx', '.ts', '.tsx']
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(js|ts|tsx)$/,
|
||||
exclude: /(node_modules)/,
|
||||
test: /\.(js|ts|tsx)$/,
|
||||
use: [
|
||||
'babel-loader'
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
plugins: []
|
||||
output: {
|
||||
filename: './Demo.js',
|
||||
path: path.join(__dirname, 'build')
|
||||
},
|
||||
plugins: [],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@polkadot/ui-settings': path.resolve(__dirname, '../ui-settings/build'),
|
||||
'@polkadot/ui-shared': path.resolve(__dirname, '../ui-shared/build')
|
||||
},
|
||||
extensions: ['.js', '.jsx', '.ts', '.tsx']
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@polkadot/react-qr",
|
||||
"version": "0.48.1",
|
||||
"version": "0.55.1",
|
||||
"description": "Generates and reads QR codes",
|
||||
"main": "index.js",
|
||||
"author": "Jaco Greeff <jacogr@gmail.com>",
|
||||
@@ -9,9 +9,19 @@
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.8.3",
|
||||
"@types/react-qr-reader": "^2.1.1",
|
||||
"@babel/runtime": "^7.10.4",
|
||||
"qrcode-generator": "^1.4.4",
|
||||
"react-qr-reader": "^2.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react-qr-reader": "^2.1.3",
|
||||
"@types/styled-components": "^5.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@polkadot/util": "*",
|
||||
"@polkadot/util-crypto": "*",
|
||||
"react": "*",
|
||||
"react-dom": "*",
|
||||
"styled-components": "*"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,27 +2,31 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { BaseProps } from './types';
|
||||
|
||||
import React from 'react';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { xxhashAsHex } from '@polkadot/util-crypto';
|
||||
|
||||
import qrcode from './qrcode';
|
||||
import { createFrames, createImgSize } from './util';
|
||||
|
||||
interface Props extends BaseProps {
|
||||
interface Props {
|
||||
className?: string;
|
||||
size?: string | number;
|
||||
skipEncoding?: boolean;
|
||||
style?: React.CSSProperties;
|
||||
value: Uint8Array;
|
||||
}
|
||||
|
||||
interface State {
|
||||
interface FrameState {
|
||||
frames: Uint8Array[];
|
||||
frameIdx: number;
|
||||
image: string | null;
|
||||
valueHash: string | null;
|
||||
}
|
||||
|
||||
interface TimerState {
|
||||
timerDelay: number;
|
||||
timerId: number | null;
|
||||
valueHash: string | null;
|
||||
}
|
||||
|
||||
const FRAME_DELAY = 2500;
|
||||
@@ -40,99 +44,94 @@ function getDataUrl (value: Uint8Array): string {
|
||||
return qr.createDataURL(16, 0);
|
||||
}
|
||||
|
||||
class Display extends React.PureComponent<Props, State> {
|
||||
public state: State = {
|
||||
frames: [],
|
||||
frameIdx: 0,
|
||||
image: null,
|
||||
timerDelay: FRAME_DELAY,
|
||||
timerId: null,
|
||||
valueHash: null
|
||||
};
|
||||
function Display ({ className, size, skipEncoding, style, value }: Props): React.ReactElement<Props> | null {
|
||||
const [{ image }, setFrameState] = useState<FrameState>({ frameIdx: 0, frames: [], image: null, valueHash: null });
|
||||
const [containerStyle, setContainerStyle] = useState(createImgSize(size));
|
||||
const timerRef = useRef<TimerState>({ timerDelay: FRAME_DELAY, timerId: null });
|
||||
|
||||
public static getDerivedStateFromProps ({ value, skipEncoding = false }: Props, prevState: State): Pick<State, never> | null {
|
||||
const valueHash = xxhashAsHex(value);
|
||||
// run on initial load to setup the global timer and provide and unsubscribe
|
||||
useEffect((): () => void => {
|
||||
const nextFrame = () => setFrameState((state): FrameState => {
|
||||
// when we have a single frame, we only ever fire once
|
||||
if (state.frames.length <= 1) {
|
||||
return state;
|
||||
}
|
||||
|
||||
if (valueHash === prevState.valueHash) {
|
||||
return null;
|
||||
}
|
||||
let frameIdx = state.frameIdx + 1;
|
||||
|
||||
const frames: Uint8Array[] = skipEncoding
|
||||
? [value]
|
||||
: createFrames(value);
|
||||
// when we overflow, skip to the first and slightly increase the delay between frames
|
||||
if (frameIdx === state.frames.length) {
|
||||
frameIdx = 0;
|
||||
timerRef.current.timerDelay = timerRef.current.timerDelay + TIMER_INC;
|
||||
}
|
||||
|
||||
// encode on demand
|
||||
return {
|
||||
frames,
|
||||
frameIdx: 0,
|
||||
image: getDataUrl(frames[0]),
|
||||
valueHash
|
||||
timerRef.current.timerId = setTimeout(nextFrame, timerRef.current.timerDelay);
|
||||
|
||||
// only encode the frames on demand, not above as part of the
|
||||
// state derivation - in the case of large payloads, this should
|
||||
// be slightly more responsive on initial load
|
||||
return {
|
||||
...state,
|
||||
frameIdx,
|
||||
image: getDataUrl(state.frames[frameIdx])
|
||||
};
|
||||
});
|
||||
|
||||
timerRef.current.timerId = window.setTimeout(nextFrame, FRAME_DELAY);
|
||||
|
||||
return (): void => {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
timerRef.current.timerId && clearTimeout(timerRef.current.timerId);
|
||||
};
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
public componentDidMount (): void {
|
||||
this.setState({
|
||||
timerId: window.setTimeout(this.nextFrame, FRAME_DELAY)
|
||||
useEffect((): void => {
|
||||
setContainerStyle(createImgSize(size));
|
||||
}, [size]);
|
||||
|
||||
useEffect((): void => {
|
||||
setFrameState((state): FrameState => {
|
||||
const valueHash = xxhashAsHex(value);
|
||||
|
||||
if (valueHash === state.valueHash) {
|
||||
return state;
|
||||
}
|
||||
|
||||
const frames: Uint8Array[] = skipEncoding
|
||||
? [value]
|
||||
: createFrames(value);
|
||||
|
||||
// encode on demand
|
||||
return {
|
||||
frameIdx: 0,
|
||||
frames,
|
||||
image: getDataUrl(frames[0]),
|
||||
valueHash
|
||||
};
|
||||
});
|
||||
}, [skipEncoding, value]);
|
||||
|
||||
if (!image) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public componentWillUnmount (): void {
|
||||
const { timerId } = this.state;
|
||||
|
||||
if (timerId) {
|
||||
clearTimeout(timerId);
|
||||
}
|
||||
}
|
||||
|
||||
public render (): React.ReactNode {
|
||||
const { className, size, style } = this.props;
|
||||
const { image } = this.state;
|
||||
|
||||
if (!image) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
return (
|
||||
<div
|
||||
className={className}
|
||||
style={containerStyle}
|
||||
>
|
||||
<div
|
||||
className={className}
|
||||
style={createImgSize(size)}
|
||||
className='ui--qr-Display'
|
||||
style={style}
|
||||
>
|
||||
<div
|
||||
className='ui--qr-Display'
|
||||
style={style}
|
||||
>
|
||||
<img src={image} />
|
||||
</div>
|
||||
<img src={image} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private nextFrame = (): void => {
|
||||
const { frames, frameIdx, timerDelay } = this.state;
|
||||
|
||||
if (!frames || frames.length <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const nextIdx = frameIdx === frames.length - 1
|
||||
? 0
|
||||
: frameIdx + 1;
|
||||
const nextDelay = timerDelay + ((nextIdx === 0) ? TIMER_INC : 0);
|
||||
const timerId = setTimeout(this.nextFrame, nextDelay);
|
||||
|
||||
// only encode the frames on demand, not above as part of the
|
||||
// state derivation - in the case of large payloads, this should
|
||||
// be slightly more responsive on initial load
|
||||
this.setState({
|
||||
frameIdx: nextIdx,
|
||||
image: getDataUrl(frames[nextIdx]),
|
||||
timerId,
|
||||
timerDelay: nextDelay
|
||||
});
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default styled(Display as React.ComponentClass<Props>)`
|
||||
export default React.memo(styled(Display)`
|
||||
.ui--qr-Display {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
@@ -146,4 +145,4 @@ export default styled(Display as React.ComponentClass<Props>)`
|
||||
width: auto !important;
|
||||
}
|
||||
}
|
||||
`;
|
||||
`);
|
||||
|
||||
@@ -2,57 +2,39 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { BaseProps } from './types';
|
||||
|
||||
import React from 'react';
|
||||
import { xxhashAsHex } from '@polkadot/util-crypto';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import { createAddressPayload } from './util';
|
||||
import QrDisplay from './Display';
|
||||
|
||||
interface Props extends BaseProps {
|
||||
interface Props {
|
||||
address: string;
|
||||
genesisHash: string;
|
||||
className?: string;
|
||||
size?: string | number;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
||||
interface State {
|
||||
data: Uint8Array | null;
|
||||
dataHash: string | null;
|
||||
}
|
||||
function DisplayExtrinsic ({ address, className, genesisHash, size, style }: Props): React.ReactElement<Props> | null {
|
||||
const [data, setData] = useState<Uint8Array | null>(null);
|
||||
|
||||
export default class DisplayExtrinsic extends React.PureComponent<Props, State> {
|
||||
public state: State = {
|
||||
data: null,
|
||||
dataHash: null
|
||||
};
|
||||
useEffect((): void => {
|
||||
setData(createAddressPayload(address, genesisHash));
|
||||
}, [address, genesisHash]);
|
||||
|
||||
public static getDerivedStateFromProps ({ address, genesisHash }: Props, prevState: State): State | null {
|
||||
const data = createAddressPayload(address, genesisHash);
|
||||
const dataHash = xxhashAsHex(data);
|
||||
|
||||
if (dataHash === prevState.dataHash) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return { data, dataHash };
|
||||
if (!data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public render (): React.ReactNode {
|
||||
const { className, size, style } = this.props;
|
||||
const { data } = this.state;
|
||||
|
||||
if (!data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<QrDisplay
|
||||
className={className}
|
||||
skipEncoding={true}
|
||||
size={size}
|
||||
style={style}
|
||||
value={data}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<QrDisplay
|
||||
className={className}
|
||||
size={size}
|
||||
skipEncoding
|
||||
style={style}
|
||||
value={data}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(DisplayExtrinsic);
|
||||
|
||||
@@ -2,57 +2,40 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { BaseProps } from './types';
|
||||
|
||||
import React from 'react';
|
||||
import { xxhashAsHex } from '@polkadot/util-crypto';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import { createSignPayload } from './util';
|
||||
import QrDisplay from './Display';
|
||||
|
||||
interface Props extends BaseProps {
|
||||
interface Props {
|
||||
address: string;
|
||||
className?: string;
|
||||
cmd: number;
|
||||
genesisHash: Uint8Array | string;
|
||||
payload: Uint8Array;
|
||||
size?: string | number;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
||||
interface State {
|
||||
data: Uint8Array | null;
|
||||
dataHash: string | null;
|
||||
}
|
||||
function DisplayPayload ({ address, className, cmd, genesisHash, payload, size, style }: Props): React.ReactElement<Props> | null {
|
||||
const [data, setData] = useState<Uint8Array | null>(null);
|
||||
|
||||
export default class DisplayPayload extends React.PureComponent<Props, State> {
|
||||
public state: State = {
|
||||
data: null,
|
||||
dataHash: null
|
||||
};
|
||||
useEffect((): void => {
|
||||
setData(createSignPayload(address, cmd, payload, genesisHash));
|
||||
}, [address, cmd, payload, genesisHash]);
|
||||
|
||||
public static getDerivedStateFromProps ({ address, cmd, payload }: Props, prevState: State): State | null {
|
||||
const data = createSignPayload(address, cmd, payload);
|
||||
const dataHash = xxhashAsHex(data);
|
||||
|
||||
if (dataHash === prevState.dataHash) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return { data, dataHash };
|
||||
if (!data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public render (): React.ReactNode {
|
||||
const { className, size, style } = this.props;
|
||||
const { data } = this.state;
|
||||
|
||||
if (!data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<QrDisplay
|
||||
className={className}
|
||||
size={size}
|
||||
style={style}
|
||||
value={data}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<QrDisplay
|
||||
className={className}
|
||||
size={size}
|
||||
style={style}
|
||||
value={data}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(DisplayPayload);
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
// Copyright 2017-2020 @polkadot/react-qr authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { NetworkSpecsStruct } from '@polkadot/ui-settings';
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import QrDisplay from './Display';
|
||||
|
||||
import { encodeString } from './util';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
networkSpecs: NetworkSpecsStruct;
|
||||
size?: string | number;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
||||
function DisplayNetworkSpecs ({ className, networkSpecs, size, style }: Props): React.ReactElement<Props> | null {
|
||||
const [data, setData] = useState<Uint8Array | null>(null);
|
||||
|
||||
useEffect((): void => {
|
||||
setData(encodeString(JSON.stringify(networkSpecs)));
|
||||
}, [networkSpecs]);
|
||||
|
||||
if (!data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<QrDisplay
|
||||
className={className}
|
||||
size={size}
|
||||
skipEncoding
|
||||
style={style}
|
||||
value={data}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(DisplayNetworkSpecs);
|
||||
@@ -2,63 +2,61 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { BaseProps } from './types';
|
||||
|
||||
import React from 'react';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import Reader from 'react-qr-reader';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { createImgSize } from './util';
|
||||
|
||||
interface Props extends BaseProps {
|
||||
interface Props {
|
||||
className?: string;
|
||||
delay?: number;
|
||||
onError?: (error: Error) => void;
|
||||
onScan?: (data: string) => void;
|
||||
onScan: (data: string) => void;
|
||||
size?: string | number;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
||||
const DEFAULT_DELAY = 150;
|
||||
|
||||
const DEFAULT_ERROR = (error: Error): void => {
|
||||
console.error('@polkadot/react-qr:Scan', error.message);
|
||||
};
|
||||
|
||||
class Scan extends React.PureComponent<Props> {
|
||||
public render (): React.ReactNode {
|
||||
const { className, delay = DEFAULT_DELAY, size, style } = this.props;
|
||||
function Scan ({ className, delay = DEFAULT_DELAY, onError = DEFAULT_ERROR, onScan, size, style }: Props): React.ReactElement<Props> {
|
||||
const [containerStyle, setContainerStyle] = useState(createImgSize(size));
|
||||
|
||||
return (
|
||||
<div
|
||||
className={className}
|
||||
style={createImgSize(size)}
|
||||
>
|
||||
<Reader
|
||||
className='ui--qr-Scan'
|
||||
delay={delay}
|
||||
onError={this.onError}
|
||||
onScan={this.onScan}
|
||||
style={style}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
useEffect((): void => {
|
||||
setContainerStyle(createImgSize(size));
|
||||
}, [size]);
|
||||
|
||||
private onError = (error: Error): void => {
|
||||
const { onError = DEFAULT_ERROR } = this.props;
|
||||
const _onError = useCallback(
|
||||
(error: Error) => onError(error),
|
||||
[onError]
|
||||
);
|
||||
|
||||
onError(error);
|
||||
}
|
||||
const _onScan = useCallback(
|
||||
(data: string | null) => data && onScan(data),
|
||||
[onScan]
|
||||
);
|
||||
|
||||
private onScan = (data: string | null): void => {
|
||||
const { onScan } = this.props;
|
||||
|
||||
if (!data || !onScan) {
|
||||
return;
|
||||
}
|
||||
|
||||
onScan(data);
|
||||
}
|
||||
return (
|
||||
<div
|
||||
className={className}
|
||||
style={containerStyle}
|
||||
>
|
||||
<Reader
|
||||
className='ui--qr-Scan'
|
||||
delay={delay}
|
||||
onError={_onError}
|
||||
onScan={_onScan}
|
||||
style={style}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default styled(Scan)`
|
||||
export default React.memo(styled(Scan)`
|
||||
.ui--qr-Scan {
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
@@ -69,4 +67,4 @@ export default styled(Scan)`
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
`;
|
||||
`);
|
||||
|
||||
@@ -2,57 +2,62 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { BaseProps } from './types';
|
||||
|
||||
import React from 'react';
|
||||
import React, { useCallback } from 'react';
|
||||
import { assert } from '@polkadot/util';
|
||||
|
||||
import { ADDRESS_PREFIX } from './constants';
|
||||
import QrScan from './Scan';
|
||||
import { decodeAddress } from '@polkadot/util-crypto';
|
||||
|
||||
import { ADDRESS_PREFIX, SEED_PREFIX } from './constants';
|
||||
import QrScan from './Scan';
|
||||
|
||||
interface ScanType {
|
||||
address: string;
|
||||
isAddress: boolean;
|
||||
content: string;
|
||||
genesisHash: string;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
interface Props extends BaseProps {
|
||||
interface Props {
|
||||
className?: string;
|
||||
onError?: (error: Error) => void;
|
||||
onScan?: (scanned: ScanType) => void;
|
||||
onScan: (scanned: ScanType) => void;
|
||||
size?: string | number;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
||||
export default class ScanAddress extends React.PureComponent<Props> {
|
||||
public render (): React.ReactNode {
|
||||
const { className, onError, size, style } = this.props;
|
||||
function ScanAddress ({ className, onError, onScan, size, style }: Props): React.ReactElement<Props> {
|
||||
const _onScan = useCallback(
|
||||
(data: string | null): void => {
|
||||
if (data) {
|
||||
try {
|
||||
const [prefix, content, genesisHash, name] = data.split(':');
|
||||
const isValidPrefix = prefix === ADDRESS_PREFIX || prefix === SEED_PREFIX;
|
||||
|
||||
return (
|
||||
<QrScan
|
||||
className={className}
|
||||
onError={onError}
|
||||
onScan={this.onScan}
|
||||
size={size}
|
||||
style={style}
|
||||
/>
|
||||
);
|
||||
}
|
||||
assert(isValidPrefix, `Invalid prefix received, expected '${ADDRESS_PREFIX}/${SEED_PREFIX}' , found '${prefix}'`);
|
||||
|
||||
private onScan = (data: string | null): void => {
|
||||
const { onScan } = this.props;
|
||||
const isAddress = prefix === ADDRESS_PREFIX;
|
||||
|
||||
if (!data || !onScan) {
|
||||
return;
|
||||
}
|
||||
if (isAddress) {
|
||||
decodeAddress(content);
|
||||
}
|
||||
|
||||
try {
|
||||
const [prefix, address, genesisHash, name] = data.split(':');
|
||||
onScan({ content, genesisHash, isAddress, name });
|
||||
} catch (error) {
|
||||
console.error('@polkadot/react-qr:QrScanAddress', (error as Error).message, data);
|
||||
}
|
||||
}
|
||||
},
|
||||
[onScan]
|
||||
);
|
||||
|
||||
assert(prefix === ADDRESS_PREFIX, `Invalid address received, expected '${ADDRESS_PREFIX}', found '${prefix}'`);
|
||||
|
||||
decodeAddress(address);
|
||||
onScan({ address, genesisHash, name });
|
||||
} catch (error) {
|
||||
console.error('@polkadot/react-qr:QrScanAddress', error.message, data);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<QrScan
|
||||
className={className}
|
||||
onError={onError}
|
||||
onScan={_onScan}
|
||||
size={size}
|
||||
style={style}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(ScanAddress);
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { BaseProps } from './types';
|
||||
|
||||
import React from 'react';
|
||||
import React, { useCallback } from 'react';
|
||||
|
||||
import QrScan from './Scan';
|
||||
|
||||
@@ -12,33 +10,29 @@ interface ScanType {
|
||||
signature: string;
|
||||
}
|
||||
|
||||
interface Props extends BaseProps {
|
||||
interface Props {
|
||||
className?: string;
|
||||
onError?: (error: Error) => void;
|
||||
onScan?: (scanned: ScanType) => void;
|
||||
onScan: (scanned: ScanType) => void;
|
||||
size?: string | number;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
||||
export default class ScanSignature extends React.PureComponent<Props> {
|
||||
public render (): React.ReactNode {
|
||||
const { className, onError, size, style } = this.props;
|
||||
function ScanSignature ({ className, onError, onScan, size, style }: Props): React.ReactElement<Props> {
|
||||
const _onScan = useCallback(
|
||||
(signature: string | null) => signature && onScan({ signature: `0x${signature}` }),
|
||||
[onScan]
|
||||
);
|
||||
|
||||
return (
|
||||
<QrScan
|
||||
className={className}
|
||||
onError={onError}
|
||||
onScan={this.onScan}
|
||||
size={size}
|
||||
style={style}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
private onScan = (signature: string | null): void => {
|
||||
const { onScan } = this.props;
|
||||
|
||||
if (!signature || !onScan) {
|
||||
return;
|
||||
}
|
||||
|
||||
onScan({ signature: `0x${signature}` });
|
||||
}
|
||||
return (
|
||||
<QrScan
|
||||
className={className}
|
||||
onError={onError}
|
||||
onScan={_onScan}
|
||||
size={size}
|
||||
style={style}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(ScanSignature);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
const ADDRESS_PREFIX = 'substrate';
|
||||
const SEED_PREFIX = 'secret';
|
||||
const FRAME_SIZE = 1024;
|
||||
const SUBSTRATE_ID = new Uint8Array([0x53]);
|
||||
const CRYPTO_SR25519 = new Uint8Array([0x01]);
|
||||
@@ -19,5 +20,6 @@ export {
|
||||
CMD_SIGN_MSG,
|
||||
CRYPTO_SR25519,
|
||||
FRAME_SIZE,
|
||||
SEED_PREFIX,
|
||||
SUBSTRATE_ID
|
||||
};
|
||||
|
||||
@@ -6,3 +6,4 @@ export { default as QrDisplayAddress } from './DisplayAddress';
|
||||
export { default as QrDisplayPayload } from './DisplayPayload';
|
||||
export { default as QrScanAddress } from './ScanAddress';
|
||||
export { default as QrScanSignature } from './ScanSignature';
|
||||
export { default as QrNetworkSpecs } from './NetworkSpecs';
|
||||
|
||||
@@ -9,7 +9,7 @@ const qrcode: typeof _qrcode = _qrcode;
|
||||
|
||||
// HACK The default function take string -> number[], the Uint8array is compatible
|
||||
// with that signature and the use thereof
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-member-access
|
||||
(qrcode as any).stringToBytes = (data: Uint8Array): Uint8Array =>
|
||||
data;
|
||||
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
// Copyright 2017-2020 @polkadot/react-qr authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
export interface BaseProps {
|
||||
className?: string;
|
||||
size?: string | number;
|
||||
style?: Record<string, string | number>;
|
||||
}
|
||||
@@ -64,7 +64,7 @@ describe('util', (): void => {
|
||||
it('encodes a payload properly', (): void => {
|
||||
expect(
|
||||
u8aToHex(
|
||||
createSignPayload('5HbgaJEuVN5qGbkhgtuDQANivSWwHXWsC2erP1SQUXgciTVq', 3, 'THIS IS SPARTA!')
|
||||
createSignPayload('5HbgaJEuVN5qGbkhgtuDQANivSWwHXWsC2erP1SQUXgciTVq', 3, 'THIS IS SPARTA!', '0xb0a8d493285c2df73290dfb7e61f870f17b41801197a149ca93654499ea3dafe')
|
||||
)
|
||||
).toEqual(
|
||||
'0x' + // prefix
|
||||
@@ -72,7 +72,8 @@ describe('util', (): void => {
|
||||
'01' + // sr25519
|
||||
'03' + // sign tx
|
||||
'f4cd755672a8f9542ca9da4fbf2182e79135d94304002e6a09ffc96fef6e6c4c' + // publickey
|
||||
'544849532049532053504152544121' // THIS IS SPARTA!
|
||||
'544849532049532053504152544121' + // THIS IS SPARTA!
|
||||
'b0a8d493285c2df73290dfb7e61f870f17b41801197a149ca93654499ea3dafe' // genesisHash
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -81,7 +82,7 @@ describe('util', (): void => {
|
||||
it('encodes frames properly', (): void => {
|
||||
expect(
|
||||
createFrames(
|
||||
createSignPayload('5HbgaJEuVN5qGbkhgtuDQANivSWwHXWsC2erP1SQUXgciTVq', 0, '0x12345678')
|
||||
createSignPayload('5HbgaJEuVN5qGbkhgtuDQANivSWwHXWsC2erP1SQUXgciTVq', 0, '0x12345678', '0xb0a8d493285c2df73290dfb7e61f870f17b41801197a149ca93654499ea3dafe')
|
||||
).map((u8a): string => u8aToHex(u8a))
|
||||
).toEqual([
|
||||
'0x' +
|
||||
@@ -90,7 +91,8 @@ describe('util', (): void => {
|
||||
'0000' + // index
|
||||
'530100' + // payload info, substrate + sr25519 + signtx
|
||||
'f4cd755672a8f9542ca9da4fbf2182e79135d94304002e6a09ffc96fef6e6c4c' + // publicKey
|
||||
'12345678' // data
|
||||
'12345678' + // data
|
||||
'b0a8d493285c2df73290dfb7e61f870f17b41801197a149ca93654499ea3dafe' // genesisHash
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -33,13 +33,14 @@ export function createAddressPayload (address: string, genesisHash: string): Uin
|
||||
return encodeString(`${ADDRESS_PREFIX}:${address}:${genesisHash}`);
|
||||
}
|
||||
|
||||
export function createSignPayload (address: string, cmd: number, payload: string | Uint8Array): Uint8Array {
|
||||
export function createSignPayload (address: string, cmd: number, payload: string | Uint8Array, genesisHash: string | Uint8Array): Uint8Array {
|
||||
return u8aConcat(
|
||||
SUBSTRATE_ID,
|
||||
CRYPTO_SR25519,
|
||||
new Uint8Array([cmd]),
|
||||
decodeAddress(address),
|
||||
u8aToU8a(payload)
|
||||
u8aToU8a(payload),
|
||||
u8aToU8a(genesisHash)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@polkadot/reactnative-identicon",
|
||||
"version": "0.48.1",
|
||||
"version": "0.55.1",
|
||||
"description": "Renders an SVG picture representing an address",
|
||||
"main": "index.js",
|
||||
"author": "Jaco Greeff <jacogr@gmail.com>",
|
||||
@@ -9,12 +9,17 @@
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.8.3",
|
||||
"@polkadot/ui-shared": "^0.48.1",
|
||||
"react-native-svg": "^11.0.1"
|
||||
"@babel/runtime": "^7.10.4",
|
||||
"@polkadot/ui-shared": "0.55.1",
|
||||
"react-native-svg": "^12.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@polkadot/util-crypto": "*",
|
||||
"react": "*",
|
||||
"react-native": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@polkadot/util-crypto": "^2.16.1",
|
||||
"@types/react-native": "^0.62.16"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ export default function Empty ({ size }: Props): React.ReactElement<Props> {
|
||||
<Circle
|
||||
cx='32'
|
||||
cy='32'
|
||||
r='32'
|
||||
fill='#eee'
|
||||
r='32'
|
||||
/>
|
||||
</Svg>
|
||||
</View>
|
||||
|
||||
@@ -1,40 +1,37 @@
|
||||
// Copyright 2018 @polkadot/reactnative-identicon authors & contributors
|
||||
// Copyright 2018-2020 @polkadot/reactnative-identicon authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { Props as BaseProps } from '../types';
|
||||
import { Circle as CircleType } from '@polkadot/ui-shared/icons/types';
|
||||
import { Props } from '../types';
|
||||
|
||||
import React from 'react';
|
||||
import { View } from 'react-native';
|
||||
import Svg, { Circle as SvgCircle } from 'react-native-svg';
|
||||
import generateIcon, { Circle as CircleType } from '@polkadot/ui-shared/polkadotIcon';
|
||||
import { polkadotIcon } from '@polkadot/ui-shared';
|
||||
|
||||
interface Props extends BaseProps {
|
||||
sixPoint?: boolean;
|
||||
}
|
||||
|
||||
function renderCircle ({ cx, cy, r, fill }: CircleType, key: number): React.ReactNode {
|
||||
function renderCircle ({ cx, cy, fill, r }: CircleType, key: number): React.ReactNode {
|
||||
return (
|
||||
<SvgCircle
|
||||
key={key}
|
||||
cx={cx}
|
||||
cy={cy}
|
||||
r={r}
|
||||
fill={fill}
|
||||
key={key}
|
||||
r={r}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default function Identicon ({ address, sixPoint, size }: Props): React.ReactElement<Props> {
|
||||
export default function Identicon ({ address, isAlternative = false, size }: Props): React.ReactElement<Props> {
|
||||
return (
|
||||
<View>
|
||||
<Svg
|
||||
height={size}
|
||||
id={address}
|
||||
width={size}
|
||||
viewBox='0 0 64 64'
|
||||
width={size}
|
||||
>
|
||||
{generateIcon(address, sixPoint).map(renderCircle)}
|
||||
{polkadotIcon(address, { isAlternative }).map(renderCircle)}
|
||||
</Svg>
|
||||
</View>
|
||||
);
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
// Copyright 2018 @polkadot/reactnative-identicon authors & contributors
|
||||
// Copyright 2018-2020 @polkadot/reactnative-identicon authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
export interface Props {
|
||||
address: string;
|
||||
isAlternative?: boolean;
|
||||
publicKey: string;
|
||||
size: number;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@polkadot/ui-assets",
|
||||
"version": "0.48.1",
|
||||
"version": "0.55.1",
|
||||
"description": "Static assets shared accross projects",
|
||||
"main": "index.js",
|
||||
"author": "Jaco Greeff <jacogr@gmail.com>",
|
||||
@@ -9,6 +9,6 @@
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.8.3"
|
||||
"@babel/runtime": "^7.10.4"
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@polkadot/ui-keyring",
|
||||
"version": "0.48.1",
|
||||
"version": "0.55.1",
|
||||
"main": "index.js",
|
||||
"repository": "https://github.com/polkadot-js/apps.git",
|
||||
"author": "Jaco Greeff <jacogr@gmail.com>",
|
||||
@@ -10,36 +10,35 @@
|
||||
"contributors": [],
|
||||
"license": "Apache-2.0",
|
||||
"browser": {
|
||||
"../package.json": "./package.json",
|
||||
"./ledger/transportsNode": "./ledger/transportsEmpty"
|
||||
},
|
||||
"react-native": {
|
||||
"../package.json": "./package.json",
|
||||
"./ledger/transportsNode": "./ledger/transportsEmpty",
|
||||
"./ledger/transportsWeb": "./ledger/transportsEmpty"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.8.3",
|
||||
"@ledgerhq/hw-transport-u2f": "^5.7.0",
|
||||
"@ledgerhq/hw-transport-webusb": "^5.7.0",
|
||||
"@types/ledgerhq__hw-transport-node-hid": "^4.21.1",
|
||||
"@types/ledgerhq__hw-transport-u2f": "^4.21.1",
|
||||
"@types/mkdirp": "^0.5.2",
|
||||
"@types/store": "^2.0.2",
|
||||
"extensionizer": "^1.0.1",
|
||||
"ledger-polkadot": "^0.7.0",
|
||||
"mkdirp": "^1.0.3",
|
||||
"@babel/runtime": "^7.10.4",
|
||||
"@ledgerhq/hw-transport-webusb": "^5.17.0",
|
||||
"@zondax/ledger-polkadot": "^0.10.4",
|
||||
"mkdirp": "^1.0.4",
|
||||
"rxjs": "^6.6.0",
|
||||
"store": "^2.0.12"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@polkadot/keyring": "^2.0.1",
|
||||
"@polkadot/types": "^1.0.1",
|
||||
"@polkadot/util": "^2.0.1"
|
||||
"@polkadot/keyring": "^2.16.1",
|
||||
"@polkadot/types": "^1.23.0-beta.3",
|
||||
"@polkadot/util": "^2.16.1",
|
||||
"@types/ledgerhq__hw-transport-node-hid": "^4.22.1",
|
||||
"@types/ledgerhq__hw-transport-webusb": "^4.70.0",
|
||||
"@types/mkdirp": "^1.0.1",
|
||||
"@types/store": "^2.0.2"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@ledgerhq/hw-transport-node-hid": "^5.7.0"
|
||||
"@ledgerhq/hw-transport-node-hid": "^5.18.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@polkadot/keyring": "*"
|
||||
"@polkadot/keyring": "*",
|
||||
"@polkadot/ui-settings": "*",
|
||||
"@polkadot/util": "*"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,42 +18,40 @@ import BrowserStore from './stores/Browser'; // direct import (skip index with a
|
||||
import { MAX_PASS_LEN } from './defaults';
|
||||
|
||||
export default class Base {
|
||||
private _accounts: AddressSubject;
|
||||
#accounts: AddressSubject;
|
||||
|
||||
private _addresses: AddressSubject;
|
||||
#addresses: AddressSubject;
|
||||
|
||||
private _contracts: AddressSubject;
|
||||
#contracts: AddressSubject;
|
||||
|
||||
private _keyring?: KeyringInstance;
|
||||
#keyring?: KeyringInstance;
|
||||
|
||||
protected _store: KeyringStore;
|
||||
|
||||
protected _genesisHash?: string;
|
||||
|
||||
protected _store!: KeyringStore;
|
||||
|
||||
private _ss58Format?: Prefix;
|
||||
|
||||
constructor () {
|
||||
this._accounts = accounts;
|
||||
this._addresses = addresses;
|
||||
this._contracts = contracts;
|
||||
this._keyring = undefined;
|
||||
this.#accounts = accounts;
|
||||
this.#addresses = addresses;
|
||||
this.#contracts = contracts;
|
||||
this._store = new BrowserStore();
|
||||
}
|
||||
|
||||
public get accounts (): AddressSubject {
|
||||
return this._accounts;
|
||||
return this.#accounts;
|
||||
}
|
||||
|
||||
public get addresses (): AddressSubject {
|
||||
return this._addresses;
|
||||
return this.#addresses;
|
||||
}
|
||||
|
||||
public get contracts (): AddressSubject {
|
||||
return this._contracts;
|
||||
return this.#contracts;
|
||||
}
|
||||
|
||||
public get keyring (): KeyringInstance {
|
||||
if (this._keyring) {
|
||||
return this._keyring;
|
||||
if (this.#keyring) {
|
||||
return this.#keyring;
|
||||
}
|
||||
|
||||
throw new Error('Keyring should be initialised via \'loadAll\' before use');
|
||||
@@ -96,8 +94,10 @@ export default class Base {
|
||||
return password.length > 0 && password.length <= MAX_PASS_LEN;
|
||||
}
|
||||
|
||||
public setSS58Format (ss58Format: Prefix): void {
|
||||
this._ss58Format = ss58Format;
|
||||
public setSS58Format (ss58Format?: Prefix): void {
|
||||
if (this.#keyring && ss58Format) {
|
||||
this.#keyring.setSS58Format(ss58Format);
|
||||
}
|
||||
}
|
||||
|
||||
public setDevMode (isDevelopment: boolean): void {
|
||||
@@ -105,15 +105,15 @@ export default class Base {
|
||||
}
|
||||
|
||||
protected initKeyring (options: KeyringOptions): void {
|
||||
const keyring = testKeyring({ ss58Format: this._ss58Format, ...options }, true);
|
||||
const keyring = testKeyring(options, true);
|
||||
|
||||
if (isBoolean(options.isDevelopment)) {
|
||||
this.setDevMode(options.isDevelopment);
|
||||
}
|
||||
|
||||
this._keyring = keyring;
|
||||
this.#keyring = keyring;
|
||||
this._genesisHash = options.genesisHash && options.genesisHash.toHex();
|
||||
this._store = options.store || new BrowserStore();
|
||||
this._store = options.store || this._store;
|
||||
|
||||
this.addAccountPairs();
|
||||
}
|
||||
|
||||
@@ -7,9 +7,11 @@ import { KeypairType } from '@polkadot/util-crypto/types';
|
||||
import { AddressSubject, SingleAddress } from './observable/types';
|
||||
import { CreateResult, KeyringAddress, KeyringAddressType, KeyringItemType, KeyringJson, KeyringJson$Meta, KeyringOptions, KeyringStruct } from './types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import createPair from '@polkadot/keyring/pair';
|
||||
import chains from '@polkadot/ui-settings/defaults/chains';
|
||||
import { hexToU8a, isHex, isString } from '@polkadot/util';
|
||||
import { bnToBn, hexToU8a, isHex, isString, u8aSorted } from '@polkadot/util';
|
||||
import { createKeyMulti } from '@polkadot/util-crypto';
|
||||
|
||||
import env from './observable/development';
|
||||
import Base from './Base';
|
||||
@@ -22,10 +24,10 @@ const RECENT_EXPIRY = 24 * 60 * 60;
|
||||
// Chain determination occurs outside of Keyring. Loading `keyring.loadAll({ type: 'ed25519' | 'sr25519' })` is triggered
|
||||
// from the API after the chain is received
|
||||
export class Keyring extends Base implements KeyringStruct {
|
||||
private stores = {
|
||||
#stores = {
|
||||
account: (): AddressSubject => this.accounts,
|
||||
address: (): AddressSubject => this.addresses,
|
||||
contract: (): AddressSubject => this.contracts,
|
||||
account: (): AddressSubject => this.accounts
|
||||
contract: (): AddressSubject => this.contracts
|
||||
};
|
||||
|
||||
public addExternal (address: string | Uint8Array, meta: KeyringPair$Meta = {}): CreateResult {
|
||||
@@ -41,6 +43,15 @@ export class Keyring extends Base implements KeyringStruct {
|
||||
return this.addExternal(address, { ...meta, hardwareType, isHardware: true });
|
||||
}
|
||||
|
||||
public addMultisig (addresses: (string | Uint8Array)[], threshold: BigInt | BN | number, meta: KeyringPair$Meta = {}): CreateResult {
|
||||
const address = createKeyMulti(addresses, threshold);
|
||||
|
||||
// we could use `sortAddresses`, but rather use internal encode/decode so we are 100%
|
||||
const who = u8aSorted(addresses.map((who) => this.decodeAddress(who))).map((who) => this.encodeAddress(who));
|
||||
|
||||
return this.addExternal(address, { ...meta, isMultisig: true, threshold: bnToBn(threshold).toNumber(), who });
|
||||
}
|
||||
|
||||
public addPair (pair: KeyringPair, password: string): CreateResult {
|
||||
this.keyring.addPair(pair);
|
||||
|
||||
@@ -114,16 +125,16 @@ export class Keyring extends Base implements KeyringStruct {
|
||||
: this.encodeAddress(_address);
|
||||
const publicKey = this.decodeAddress(address);
|
||||
const stores = type
|
||||
? [this.stores[type]]
|
||||
: Object.values(this.stores);
|
||||
? [this.#stores[type]]
|
||||
: Object.values(this.#stores);
|
||||
|
||||
const info = stores.reduce<SingleAddress | undefined>((lastInfo, store): SingleAddress | undefined =>
|
||||
(store().subject.getValue()[address] || lastInfo), undefined);
|
||||
|
||||
return info && {
|
||||
address,
|
||||
publicKey,
|
||||
meta: info.json.meta
|
||||
meta: info.json.meta,
|
||||
publicKey
|
||||
};
|
||||
}
|
||||
|
||||
@@ -177,6 +188,7 @@ export class Keyring extends Base implements KeyringStruct {
|
||||
|
||||
if (isRecent && (Date.now() - whenCreated) > RECENT_EXPIRY) {
|
||||
this._store.remove(key);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -263,11 +275,8 @@ export class Keyring extends Base implements KeyringStruct {
|
||||
public restoreAccount (json: KeyringPair$Json, password: string): KeyringPair {
|
||||
const type = Array.isArray(json.encoding.content) ? json.encoding.content[1] : 'ed25519';
|
||||
const pair = createPair(
|
||||
type,
|
||||
{
|
||||
// FIXME Just for the transition period (ignoreChecksum)
|
||||
publicKey: this.decodeAddress(json.address, true)
|
||||
},
|
||||
{ toSS58: this.encodeAddress, type },
|
||||
{ publicKey: this.decodeAddress(json.address, true) },
|
||||
json.meta,
|
||||
hexToU8a(json.encoded)
|
||||
);
|
||||
@@ -319,7 +328,7 @@ export class Keyring extends Base implements KeyringStruct {
|
||||
|
||||
delete json.meta.isRecent;
|
||||
|
||||
this.stores[type]().add(this._store, address, json);
|
||||
this.#stores[type]().add(this._store, address, json);
|
||||
|
||||
return json as KeyringPair$Json;
|
||||
}
|
||||
|
||||
@@ -7,15 +7,8 @@ import { detectPackage } from '@polkadot/util';
|
||||
import keyring, { Keyring } from './Keyring';
|
||||
import Ledger from './ledger';
|
||||
|
||||
let pkgJson;
|
||||
|
||||
try {
|
||||
pkgJson = require('./package.json');
|
||||
} catch (error) {
|
||||
pkgJson = require('../package.json');
|
||||
}
|
||||
|
||||
detectPackage(pkgJson);
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
detectPackage(require('./package.json'), typeof __dirname !== 'undefined' && __dirname);
|
||||
|
||||
export default keyring;
|
||||
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import Transport from '@ledgerhq/hw-transport';
|
||||
import { LedgerAddress, LedgerSignature, LedgerTypes, LedgerVersion } from './types';
|
||||
|
||||
import LedgerApp, { ResponseBase } from 'ledger-polkadot';
|
||||
import { ResponseBase, SubstrateApp, newKusamaApp, newPolkadotApp } from '@zondax/ledger-polkadot';
|
||||
import { assert, bufferToU8a, u8aToBuffer, u8aToHex } from '@polkadot/util';
|
||||
|
||||
import allNode from './transportsNode';
|
||||
@@ -20,46 +21,59 @@ const SUCCESS_CODE = 0x9000;
|
||||
|
||||
const transports = allNode.concat(allWeb);
|
||||
|
||||
const APPS: Record<string, (transport: Transport) => SubstrateApp> = {
|
||||
kusama: newKusamaApp,
|
||||
polkadot: newPolkadotApp
|
||||
};
|
||||
|
||||
type Chain = keyof typeof APPS;
|
||||
|
||||
// A very basic wrapper for a ledger app -
|
||||
// - it connects automatically, creating an app as required
|
||||
// - Promises return errors (instead of wrapper errors)
|
||||
export default class Ledger {
|
||||
private app: LedgerApp | null = null;
|
||||
private type: LedgerTypes;
|
||||
#app: SubstrateApp | null = null;
|
||||
|
||||
constructor (type: LedgerTypes) {
|
||||
assert(['hid', 'u2f', 'webusb'].includes(type), `Unsupported transport ${type}`);
|
||||
#chain: Chain;
|
||||
|
||||
this.type = type;
|
||||
#transport: LedgerTypes;
|
||||
|
||||
constructor (transport: LedgerTypes, chain: Chain) {
|
||||
// u2f is deprecated
|
||||
assert(['hid', 'webusb'].includes(transport), `Unsupported transport ${transport}`);
|
||||
assert(Object.keys(APPS).includes(chain), `Unsupported chain ${chain}`);
|
||||
|
||||
this.#chain = chain;
|
||||
this.#transport = transport;
|
||||
}
|
||||
|
||||
private async getApp (): Promise<LedgerApp> {
|
||||
if (!this.app) {
|
||||
const def = transports.find(({ type }): boolean => type === this.type);
|
||||
private async _getApp (): Promise<SubstrateApp> {
|
||||
if (!this.#app) {
|
||||
const def = transports.find(({ type }) => type === this.#transport);
|
||||
|
||||
assert(def, `Unable to find a transport for ${this.type}`);
|
||||
assert(def, `Unable to find a transport for ${this.#transport}`);
|
||||
|
||||
const transport = await def.create();
|
||||
|
||||
this.app = new LedgerApp(transport);
|
||||
this.#app = APPS[this.#chain](transport);
|
||||
}
|
||||
|
||||
return this.app;
|
||||
return this.#app;
|
||||
}
|
||||
|
||||
private async withApp <T> (fn: (app: LedgerApp) => Promise<T>): Promise<T> {
|
||||
private async _withApp <T> (fn: (app: SubstrateApp) => Promise<T>): Promise<T> {
|
||||
try {
|
||||
const app = await this.getApp();
|
||||
const app = await this._getApp();
|
||||
|
||||
return await fn(app);
|
||||
} catch (error) {
|
||||
this.app = null;
|
||||
this.#app = null;
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
private async wrapError <T extends ResponseBase> (promise: Promise<T>): Promise<T> {
|
||||
private async _wrapError <T extends ResponseBase> (promise: Promise<T>): Promise<T> {
|
||||
const result = await promise;
|
||||
|
||||
assert(result.return_code === SUCCESS_CODE, result.error_message);
|
||||
@@ -68,8 +82,8 @@ export default class Ledger {
|
||||
}
|
||||
|
||||
public async getAddress (confirm = false, account = LEDGER_DEFAULT_ACCOUNT, change = LEDGER_DEFAULT_CHANGE, addressIndex = LEDGER_DEFAULT_INDEX): Promise<LedgerAddress> {
|
||||
return this.withApp(async (app: LedgerApp): Promise<LedgerAddress> => {
|
||||
const { address, pubKey } = await this.wrapError(app.getAddress(account, change, addressIndex, confirm));
|
||||
return this._withApp(async (app: SubstrateApp): Promise<LedgerAddress> => {
|
||||
const { address, pubKey } = await this._wrapError(app.getAddress(account, change, addressIndex, confirm));
|
||||
|
||||
return {
|
||||
address,
|
||||
@@ -79,8 +93,8 @@ export default class Ledger {
|
||||
}
|
||||
|
||||
public async getVersion (): Promise<LedgerVersion> {
|
||||
return this.withApp(async (app: LedgerApp): Promise<LedgerVersion> => {
|
||||
const { device_locked: isLocked, major, minor, patch, test_mode: isTestMode } = await this.wrapError(app.getVersion());
|
||||
return this._withApp(async (app: SubstrateApp): Promise<LedgerVersion> => {
|
||||
const { device_locked: isLocked, major, minor, patch, test_mode: isTestMode } = await this._wrapError(app.getVersion());
|
||||
|
||||
return {
|
||||
isLocked,
|
||||
@@ -91,9 +105,9 @@ export default class Ledger {
|
||||
}
|
||||
|
||||
public async sign (message: Uint8Array, account = LEDGER_DEFAULT_ACCOUNT, change = LEDGER_DEFAULT_CHANGE, addressIndex = LEDGER_DEFAULT_INDEX): Promise<LedgerSignature> {
|
||||
return this.withApp(async (app: LedgerApp): Promise<LedgerSignature> => {
|
||||
return this._withApp(async (app: SubstrateApp): Promise<LedgerSignature> => {
|
||||
const buffer = u8aToBuffer(message);
|
||||
const { signature } = await this.wrapError(app.sign(account, change, addressIndex, buffer));
|
||||
const { signature } = await this._wrapError(app.sign(account, change, addressIndex, buffer));
|
||||
|
||||
return {
|
||||
signature: u8aToHex(bufferToU8a(signature))
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
declare module '@ledgerhq/hw-transport-webusb';
|
||||
@@ -5,15 +5,16 @@
|
||||
import { TransportDef } from './types';
|
||||
|
||||
import Transport from '@ledgerhq/hw-transport';
|
||||
import LedgerU2F from '@ledgerhq/hw-transport-u2f';
|
||||
import LedgerWebUSB from '@ledgerhq/hw-transport-webusb';
|
||||
|
||||
const transports: TransportDef[] = [
|
||||
{
|
||||
create: (): Promise<Transport> =>
|
||||
LedgerU2F.create(),
|
||||
type: 'u2f'
|
||||
},
|
||||
// deprecated
|
||||
// import LedgerU2F from '@ledgerhq/hw-transport-u2f';
|
||||
// {
|
||||
// create: (): Promise<Transport> =>
|
||||
// LedgerU2F.create(),
|
||||
// type: 'u2f'
|
||||
// },
|
||||
{
|
||||
create: (): Promise<Transport> =>
|
||||
LedgerWebUSB.create(),
|
||||
|
||||
@@ -40,8 +40,8 @@ class KeyringOption implements KeyringOptionInstance {
|
||||
|
||||
public createOptionHeader (name: string): KeyringSectionOption {
|
||||
return {
|
||||
name,
|
||||
key: `header-${name.toLowerCase()}`,
|
||||
name,
|
||||
value: null
|
||||
};
|
||||
}
|
||||
@@ -131,9 +131,9 @@ class KeyringOption implements KeyringOptionInstance {
|
||||
return {
|
||||
account: [],
|
||||
address: [],
|
||||
contract: [],
|
||||
all: [],
|
||||
allPlus: [],
|
||||
contract: [],
|
||||
recent: [],
|
||||
testing: []
|
||||
};
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
import { KeyringItemType, KeyringStruct } from '../types';
|
||||
|
||||
export interface KeyringSectionOption {
|
||||
className?: string;
|
||||
disabled?: boolean;
|
||||
key: string | null;
|
||||
name: string;
|
||||
value: string | null;
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
// Copyright 2019 @polkadot/ui-keyring authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { KeyringStore, KeyringJson } from '../types';
|
||||
|
||||
import extension from 'extensionizer';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
type StoreValue = Record<string, any>;
|
||||
|
||||
const lastError = (type: string): void => {
|
||||
const error = extension.runtime.lastError;
|
||||
|
||||
if (error) {
|
||||
console.error(`ExtensionStore.${type}:: runtime.lastError:`, error);
|
||||
}
|
||||
};
|
||||
|
||||
export default class ExtensionStore implements KeyringStore {
|
||||
public all (cb: (key: string, value: KeyringJson) => void): void {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
extension.storage.local.get(null, (result: StoreValue): void => {
|
||||
lastError('all');
|
||||
|
||||
Object.entries(result).forEach(([key, value]): void => {
|
||||
cb(key, value);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public get (key: string, cb: (value: KeyringJson) => void): void {
|
||||
extension.storage.local.get([key], (result: StoreValue): void => {
|
||||
lastError('get');
|
||||
|
||||
cb(result[key]);
|
||||
});
|
||||
}
|
||||
|
||||
public remove (key: string, cb?: () => void): void {
|
||||
extension.storage.local.remove(key, (): void => {
|
||||
lastError('remove');
|
||||
|
||||
cb && cb();
|
||||
});
|
||||
}
|
||||
|
||||
public set (key: string, value: KeyringJson, cb?: () => void): void {
|
||||
// shortcut, don't save testing accounts in extension storage
|
||||
if (key.startsWith('account:') && value.meta && value.meta.isTesting) {
|
||||
cb && cb();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
extension.storage.local.set({ [key]: value }, (): void => {
|
||||
lastError('set');
|
||||
|
||||
cb && cb();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -7,30 +7,37 @@ import { KeyringStore, KeyringJson } from '../types';
|
||||
import fs from 'fs';
|
||||
import mkdirp from 'mkdirp';
|
||||
import path from 'path';
|
||||
import { assert } from '@polkadot/util';
|
||||
|
||||
// NOTE untested and unused by any known apps, probably broken in various mysterious ways
|
||||
export default class FileStore implements KeyringStore {
|
||||
private _path: string;
|
||||
#path: string;
|
||||
|
||||
constructor (path: string) {
|
||||
if (!fs.existsSync(path)) {
|
||||
mkdirp.sync(path);
|
||||
}
|
||||
|
||||
this._path = path;
|
||||
this.#path = path;
|
||||
}
|
||||
|
||||
public all (cb: (key: string, value: KeyringJson) => void): void {
|
||||
fs
|
||||
.readdirSync(this._path)
|
||||
.filter((key): boolean => !['.', '..'].includes(key))
|
||||
.readdirSync(this.#path)
|
||||
.filter((key): boolean => !['.', '..', '.DS_Store'].includes(key))
|
||||
.forEach((key): void => {
|
||||
cb(key, this._readKey(key));
|
||||
const value = this._readKey(key);
|
||||
|
||||
value?.address && cb(key, value);
|
||||
});
|
||||
}
|
||||
|
||||
public get (key: string, cb: (value: KeyringJson) => void): void {
|
||||
cb(this._readKey(key));
|
||||
const value = this._readKey(key);
|
||||
|
||||
assert(value?.address, `Invalid JSON found for ${key}`);
|
||||
|
||||
cb(value);
|
||||
}
|
||||
|
||||
public remove (key: string, cb?: () => void): void {
|
||||
@@ -44,12 +51,18 @@ export default class FileStore implements KeyringStore {
|
||||
}
|
||||
|
||||
private _getPath (key: string): string {
|
||||
return path.join(this._path, key);
|
||||
return path.join(this.#path, key);
|
||||
}
|
||||
|
||||
private _readKey (key: string): KeyringJson {
|
||||
return JSON.parse(
|
||||
fs.readFileSync(this._getPath(key)).toString('utf-8')
|
||||
);
|
||||
private _readKey (key: string): KeyringJson | undefined {
|
||||
try {
|
||||
return JSON.parse(
|
||||
fs.readFileSync(this._getPath(key)).toString('utf-8')
|
||||
) as KeyringJson;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,5 +3,4 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
export { default as BrowserStore } from './Browser';
|
||||
export { default as ExtensionStore } from './Extension';
|
||||
export { default as FileStore } from './File';
|
||||
|
||||
@@ -26,7 +26,6 @@ export interface KeyringOptions extends KeyringOptionsBase {
|
||||
store?: KeyringStore;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/class-name-casing
|
||||
export interface KeyringJson$Meta {
|
||||
contract?: ContractMeta;
|
||||
genesisHash?: string | null;
|
||||
@@ -39,8 +38,7 @@ export interface KeyringJson$Meta {
|
||||
whenCreated?: number;
|
||||
whenEdited?: number;
|
||||
whenUsed?: number;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
[index: string]: any;
|
||||
[index: string]: unknown;
|
||||
}
|
||||
|
||||
export interface KeyringJson {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@polkadot/ui-settings",
|
||||
"version": "0.48.1",
|
||||
"version": "0.55.1",
|
||||
"description": "Manages app settings",
|
||||
"main": "index.js",
|
||||
"author": "Jaco Greeff <jacogr@gmail.com>",
|
||||
@@ -9,12 +9,13 @@
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.8.3",
|
||||
"@types/store": "^2.0.2",
|
||||
"@babel/runtime": "^7.10.4",
|
||||
"eventemitter3": "^4.0.4",
|
||||
"store": "^2.0.12"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@polkadot/util": "^2.0.1"
|
||||
"@polkadot/util": "^2.16.1",
|
||||
"@types/store": "^2.0.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@polkadot/util": "*"
|
||||
|
||||
@@ -12,77 +12,85 @@ import { Option, SettingsStruct } from './types';
|
||||
type ChangeCallback = (settings: SettingsStruct) => void;
|
||||
type OnTypes = 'change';
|
||||
|
||||
function withDefault (options: Option[], option: string | undefined, fallback: string): string {
|
||||
const _option = option || fallback;
|
||||
|
||||
return options.some(({ value }) => value === _option)
|
||||
? _option
|
||||
: fallback;
|
||||
}
|
||||
|
||||
export class Settings implements SettingsStruct {
|
||||
private _apiUrl: string;
|
||||
readonly #emitter: EventEmitter;
|
||||
|
||||
private _camera: string;
|
||||
#apiUrl: string;
|
||||
|
||||
private _emitter: EventEmitter;
|
||||
#camera: string;
|
||||
|
||||
private _i18nLang: string;
|
||||
#i18nLang: string;
|
||||
|
||||
private _icon: string;
|
||||
#icon: string;
|
||||
|
||||
private _ledgerConn: string;
|
||||
#ledgerConn: string;
|
||||
|
||||
private _locking: string;
|
||||
#locking: string;
|
||||
|
||||
private _prefix: number;
|
||||
#prefix: number;
|
||||
|
||||
private _uiMode: string;
|
||||
#uiMode: string;
|
||||
|
||||
private _uiTheme: string;
|
||||
#uiTheme: string;
|
||||
|
||||
constructor () {
|
||||
const settings = store.get('settings') || {};
|
||||
const settings = (store.get('settings') as SettingsStruct) || {};
|
||||
|
||||
this._emitter = new EventEmitter();
|
||||
this.#emitter = new EventEmitter();
|
||||
|
||||
this._apiUrl = settings.apiUrl || process.env.WS_URL || ENDPOINT_DEFAULT;
|
||||
this._camera = settings.camera || CAMERA_DEFAULT;
|
||||
this._ledgerConn = settings.ledgerConn || LEDGER_CONN_DEFAULT;
|
||||
this._i18nLang = settings.i18nLang || LANGUAGE_DEFAULT;
|
||||
this._icon = settings.icon || ICON_DEFAULT;
|
||||
this._locking = settings.locking || LOCKING_DEFAULT;
|
||||
this._prefix = isUndefined(settings.prefix) ? PREFIX_DEFAULT : settings.prefix;
|
||||
this._uiMode = settings.uiMode || UIMODE_DEFAULT;
|
||||
this._uiTheme = settings.uiTheme || UITHEME_DEFAULT;
|
||||
this.#apiUrl = (typeof settings.apiUrl === 'string' && settings.apiUrl) || process.env.WS_URL || (ENDPOINT_DEFAULT.value as string);
|
||||
this.#camera = withDefault(CAMERA, settings.camera, CAMERA_DEFAULT);
|
||||
this.#ledgerConn = withDefault(LEDGER_CONN, settings.ledgerConn, LEDGER_CONN_DEFAULT);
|
||||
this.#i18nLang = settings.i18nLang || LANGUAGE_DEFAULT;
|
||||
this.#icon = settings.icon || ICON_DEFAULT;
|
||||
this.#locking = settings.locking || LOCKING_DEFAULT;
|
||||
this.#prefix = isUndefined(settings.prefix) ? PREFIX_DEFAULT : settings.prefix;
|
||||
this.#uiMode = settings.uiMode || UIMODE_DEFAULT;
|
||||
this.#uiTheme = settings.uiTheme || UITHEME_DEFAULT;
|
||||
}
|
||||
|
||||
public get camera (): string {
|
||||
return this._camera;
|
||||
return this.#camera;
|
||||
}
|
||||
|
||||
public get apiUrl (): string {
|
||||
return this._apiUrl;
|
||||
return this.#apiUrl;
|
||||
}
|
||||
|
||||
public get i18nLang (): string {
|
||||
return this._i18nLang;
|
||||
return this.#i18nLang;
|
||||
}
|
||||
|
||||
public get icon (): string {
|
||||
return this._icon;
|
||||
return this.#icon;
|
||||
}
|
||||
|
||||
public get ledgerConn (): string {
|
||||
return this._ledgerConn;
|
||||
return this.#ledgerConn;
|
||||
}
|
||||
|
||||
public get locking (): string {
|
||||
return this._locking;
|
||||
return this.#locking;
|
||||
}
|
||||
|
||||
public get prefix (): number {
|
||||
return this._prefix;
|
||||
return this.#prefix;
|
||||
}
|
||||
|
||||
public get uiMode (): string {
|
||||
return this._uiMode;
|
||||
return this.#uiMode;
|
||||
}
|
||||
|
||||
public get uiTheme (): string {
|
||||
return this._uiTheme;
|
||||
return this.#uiTheme;
|
||||
}
|
||||
|
||||
public get availableCamera (): Option[] {
|
||||
@@ -123,37 +131,37 @@ export class Settings implements SettingsStruct {
|
||||
|
||||
public get (): SettingsStruct {
|
||||
return {
|
||||
apiUrl: this._apiUrl,
|
||||
camera: this._camera,
|
||||
i18nLang: this._i18nLang,
|
||||
icon: this._icon,
|
||||
ledgerConn: this._ledgerConn,
|
||||
locking: this._locking,
|
||||
prefix: this._prefix,
|
||||
uiMode: this._uiMode,
|
||||
uiTheme: this._uiTheme
|
||||
apiUrl: this.#apiUrl,
|
||||
camera: this.#camera,
|
||||
i18nLang: this.#i18nLang,
|
||||
icon: this.#icon,
|
||||
ledgerConn: this.#ledgerConn,
|
||||
locking: this.#locking,
|
||||
prefix: this.#prefix,
|
||||
uiMode: this.#uiMode,
|
||||
uiTheme: this.#uiTheme
|
||||
};
|
||||
}
|
||||
|
||||
public set (settings: Partial<SettingsStruct>): void {
|
||||
this._apiUrl = settings.apiUrl || this._apiUrl;
|
||||
this._camera = settings.camera || this._camera;
|
||||
this._ledgerConn = settings.ledgerConn || this._ledgerConn;
|
||||
this._i18nLang = settings.i18nLang || this._i18nLang;
|
||||
this._icon = settings.icon || this._icon;
|
||||
this._locking = settings.locking || this._locking;
|
||||
this._prefix = isUndefined(settings.prefix) ? this._prefix : settings.prefix;
|
||||
this._uiMode = settings.uiMode || this._uiMode;
|
||||
this._uiTheme = settings.uiTheme || this._uiTheme;
|
||||
this.#apiUrl = settings.apiUrl || this.#apiUrl;
|
||||
this.#camera = settings.camera || this.#camera;
|
||||
this.#ledgerConn = settings.ledgerConn || this.#ledgerConn;
|
||||
this.#i18nLang = settings.i18nLang || this.#i18nLang;
|
||||
this.#icon = settings.icon || this.#icon;
|
||||
this.#locking = settings.locking || this.#locking;
|
||||
this.#prefix = isUndefined(settings.prefix) ? this.#prefix : settings.prefix;
|
||||
this.#uiMode = settings.uiMode || this.#uiMode;
|
||||
this.#uiTheme = settings.uiTheme || this.#uiTheme;
|
||||
|
||||
const newValues = this.get();
|
||||
|
||||
store.set('settings', newValues);
|
||||
this._emitter.emit('change', newValues);
|
||||
this.#emitter.emit('change', newValues);
|
||||
}
|
||||
|
||||
public on (type: OnTypes, cb: ChangeCallback): void {
|
||||
this._emitter.on(type, cb);
|
||||
this.#emitter.on(type, cb);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,9 @@ const chains: Record<string, ChainDef> = {
|
||||
'0x3fd7b9eb6a00376e5be61f01abb429ffb0b104be05eaff4d458da48fcd425baf', // Kusama CC1
|
||||
'0xe3777fa922cafbff200cadeaea1a76bd7898ad5b89f7848999058b50e715f636', // Kusama CC2
|
||||
'0xb0a8d493285c2df73290dfb7e61f870f17b41801197a149ca93654499ea3dafe' // Kusama CC3
|
||||
],
|
||||
polkadot: [
|
||||
'0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3' // Polkadot CC1
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
@@ -5,14 +5,19 @@
|
||||
import { Option } from '../types';
|
||||
|
||||
export const CRYPTOS: Option[] = [
|
||||
{
|
||||
info: 'sr25519',
|
||||
text: 'Schnorrkel (sr25519, recommended)',
|
||||
value: 'sr25519'
|
||||
},
|
||||
{
|
||||
info: 'ed25519',
|
||||
text: 'Edwards (ed25519)',
|
||||
text: 'Edwards (ed25519, alternative)',
|
||||
value: 'ed25519'
|
||||
},
|
||||
{
|
||||
info: 'sr25519',
|
||||
text: 'Schnorrkel (sr25519)',
|
||||
value: 'sr25519'
|
||||
info: 'ecdsa',
|
||||
text: 'ECDSA (BTC/ETH compatible)',
|
||||
value: 'ecdsa'
|
||||
}
|
||||
];
|
||||
|
||||
@@ -4,132 +4,10 @@
|
||||
|
||||
import { Option } from '../types';
|
||||
|
||||
import { isPolkadot } from './type';
|
||||
|
||||
type ChainName = 'alexander' | 'edgeware' | 'edgewareTest' | 'flamingFir' | 'kusama' | 'kulupu' | 'westend';
|
||||
|
||||
interface ChainData {
|
||||
chainDisplay: string;
|
||||
logo: 'alexander' | 'edgeware' | 'kusama' | 'polkadot' | 'substrate';
|
||||
type: string;
|
||||
}
|
||||
|
||||
type ProviderName = 'commonwealth' | 'parity' | 'unfrastructure' | 'w3f' | 'kulupu';
|
||||
|
||||
interface PoviderData {
|
||||
providerDisplay: string;
|
||||
nodes: Partial<Record<ChainName, string>>;
|
||||
}
|
||||
|
||||
// we use this to give an ordering to the chains available
|
||||
const ORDER_CHAINS: ChainName[] = ['kusama', 'edgeware', 'westend', 'edgewareTest', 'flamingFir', 'kulupu'];
|
||||
|
||||
// we use this to order the providers inside the chains
|
||||
const ORDER_PROVIDERS: ProviderName[] = ['parity', 'w3f', 'unfrastructure', 'commonwealth', 'kulupu'];
|
||||
|
||||
// some suplementary info on a per-chain basis
|
||||
const CHAIN_INFO: Record<ChainName, ChainData> = {
|
||||
alexander: {
|
||||
chainDisplay: 'Alexander',
|
||||
logo: 'alexander',
|
||||
type: 'Polkadot Testnet'
|
||||
},
|
||||
edgeware: {
|
||||
chainDisplay: 'Edgeware',
|
||||
logo: 'edgeware',
|
||||
type: 'Edgeware Mainnet'
|
||||
},
|
||||
edgewareTest: {
|
||||
chainDisplay: 'Edgeware Testnet',
|
||||
logo: 'edgeware',
|
||||
type: 'Edgeware Testnet'
|
||||
},
|
||||
flamingFir: {
|
||||
chainDisplay: 'Flaming Fir',
|
||||
logo: 'substrate',
|
||||
type: 'Substrate Testnet'
|
||||
},
|
||||
kusama: {
|
||||
chainDisplay: 'Kusama',
|
||||
logo: 'kusama',
|
||||
type: 'Polkadot Canary'
|
||||
},
|
||||
kulupu: {
|
||||
chainDisplay: 'Kulupu',
|
||||
logo: 'substrate',
|
||||
type: 'Kulupu Mainnet'
|
||||
},
|
||||
westend: {
|
||||
chainDisplay: 'Westend',
|
||||
logo: 'alexander',
|
||||
type: 'Polkadot Testnet'
|
||||
}
|
||||
};
|
||||
|
||||
// the actual providers with all the nodes they provide
|
||||
const PROVIDERS: Record<ProviderName, PoviderData> = {
|
||||
commonwealth: {
|
||||
providerDisplay: 'Commonwealth Labs',
|
||||
nodes: {
|
||||
// edgeware: 'wss://mainnet1.edgewa.re',
|
||||
edgewareTest: 'wss://testnet4.edgewa.re'
|
||||
}
|
||||
},
|
||||
parity: {
|
||||
providerDisplay: 'Parity',
|
||||
nodes: {
|
||||
// alexander: 'wss://poc3-rpc.polkadot.io/',
|
||||
flamingFir: 'wss://substrate-rpc.parity.io/',
|
||||
kusama: 'wss://kusama-rpc.polkadot.io/',
|
||||
westend: 'wss://westend-rpc.polkadot.io'
|
||||
}
|
||||
},
|
||||
unfrastructure: {
|
||||
providerDisplay: 'Centrality UNfrastructure',
|
||||
nodes: {
|
||||
// alexander: 'wss://alex.unfrastructure.io/public/ws'
|
||||
}
|
||||
},
|
||||
w3f: {
|
||||
providerDisplay: 'Web3 Foundation',
|
||||
nodes: {
|
||||
kusama: 'wss://cc3-5.kusama.network/'
|
||||
}
|
||||
},
|
||||
kulupu: {
|
||||
providerDisplay: 'Kulupu',
|
||||
nodes: {
|
||||
kulupu: 'wss://rpc.kulupu.network/ws'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const ENDPOINT_DEFAULT = isPolkadot
|
||||
? PROVIDERS.parity.nodes.kusama
|
||||
: PROVIDERS.parity.nodes.flamingFir;
|
||||
|
||||
export const ENDPOINTS: Option[] = ORDER_CHAINS.reduce((endpoints: Option[], chainName): Option[] => {
|
||||
const { chainDisplay, logo, type } = CHAIN_INFO[chainName];
|
||||
|
||||
return ORDER_PROVIDERS.reduce((endpoints: Option[], providerName): Option[] => {
|
||||
const { providerDisplay, nodes } = PROVIDERS[providerName];
|
||||
const wssUrl = nodes[chainName];
|
||||
|
||||
if (wssUrl) {
|
||||
endpoints.push({
|
||||
info: logo,
|
||||
text: `${chainDisplay} (${type}, hosted by ${providerDisplay})`,
|
||||
value: wssUrl
|
||||
});
|
||||
}
|
||||
|
||||
return endpoints;
|
||||
}, endpoints);
|
||||
}, []);
|
||||
|
||||
// add a local node right at the end
|
||||
ENDPOINTS.push({
|
||||
export const ENDPOINTS: Option[] = [{
|
||||
info: 'local',
|
||||
text: 'Local Node (Own, 127.0.0.1:9944)',
|
||||
value: 'ws://127.0.0.1:9944/'
|
||||
});
|
||||
}];
|
||||
|
||||
export const ENDPOINT_DEFAULT = ENDPOINTS[0];
|
||||
|
||||
@@ -12,11 +12,12 @@ export const LEDGER_CONN: Option[] = [
|
||||
text: 'Do not attach Ledger devices',
|
||||
value: 'none'
|
||||
},
|
||||
{
|
||||
info: 'u2f',
|
||||
text: 'Attach Ledger via U2F',
|
||||
value: 'u2f'
|
||||
},
|
||||
// Deprecated
|
||||
// {
|
||||
// info: 'u2f',
|
||||
// text: 'Attach Ledger via U2F',
|
||||
// value: 'u2f'
|
||||
// },
|
||||
{
|
||||
info: 'webusb',
|
||||
text: 'Attach Ledger via WebUSB',
|
||||
|
||||
@@ -12,19 +12,26 @@ export const PREFIXES: Option[] = [
|
||||
text: 'Default for the connected node',
|
||||
value: -1
|
||||
},
|
||||
// keep as first (well, after default)
|
||||
{
|
||||
info: 'substrate',
|
||||
text: 'Substrate (development)',
|
||||
text: 'Substrate (generic)',
|
||||
value: 42
|
||||
},
|
||||
// all in ascending order based on value
|
||||
{
|
||||
info: 'polkadot',
|
||||
text: 'Polkadot (live)',
|
||||
value: 0
|
||||
},
|
||||
{
|
||||
info: 'kusama',
|
||||
text: 'Kusama (canary)',
|
||||
value: 2
|
||||
},
|
||||
{
|
||||
info: 'polkadot',
|
||||
text: 'Polkadot (live)',
|
||||
value: 0
|
||||
info: 'edgeware',
|
||||
text: 'Edgeware (live)',
|
||||
value: 7
|
||||
}
|
||||
];
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
import settings, { Settings } from './Settings';
|
||||
export { ENDPOINT_DEFAULT, ICON_DEFAULT, ICON_DEFAULT_HOST, LANGUAGE_DEFAULT, LOCKING_DEFAULT, PREFIX_DEFAULT, UIMODE_DEFAULT, UITHEME_DEFAULT } from './defaults';
|
||||
export { SettingsStruct } from './types';
|
||||
export { SettingsStruct, NetworkSpecsStruct } from './types';
|
||||
|
||||
export default settings;
|
||||
|
||||
|
||||
@@ -20,3 +20,12 @@ export interface SettingsStruct {
|
||||
uiMode: string;
|
||||
uiTheme: string;
|
||||
}
|
||||
|
||||
export interface NetworkSpecsStruct {
|
||||
color: string;
|
||||
decimals: number;
|
||||
genesisHash: string;
|
||||
prefix: number;
|
||||
title: string;
|
||||
unit: string;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# @polkadot/ui-shared
|
||||
|
||||
Shared logic for various logic, i.e. for identicon generation
|
||||
Shared logic for various logic. For identicon generation used inside the `@polkadot/{react, reactnative, vue}-identicon` icons.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@polkadot/ui-shared",
|
||||
"version": "0.48.1",
|
||||
"version": "0.55.1",
|
||||
"description": "Shared logic that is usable accross all frameworks-specific areas",
|
||||
"main": "index.js",
|
||||
"author": "Jaco Greeff <jacogr@gmail.com>",
|
||||
@@ -9,14 +9,17 @@
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.8.3",
|
||||
"@types/color": "^3.0.1",
|
||||
"@babel/runtime": "^7.10.4",
|
||||
"color": "^3.1.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@polkadot/util": "*",
|
||||
"@polkadot/util-crypto": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@polkadot/util-crypto": "^2.0.1"
|
||||
"@polkadot/util": "^2.16.1",
|
||||
"@polkadot/util-crypto": "^2.16.1",
|
||||
"@types/color": "^3.0.1",
|
||||
"@types/xmlserializer": "^0.6.0"
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -7,7 +7,7 @@ import container from './container';
|
||||
describe('container', (): void => {
|
||||
it('applies default styles', (): void => {
|
||||
expect(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-member-access
|
||||
(container(100).style as any)._values
|
||||
).toMatchObject({
|
||||
background: 'white',
|
||||
@@ -23,7 +23,7 @@ describe('container', (): void => {
|
||||
|
||||
it('overrides with supplied styles', (): void => {
|
||||
expect(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-member-access
|
||||
(container(50, 'black', '', { display: 'block' }).style as any)._values
|
||||
).toMatchObject({
|
||||
background: 'black',
|
||||
+1
-1
@@ -18,7 +18,7 @@ function generateIcon (seed: string = encodeAddress(randomAsU8a(32))): void {
|
||||
}
|
||||
|
||||
element.appendChild(
|
||||
identicon(seed, 100, 'padded')
|
||||
identicon(seed, { isAlternative: false, size: 100 }, 'padded')
|
||||
);
|
||||
|
||||
console.log(`Icon generated in ${(Date.now() - start)}ms`);
|
||||
+3
-3
@@ -4,13 +4,13 @@
|
||||
|
||||
import xmlserializer from 'xmlserializer';
|
||||
|
||||
import identicon from '.';
|
||||
import generate from '.';
|
||||
|
||||
describe('identicon', (): void => {
|
||||
it('generates a basic [0,..,0] identicon', (): void => {
|
||||
expect(
|
||||
xmlserializer.serializeToString(
|
||||
identicon(new Uint8Array(32))
|
||||
generate(new Uint8Array(32), { isAlternative: false, size: 256 })
|
||||
)
|
||||
).toEqual(
|
||||
'<div xmlns="http://www.w3.org/1999/xhtml" class="" style="background: white; border-radius: 128px; display: inline-block; height: 256px; margin: 0px; overflow: hidden; padding: 0px; width: 256px;"><div class="" style="background: rgb(20, 20, 20); border-radius: 128px; display: inline-block; height: 256px; margin: 0px; overflow: hidden; padding: 0px; width: 256px;"><svg xmlns="http://www.w3.org/2000/svg" x="0" y="0" width="256" height="256"><circle cx="128" cy="140.8" r="128" fill="hsl(212.10000000000002, 65.6%, 55.5%)"/><circle cx="128" cy="153.6" r="102.4" fill="hsl(9.800000000000011, 90.7%, 57.6%)"/><circle cx="128" cy="166.4" r="76.8" fill="hsl(345, 85.7%, 86.3%)"/><circle cx="128" cy="179.2" r="51.2" fill="hsl(261.9, 100%, 87.3%)"/><circle cx="128" cy="192" r="25.6" fill="hsl(345, 100%, 25.1%)"/></svg></div></div>'
|
||||
@@ -20,7 +20,7 @@ describe('identicon', (): void => {
|
||||
it('allows overrides', (): void => {
|
||||
expect(
|
||||
xmlserializer.serializeToString(
|
||||
identicon(new Uint8Array(32), 100, 'testClass', { display: 'block' })
|
||||
generate(new Uint8Array(32), { isAlternative: false, size: 100 }, 'testClass', { display: 'block' })
|
||||
)
|
||||
).toEqual(
|
||||
'<div xmlns="http://www.w3.org/1999/xhtml" class="testClass" style="background: white; border-radius: 50px; display: block; height: 100px; margin: 0px; overflow: hidden; padding: 0px; width: 100px;"><div class="" style="background: rgb(20, 20, 20); border-radius: 50px; display: inline-block; height: 100px; margin: 0px; overflow: hidden; padding: 0px; width: 100px;"><svg xmlns="http://www.w3.org/2000/svg" x="0" y="0" width="100" height="100"><circle cx="50" cy="55" r="50" fill="hsl(212.10000000000002, 65.6%, 55.5%)"/><circle cx="50" cy="60" r="40" fill="hsl(9.800000000000011, 90.7%, 57.6%)"/><circle cx="50" cy="65" r="30" fill="hsl(345, 85.7%, 86.3%)"/><circle cx="50" cy="70" r="20" fill="hsl(261.9, 100%, 87.3%)"/><circle cx="50" cy="75" r="10" fill="hsl(345, 100%, 25.1%)"/></svg></div></div>'
|
||||
+7
-5
@@ -3,6 +3,8 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { Options } from '../types';
|
||||
|
||||
import colors from './colors';
|
||||
import newContainer from './container';
|
||||
import newSeeder from './seeder';
|
||||
@@ -10,19 +12,19 @@ import newShape from './shape/circle';
|
||||
import newElement from './svg/element';
|
||||
import { SHAPE_COUNT } from './defaults';
|
||||
|
||||
export default function identicon (seed: string | Uint8Array, diameter = 256, className = '', style?: { [index: string]: string }): HTMLElement {
|
||||
export default function generate (seed: string | Uint8Array, { size = 256 }: Options, className = '', style?: { [index: string]: string }): HTMLElement {
|
||||
const seeder = newSeeder(seed);
|
||||
const colorGen = colors(seeder);
|
||||
const outer = newContainer(diameter, 'white', className, style);
|
||||
const container = newContainer(diameter, colorGen());
|
||||
const svg = newElement(diameter);
|
||||
const outer = newContainer(size, 'white', className, style);
|
||||
const container = newContainer(size, colorGen());
|
||||
const svg = newElement(size);
|
||||
|
||||
outer.appendChild(container);
|
||||
container.appendChild(svg);
|
||||
|
||||
for (let count = 0; count < SHAPE_COUNT; count++) {
|
||||
const fill = colorGen();
|
||||
const shape = newShape(seeder, fill, diameter, count);
|
||||
const shape = newShape(seeder, fill, size, count);
|
||||
|
||||
svg.appendChild(shape);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user