Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
27871135a0 | ||
|
|
26be5e0cc5 | ||
|
|
66142c0137 | ||
|
|
de395c7053 | ||
|
|
ab78245576 | ||
|
|
6ff0efca25 | ||
|
|
fa0fd7140c | ||
|
|
0b71291cf1 | ||
|
|
44d0ced5af | ||
|
|
a8bfa90b87 | ||
|
|
835361d3c5 | ||
|
|
3bb719fcfc | ||
|
|
00a3001df9 | ||
|
|
cac0056fc4 | ||
|
|
a9e55e66d6 | ||
|
|
c10f0e47b2 | ||
|
|
0b45bc6ab9 | ||
|
|
30f62f4024 | ||
|
|
262f01b54e | ||
|
|
26c2774992 | ||
|
|
58ff26cc78 | ||
|
|
62eab2d661 | ||
|
|
d4ab4f8293 | ||
|
|
aed4b3ee6a | ||
|
|
4c90c6158f | ||
|
|
b911bdbd2d | ||
|
|
b5edcb8529 | ||
|
|
9086592252 | ||
|
|
c0b428dfbc | ||
|
|
e49427ac61 | ||
|
|
64149de2d4 | ||
|
|
fe3de4379f | ||
|
|
5532daf640 | ||
|
|
e197c6f114 | ||
|
|
f3b71b21b5 | ||
|
|
db3cb47d05 | ||
|
|
3f135f2da2 | ||
|
|
4ec6a0f9b8 | ||
|
|
eca0d8d81a | ||
|
|
e056675b3a | ||
|
|
71a4b39698 | ||
|
|
d194a6e4c9 | ||
|
|
4a7d8677a3 | ||
|
|
21ac0ac2fb | ||
|
|
acfd856b25 | ||
|
|
d5d8b59f8b | ||
|
|
b24fe30a40 | ||
|
|
207e2982d7 | ||
|
|
6fab577e23 | ||
|
|
f7ca638a1a | ||
|
|
0c96ba7a02 | ||
|
|
7143f5e643 | ||
|
|
910fa20b78 | ||
|
|
4855e631b5 | ||
|
|
698f2725c9 | ||
|
|
492fce1af7 | ||
|
|
397e9494eb | ||
|
|
b8d7f4803b | ||
|
|
89f0d452f4 | ||
|
|
bf8bed36ef | ||
|
|
38529ad13c | ||
|
|
8a6d23d461 | ||
|
|
d80cc717e2 | ||
|
|
a207348c13 | ||
|
|
4a795b4c50 | ||
|
|
e54cee1fad | ||
|
|
4e4108abfa | ||
|
|
3196e66efb | ||
|
|
7e0f20908c | ||
|
|
985749ade1 | ||
|
|
ec8deb8be3 | ||
|
|
b8d4bc5c6a | ||
|
|
2870513453 | ||
|
|
e27b35cd9f | ||
|
|
bc86dbb31e | ||
|
|
d1b047f675 | ||
|
|
8b43ee6ca1 | ||
|
|
f6e5068dae | ||
|
|
fe40e2378a | ||
|
|
2e9192ca02 | ||
|
|
05ec4964fe | ||
|
|
64f8444d47 | ||
|
|
c0f9b45dca | ||
|
|
ffadc335d5 | ||
|
|
9c09386600 | ||
|
|
7cc541c45f | ||
|
|
2accd13bb6 | ||
|
|
647e605c9f | ||
|
|
eaa9dd00c7 | ||
|
|
fb7e067737 | ||
|
|
eaa71e0097 | ||
|
|
cd7767d39a | ||
|
|
cf07d4f743 | ||
|
|
525b6bf4ad | ||
|
|
f73c01889f | ||
|
|
56d20ceb41 | ||
|
|
25d1a1195e | ||
|
|
db593d2303 | ||
|
|
e17572d845 | ||
|
|
73704b68ab | ||
|
|
d594149ed1 | ||
|
|
6b0e2fe919 | ||
|
|
b36660a0cc | ||
|
|
29922c2bef | ||
|
|
1e67aeed9a | ||
|
|
c28df79c3b | ||
|
|
f145fe7c8b | ||
|
|
a03a303b8f | ||
|
|
eda93d25f6 | ||
|
|
44d89ed204 | ||
|
|
d632f25a9b | ||
|
|
2f6a397484 | ||
|
|
a54286c98b | ||
|
|
ddd21c691f | ||
|
|
d0f9114fda | ||
|
|
275593b6fb | ||
|
|
17a10fbffe | ||
|
|
afff880c20 | ||
|
|
739625c171 | ||
|
|
5fc8e3975b | ||
|
|
fadb1ffdd8 | ||
|
|
bddb48f452 | ||
|
|
af682bc23b | ||
|
|
7b2cf6dcb0 | ||
|
|
9807ff70fa | ||
|
|
d30bd0dd86 | ||
|
|
25f78a7354 | ||
|
|
0bc0ef6110 | ||
|
|
b231b7b8cb |
@@ -1,24 +0,0 @@
|
||||
version: 2
|
||||
jobs:
|
||||
build:
|
||||
branches:
|
||||
ignore:
|
||||
- gh-pages
|
||||
working_directory: ~/polkadot-js
|
||||
docker:
|
||||
- image: circleci/node:10
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
key: dependency-cache-{{ checksum "yarn.lock" }}
|
||||
- run:
|
||||
name: install-deps
|
||||
command: yarn install --frozen-lockfile
|
||||
- save_cache:
|
||||
key: dependency-cache-{{ checksum "yarn.lock" }}
|
||||
paths:
|
||||
- ./node_modules
|
||||
- ~/.cache/yarn
|
||||
- run:
|
||||
name: build
|
||||
command: yarn polkadot-dev-circleci-build
|
||||
+1
-1
@@ -5,7 +5,7 @@ module.exports = {
|
||||
parserOptions: {
|
||||
...base.parserOptions,
|
||||
project: [
|
||||
'./tsconfig.eslint.json'
|
||||
'./tsconfig.json'
|
||||
]
|
||||
},
|
||||
rules: {
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
name: PR
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: Linting
|
||||
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: lint
|
||||
run: |
|
||||
yarn install --frozen-lockfile
|
||||
yarn lint
|
||||
|
||||
test:
|
||||
name: Testing
|
||||
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
|
||||
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
|
||||
@@ -0,0 +1,53 @@
|
||||
name: Master
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build_code:
|
||||
name: Build Code
|
||||
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:
|
||||
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
|
||||
GH_PAT: ${{ secrets.GH_PAT }}
|
||||
GH_TOKEN: ${{ secrets.GH_PAT }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
run: |
|
||||
yarn install --frozen-lockfile
|
||||
CI_NO_BETA=true 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
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "10"
|
||||
env:
|
||||
global:
|
||||
- CC_TEST_REPORTER_ID=b8983d04997f43ff9b9df9aa92904967547680e2a229af812b3cf14985713e84
|
||||
- GH_PAGES_SRC="build-docs"
|
||||
cache:
|
||||
yarn: true
|
||||
directories:
|
||||
- node_modules
|
||||
before_install:
|
||||
- curl -o- -L https://yarnpkg.com/install.sh | bash
|
||||
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
||||
- chmod +x ./cc-test-reporter
|
||||
- export PATH=$HOME/.yarn/bin::$(yarn global bin):$PATH
|
||||
before_script:
|
||||
- ./cc-test-reporter before-build
|
||||
script:
|
||||
- yarn polkadot-dev-travis-build
|
||||
after_script:
|
||||
- ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
|
||||
deploy:
|
||||
skip_cleanup: true
|
||||
provider: script
|
||||
script: yarn polkadot-dev-travis-deploy
|
||||
on:
|
||||
branch: master
|
||||
+33
-11
@@ -1,3 +1,25 @@
|
||||
# 0.95.1
|
||||
|
||||
- Support Extrinsic V4 with additional signature indicator (Latest Polkadot/Substrate/Kusama)
|
||||
- Adjust subscription update checks to avoid duplicated data updates
|
||||
- Support Metadata V8 (exposes per-module `decl_error` definitions)
|
||||
- Support next generation contracts ABI (with additional type definitions)
|
||||
- Support for `BTreeMap<K, V>` types and definitions
|
||||
- All latest Polkadot & Substrate types (as per master branches)
|
||||
- **Breaking change** `Call.injectMethods` is moved to `Call.injectMetadata` to align with `Events` (This _should_ not be used externally, however mentioned as breaking here)
|
||||
|
||||
# 0.94.1
|
||||
|
||||
- Add handling of `Result<Ok, Error>` definitions
|
||||
- Adjust API cloning now takes RPC filters from source into account
|
||||
- Simplification of isPedantic checks and less overhead on StorageData types
|
||||
- Cleanups and fixes around RPC and derive type definitions
|
||||
- Fix `derive.imOnline.receivedHeatbeats` to query via indexes
|
||||
- Adjustment of `api.derive.elections.{approvalsOf|approvalsOfAt}` to allow ss58 address input
|
||||
- Cleanup `Enum` `.eq` handling to be more exhaustive
|
||||
- Add documentation for custom extrinsic formats (advanced chains)
|
||||
- Update to latest substrate master metadata
|
||||
|
||||
# 0.93.1
|
||||
|
||||
- Support for Kusama CC2
|
||||
@@ -23,7 +45,7 @@
|
||||
- The `getRuntimeVersion` and `subscribeRuntimeVersion` RPCs are now only available on the `rpc.state.*` endpoints. This aligns with the Substrate implementation.
|
||||
- The `author_insertKey` RPC's last argument `publicKey` is now required, as to reflect Substrate implementation.
|
||||
- Support for extrinsics with versions that is not in the base Substrate implementation (V1-V3) can now be done by providing an implementation for `ExtrinsicUnknown`
|
||||
- Redeemed balance calculation if `api.derive` now returns the correct values again (bugfix)
|
||||
- Redeemed balance calculation if `api.derive` now returns the correct values again (bug fix)
|
||||
- added the `yarn chain:info [--ws URL]` utility to extract a calls-only metadata version
|
||||
- Missing types are now logged via a `console.warn`, not via `.error`
|
||||
- `Extrinsic`, `ExtrinsicPayload` & `SignerPayload` is registered in the type registry and can be overriden now
|
||||
@@ -39,7 +61,7 @@ If you are upgrading form an older version, use the CHANGELOG hand-in-hand with
|
||||
- **Breaking change** `Api.create(...)` and `new Api(...)` now only takes an options Object, so if you passed the provider directly previously, you need to swap the use to `Api.create({ provider: ... })`
|
||||
- **Breaking change** Runtime types have been extended and moved to definitions instead of classes
|
||||
- Primitive types for `i*` and `u*` (e.g. `u32`) are now only available in their lowercase versions. Additionally `Vector` is now only available as `Vec`, and `Method` has been renamed to `Call`, in both cases aligning with Rust.
|
||||
- `Moment` now implements as `u64` as per the Substrate codebase. (It it up to the user to interpret, for substrate 2.x it is not mili-second resolution)
|
||||
- `Moment` now implements as `u64` as per the Substrate codebase. (It it up to the user to interpret, for substrate 2.x it is not ms resolution)
|
||||
- For creation of types, it is recommended to use `createType(<TypeName>, <value>)` instead of e.g. `new Proposal(...)`. When passing these to methods/queries, construction should not be needed, the raw value can be passed.
|
||||
- For moved types, a previous import would have been from `@polkadot/types`, i.e. `import { SetIndex } from '@polkadot/types`, now just the interfaces (TypeScript) are available via `import { SetIndex } from '@polkadot/types/interfaces`
|
||||
- `usize` is now a blacklisted type that will throw on construction. Since it is platform-specific, it creates incompatibilities between native (generally `u64`) and WASM (always `u32`) code. Use one of the `u32` or `u64` types explicitly.
|
||||
@@ -123,7 +145,7 @@ If you are upgrading form an older version, use the CHANGELOG hand-in-hand with
|
||||
# 0.77.1
|
||||
|
||||
- Support Metadata v4, which introduces the use of a custom hasher to hash storage map keys.
|
||||
- Add TresuryProposal (not the same as democracy, type aliassed)
|
||||
- Add TreasuryProposal (not the same as democracy, type aliased)
|
||||
|
||||
|
||||
# 0.76.1
|
||||
@@ -145,7 +167,7 @@ If you are upgrading form an older version, use the CHANGELOG hand-in-hand with
|
||||
- For extrinsic status results, if you have checked the type returns, i.e. `result.type === 'Finalised'` now check on the status for `result.status.isFinalized` or `result.status.isBroadcast`, ... (the `type` property is now accessible only on `result.status.type`)
|
||||
- If using `subscribeFinalisedHeads` update this to `subscribeFinalizedHeads` (likewise `getFinalisedHead` should be updated to `getFinalizedHead` and `derive.bestNumberFinalized`)
|
||||
|
||||
- The underlying ss58 addess checksums have changed
|
||||
- The underlying ss58 address checksums have changed
|
||||
- The updated keyring with support for this has been made available
|
||||
- All examples have been updated with sr25519 addresses (with the new checksums)
|
||||
|
||||
@@ -163,12 +185,12 @@ If you are upgrading form an older version, use the CHANGELOG hand-in-hand with
|
||||
# 0.51.1
|
||||
|
||||
- Support metadata V2 as per latest substrate master
|
||||
- Update metadata with new types as per lastest substrate master
|
||||
- Update metadata with new types as per latest substrate master
|
||||
|
||||
|
||||
# 0.50.1
|
||||
|
||||
- Lastest util-crypto (usage of WASM with JS fallbacks if not available)
|
||||
- Latest util-crypto (usage of WASM with JS fallbacks if not available)
|
||||
- Update upstream @polkadot dependencies (for new crypto)
|
||||
|
||||
|
||||
@@ -191,7 +213,7 @@ If you are upgrading form an older version, use the CHANGELOG hand-in-hand with
|
||||
# 0.46.1
|
||||
|
||||
- Extended type registration to now handle internal types as well. Additionally the built-in Extrinsic type can now we overridden with a custom version.
|
||||
- Where `Extrinsic` and `Method` is used as types, considder importing `{ IMethod, IExtrinsic }` from `@polkadot/types/types`, especially in the cases where this is uased from a `SubmittableExtrinsic`
|
||||
- Where `Extrinsic` and `Method` is used as types, consider importing `{ IMethod, IExtrinsic }` from `@polkadot/types/types`, especially in the cases where this is used from a `SubmittableExtrinsic`
|
||||
- The `typeRegistry` constant is now `getTypeRegistry()` as a function
|
||||
|
||||
|
||||
@@ -214,7 +236,7 @@ console.log('llo', llo.unwrapOr('not set') /* Option<BlockNumber> */)
|
||||
|
||||
# 0.44.1
|
||||
|
||||
- Split primitives and types into seperate folders. This should not affect external use since the exports remain the same, however does have an impact where classes are referenced directly. e.g.
|
||||
- Split primitives and types into separate folders. This should not affect external use since the exports remain the same, however does have an impact where classes are referenced directly. e.g.
|
||||
|
||||
```js
|
||||
// old (affected)
|
||||
@@ -232,7 +254,7 @@ import { Method, Signature } from '@polkadot/types';
|
||||
|
||||
# 0.43.1
|
||||
|
||||
- Intrduces support for the new keyring with sr25519 support in addition to ed25519. While this does not change the exposed API, it is considerred breaking since @polkadot/keyring has interface changes. (Unless needed, don't rush the upgrade)
|
||||
- Introduces support for the new keyring with sr25519 support in addition to ed25519. While this does not change the exposed API, it is considered breaking since @polkadot/keyring has interface changes. (Unless needed, don't rush the upgrade)
|
||||
|
||||
|
||||
# 0.42.1
|
||||
@@ -243,7 +265,7 @@ import { Method, Signature } from '@polkadot/types';
|
||||
|
||||
# 0.41.1
|
||||
|
||||
- Support the V1 metadata specification from Substrate in addition to the currently testnet-active V0 version
|
||||
- Support the V1 metadata specification from Substrate in addition to the currently testnet active V0 version
|
||||
|
||||
|
||||
# 0.40.1
|
||||
@@ -263,7 +285,7 @@ Substrate has been updated with a breaking new transaction format where the Inde
|
||||
|
||||
# 0.37.1
|
||||
|
||||
api-observable has been removed. This was only used in /apps and inconsistent with the api/rx and api/promise APIs. Future work will include derivates like was included in api-observable into the base.
|
||||
api-observable has been removed. This was only used in /apps and inconsistent with the api/rx and api/promise APIs. Future work will include derives like was included in api-observable into the base.
|
||||
|
||||
Tuples now return single types when only one type is available, i.e. `(AccountId)` would now resolve as `AccountId`. The extra type wrapper adds no benefit to users here.
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ module.exports = {
|
||||
['start/api.tx.wrap.md', 'Complex transactions'],
|
||||
['start/types.basics.md', 'Type basics'],
|
||||
['start/types.extend.md', 'Extending types'],
|
||||
['start/extrinsic.extend.md', 'Extending extrinsics'],
|
||||
['start/typescript.md', 'TypeScript interfaces'],
|
||||
['start/FAQ.md', 'FAQ']
|
||||
]
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@
|
||||
- [Unsubscribe from listening](examples/promise/04_unsubscribe/README.md)
|
||||
- [Read chain state](examples/promise/05_read_storage/README.md)
|
||||
- [Make a transfer](examples/promise/06_make_transfer/README.md)
|
||||
- [Display system events](examples/promise/08_system_events/README.md)(
|
||||
- [Display system events](examples/promise/08_system_events/README.md)
|
||||
- [Transaction with events](examples/promise/09_transfer_events/README.md)
|
||||
- [Upgrade via sudo](examples/promise/10_upgrade_chain/README.md)
|
||||
- [ApiRx](examples/rx/README.md)
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
|
||||
In addition to querying the latest storage, you can make storage queries at a specific blockhash. Be aware that the node applies a pruning strategy and typically only keeps the last 256 blocks, unless run in archive mode.
|
||||
|
||||
<<< @/docs/examples/promise/07_read_storage_at/index.js
|
||||
<<< @/docs/examples/promise/05_read_storage_at/index.js
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
|
||||
This example shows how to instantiate a Polkadot API object and use it to connect to a node and retrieve balance updates.
|
||||
|
||||
<<< @/docs/examples/rx/03_listent_to_balance_change/index.js
|
||||
<<< @/docs/examples/rx/03_listen_to_balance_change/index.js
|
||||
|
||||
@@ -23,3 +23,13 @@ As of this writing we don't have an explicit example of implementing the signer
|
||||
Some calls in Polkadot/Substrate can only be submitted as root, these are indicated by `ensure_root(origin)` in the Rust codebase. Root here does not refer to the actual account, i.e. `//Alice` on a `--dev` chain, but rather that it cannot be submitted as a bare user transaction. This restriction applies to chain upgrades, changing balances or anything that modifies the state and/or chain operation.
|
||||
|
||||
To submit these transactions, it needs to be send as a [wrapped transaction](api.tx.wrap.md#sudo-use) via either `sudo.sudo` (assuming you have access on your chain) or `democracy.proposal` (which would allow users of the chain to vote on it).
|
||||
|
||||
## How do I call a function with a Tuple input
|
||||
|
||||
Tuples, as defined in the Polkadot/Substrate types appear as `(TypeA, TypeB)`. For instance we may have an `(AccountId, u64)` input as defined in the metadata or as part of the user types. To specify a Tuple as an input, wrap it is an array format, for instance to call `query.module.get((u32, u64))` where a `(u32, u64)` Tuple input is expected, you would do `query.module.get([123, 456])`
|
||||
|
||||
## How long do transactions live
|
||||
|
||||
Polkadot/Substrate supports both immortal and mortal transactions. For immortal, this means that the transaction has an infinite lifetime, for mortals, the transactions expire after a defined period. By default the API sends mortal transactions when no explicit extrinsic era has been specified. This means that all transaction has a limited lifetime and will expire if not included in the period set.
|
||||
|
||||
The length for this transaction validity is set to 50 blocks, which translates to 5 minutes assuming a default of 6 second blocktimes. (10 blocks per minute in this default configuration).
|
||||
|
||||
@@ -33,7 +33,7 @@ const momentPrev = await api.query.timestamp.now.at(lastHdr.parentHash);
|
||||
|
||||
The `.at` queries are all single-shot, i.e. there are no subscription option to these, since the state for a previous block should be static. (This is true to a certain extent, i.e. when blocks have been finalized).
|
||||
|
||||
An additional point to take care of (briefly mentioned above), is state pruning. By default a Polkadot/Substrate node will only keep state for the last 256 blocks, unless it is explicitly run in archive mode. This means that querying state further back than the pruning period will result in an error returned from the Node. (Generaly most public RPC nodes only run with default settings, which includes aggressive state pruning)
|
||||
An additional point to take care of (briefly mentioned above), is state pruning. By default a Polkadot/Substrate node will only keep state for the last 256 blocks, unless it is explicitly run in archive mode. This means that querying state further back than the pruning period will result in an error returned from the Node. (Generally most public RPC nodes only run with default settings, which includes aggressive state pruning)
|
||||
|
||||
## State entries
|
||||
|
||||
@@ -69,7 +69,7 @@ console.log(`query key: ${api.query.balances.freeBalance.key(ADDR)}`);
|
||||
|
||||
The `section` & `method` is an indication of where it is exposed on the API. In addition the `meta` holds an array with the metadata documentation for the entry.
|
||||
|
||||
The `key` endpoint requires some explanation. In the chain state, the key values (identified by the module, method & params) are hashed and this is used as a lookup. So underlying a single-shot query would utilize the `api.rpc.state.getStorage` entry, passing the output of `key` (which is a hashed representation of the values). Apart from the hashing, the API also takes care of type formatting, handling optional values and merging results accross multiple subscriptions.
|
||||
The `key` endpoint requires some explanation. In the chain state, the key values (identified by the module, method & params) are hashed and this is used as a lookup. So underlying a single-shot query would utilize the `api.rpc.state.getStorage` entry, passing the output of `key` (which is a hashed representation of the values). Apart from the hashing, the API also takes care of type formatting, handling optional values and merging results across multiple subscriptions.
|
||||
|
||||
## Let's transact already!
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Previously we explained the concepts between `api.query`. In this section we will expand on that knowledge to introduce subscriptions (akin to what we found in `api.rpc`) to stream results from the state, as it changes between blocks.
|
||||
|
||||
## Subcriptions
|
||||
## Subscriptions
|
||||
|
||||
As in the case with `api.rpc` subscriptions, query subscriptions follow exactly the same form - an actual call is augmented with a callback to return the current state value that is updated as the underlying value changes. As an example, we can extend on what we had previously -
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ The result for this call (we will deal with subscriptions in a short while), is
|
||||
Despite the single-line format of `signAndSend`, there is a lot happening under the hood (and all of this can be manually provided) -
|
||||
|
||||
- Based on the sender, the API will retrieve the `system.accountNonce` to determine the next nonce to use
|
||||
- The API will retrieve the current block hash and use it to create a mortal transaction, i.e. the transaction will only be valid for a limited number of blocks (by default this is 5 mins at 6s blocktimes)
|
||||
- The API will retrieve the current block hash and use it to create a mortal transaction, i.e. the transaction will only be valid for a limited number of blocks (by default this is 5 mins at 6s block times)
|
||||
- It will construct a payload and sign this, this includes the `genesisHash`, the `blockHash` for the start of the mortal era as well as the current chain `specVersion`
|
||||
- The transaction is submitted to the node
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Complex transactions
|
||||
|
||||
Up till now we have focussed on the base operation of transactions. There are however some more complex operations that deserve some more information, for instance when doing either democracy proposals or excuting sudo calls, in both these cases the transaction wraps a call or proposal to be evaluated.
|
||||
Up till now we have focussed on the base operation of transactions. There are however some more complex operations that deserve some more information, for instance when doing either democracy proposals or executing sudo calls, in both these cases the transaction wraps a call or proposal to be evaluated.
|
||||
|
||||
## Sudo use
|
||||
|
||||
@@ -41,4 +41,4 @@ In the above example, all we need to provide is a the fields for the `ValidatorP
|
||||
|
||||
## Understanding types
|
||||
|
||||
As has been very apparent in all the preceding sections, the management of types is what allows the API to communicate with the node. Most values are in a [binary SCALE-encoded format](https://github.com/paritytech/parity-scale-codec) and it is the reponsibility of the API is to encode and decode these. In the next section we will [take a look at what interfaces the API provides around types](types.basics.md).
|
||||
As has been very apparent in all the preceding sections, the management of types is what allows the API to communicate with the node. Most values are in a [binary SCALE-encoded format](https://github.com/paritytech/parity-scale-codec) and it is the responsibility of the API is to encode and decode these. In the next section we will [take a look at what interfaces the API provides around types](types.basics.md).
|
||||
|
||||
@@ -16,7 +16,7 @@ Additionally the metadata also provides information on [events](../substrate/eve
|
||||
|
||||
## Types
|
||||
|
||||
The metadata defiends the calls with all the type names used in the various interfaces. At the moment (this is undergoing investigations and could improve in future versions of metadata), this also means that the types between the API and the node need to be aligned. For instance, by default Substrate defines a `BlockNumber` type as a `u32` and the API follows the Substrate defaults - if a chain has a different definitions, the API needs to be aware of this so it can actually decode (and encode) the type.
|
||||
The metadata defines the calls with all the type names used in the various interfaces. At the moment (this is undergoing investigations and could improve in future versions of metadata), this also means that the types between the API and the node need to be aligned. For instance, by default Substrate defines a `BlockNumber` type as a `u32` and the API follows the Substrate defaults - if a chain has a different definitions, the API needs to be aware of this so it can actually decode (and encode) the type.
|
||||
|
||||
At this point just be aware of it, we will touch on types, custom chains and their impacts in a later section.
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ const api = await ApiPromise.create({ provider: wsProvider });
|
||||
console.log(api.genesisHash.toHex());
|
||||
```
|
||||
|
||||
We will have some explanation on the ES2015 syntax used next, but just a small note on the above - where other code is included (or just some previous boilerplate is used), you will see `...` in most of the examples. This is not due to lazyness, but rather just to keep things straight and to the point.
|
||||
We will have some explanation on the ES2015 syntax used next, but just a small note on the above - where other code is included (or just some previous boilerplate is used), you will see `...` in most of the examples. This is not due to laziness, but rather just to keep things straight and to the point.
|
||||
|
||||
## ES2015 Usage and examples
|
||||
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
# Extending extrinsics
|
||||
|
||||
On some chains, the need may arise to customize the extrinsic format. In this section we will explain what extrinsics and their payloads contain, explain how signed extensions work and provide a walk through of an advanced use-case where extrinsics are customized for a specific Substrate chain.
|
||||
|
||||
## Extensions
|
||||
|
||||
In Substrate (which forms the base of Polkadot and a number of custom chains), an extrinsic has a specific version, flag to indicating if it has been signed, the address, signature, extra data as well as the actual method with params. In addition, the signature is generated over the call and may include values that are not encoded into the final extrinsic.
|
||||
|
||||
For instance, with version 3 extrinsics, the signature payload contains the runtime spec version as well as the `genesisHash` and `blockHash` (the latter being equivalent to the `genesisHash` in case of immortal transactions), however while these 3 fields are signed together with the method data, they do not actually appear in the extrinsic itself. Rather the chain executing the transaction will retrieve this information, add it to the method data and compare the signatures thereof.
|
||||
|
||||
So in both the cases of the `genesisHash` and `specVersion`, if these do not match the signer version, the transaction won't be accepted - however the extrinsic doesn't explicitly carry this information in the data being transmitted, rather only implicitly as part of the signature. And it always forms part of the validation.
|
||||
|
||||
## Default extrinsics
|
||||
|
||||
With the above in-mind, the extrinsic format is explicitly defined as having the following structure in Substrate -
|
||||
|
||||
```rust
|
||||
pub struct UncheckedExtrinsic<Address, Call, Signature, Extra>
|
||||
where Extra: SignedExtension
|
||||
{
|
||||
pub signature: Option<(Address, Signature, Extra)>,
|
||||
pub function: Call,
|
||||
}
|
||||
```
|
||||
|
||||
The `Option` is here encoded such that is conveys both the extrinsic version `0x03` for Substrate 2.x chains (`0x01` for Substrate 1.x chains) as well as a high-bit that indicates if the transaction is signed or unsigned. (For unsigned the `signature` details therefore does not appear). The `SignedExtension` part defined both the data in the actual extrinsic as well as data, i.e. `AdditionalSigned`, that appears in the payload for the signature, but is not explicitly contained in the extrinsic.
|
||||
|
||||
The default `SignedExtension` for Substrate 2.x with extrinsic version 3 is defined as follow -
|
||||
|
||||
```rust
|
||||
pub type SignedExtra = (
|
||||
system::CheckVersion<Runtime>,
|
||||
system::CheckGenesis<Runtime>,
|
||||
system::CheckEra<Runtime>,
|
||||
system::CheckNonce<Runtime>,
|
||||
system::CheckWeight<Runtime>,
|
||||
balances::TakeFees<Runtime>,
|
||||
contracts::CheckBlockGasLimit<Runtime>,
|
||||
);
|
||||
```
|
||||
|
||||
Some of these are only checks, requiring no additional data in the payload or extrinsic itself, i.e. the contracts checks do exactly that. It only applies checks and invalidates when those checks are invalid. This is a powerful concept, for instance on the [initial Kusama chain this was used to limit the types of calls allowed](https://github.com/paritytech/polkadot/blob/f52c714ec3411eea58647d0f5176f4eb81660188/runtime/src/lib.rs#L117-L139).
|
||||
|
||||
## Extension deep-dive
|
||||
|
||||
For each of the default extensions, we will take a look through to understand the implications of the specific extension and how it relates to both the data contained in the extrinsic as well as the signature payload.
|
||||
|
||||
- `system::CheckVersion` - This checks that the spec version matches between the extrinsic and the chain. It takes no parameters which means that these is no explicit data in the extrinsic format for this field, however it has `type AdditionalSigned = u32` which means that a `u32` containing the runtime spec version is part of the signature payload.
|
||||
|
||||
- `system::CheckGenesis` - This checks that the `genesisHash` matches between extrinsic and chain. Like the previous check, no additional data is added to the extrinsic, however with `type AdditionalSigned = T::Hash`, the `genesisHash` is part of the signature payload.
|
||||
|
||||
- `system::CheckEra` - This checks the era (mortal or immortal) for the transaction being sent. It checks both the `era: Era` as part of the actual extrinsic and the `blockHash` via the `type AdditionalSigned = T::Hash`. This means that the extrinsic era is both in the data being signed and the extrinsic itself, while the `blockHash` the era applies to is only available in the signature payload.
|
||||
|
||||
- `system::CheckNonce` - This checks the nonce for the sending account. Unlike the preceding checks, it has no payload-specific data, however the `nonce: Compact<T::Index>` (`Index` is default `u32`) is applicable to both the extrinsic and, therefore, the actual signature payload as well.
|
||||
|
||||
- `system::CheckWeight` - This checks the weight and length of the block and ensure that it does not exceed the limits. It does not have any specific data attached to either the extrinsic nor payload, but rather just does calculations based on the weights and type of transaction received.
|
||||
|
||||
- `balances::TakeFees` - Consumes fees proportional to the length and weight of the transaction. It operates on the `fee: Compact<T::Balance>`, which means this value is included in both the extrinsic and subsequent payload being signed.
|
||||
|
||||
- `contracts::CheckBlockGasLimit` - As explained briefly above, this extension does not add data to the extrinsic, or the signature payload, however it ensures that the transaction does not exceeds the block gas limit.
|
||||
|
||||
## Extrinsic and signature payloads
|
||||
|
||||
With the above extension, the following formats for the extrinsic and payloads are the outcome of the application of the signed extension. For the extrinsic the following data is [always encoded for v3 extrinsics](https://github.com/polkadot-js/api/blob/8b0ef159c05bcb5d9b664546d0e7289e79b5c9d5/packages/types/src/primitive/Extrinsic/v3/Extrinsic.ts#L27) -
|
||||
|
||||
```js
|
||||
class ExtrinsicV3 extends Struct {
|
||||
constructor (value) {
|
||||
super({
|
||||
signer: 'Address',
|
||||
signature: 'Signature',
|
||||
era: 'ExtrinsicEra', // extra via system::CheckEra
|
||||
nonce: 'Compact<Index>', // extra via system::CheckNonce
|
||||
tip: 'Compact<Balance>', // extra via balances::TakeFees
|
||||
method: 'Call'
|
||||
}, value);
|
||||
}
|
||||
...
|
||||
```
|
||||
|
||||
The signature payload will contain the same information as the extrinsic, with the following [additional information](https://github.com/polkadot-js/api/blob/8b0ef159c05bcb5d9b664546d0e7289e79b5c9d5/packages/types/src/primitive/Extrinsic/v3/ExtrinsicPayload.ts#L33) as expected by the `AdditionalSigned` portions of the extensions -
|
||||
|
||||
```js
|
||||
class ExtrinsicPayloadV3 extends Struct {
|
||||
constructor (value) {
|
||||
super({
|
||||
method: 'Bytes',
|
||||
era: 'ExtrinsicEra', // extra via system::CheckEra
|
||||
nonce: 'Compact<Index>', // extra via system::CheckNonce
|
||||
tip: 'Compact<Balance>', // extra via balances::TakeFees
|
||||
specVersion: 'u32', // additional via system::CheckVersion
|
||||
genesisHash: 'Hash', // additional via system::CheckGenesis
|
||||
blockHash: 'Hash' // additional via system::CheckEra
|
||||
}, value);
|
||||
}
|
||||
...
|
||||
```
|
||||
|
||||
As per the above structures, it means that both the extrinsic sent on-chain as well as the data being signed to generate the signature is tied by the hip based on the logic the chain expects via `SignedExtension`. The API is only aware of the version of the extrinsic being used on-chain (it determines this on connection) and therefore only knows about the specific logic that has been coded for the extrinsic version.
|
||||
|
||||
## Extending existing or implementing new
|
||||
|
||||
When the API encodes or decodes an extrinsic, it uses the first `Option` byte to determine the version. Once it has this value, it will create a specific extrinsic via `createType('ExtrinsicV3', value)`. This means that at any point, you can supply your own version of either the `Extrinsic` or `ExtrinsicPayload` and you can do so via 2 avenues -
|
||||
|
||||
- If you are extending/replacing the existing version, you can inject your own types for both `ExtrinsicV3` and `ExtrinsicV3Payload` (assuming you are replacing v3)
|
||||
|
||||
- If you are adding a new version, you can add a handler for both `ExtrinsicUnknown` and `ExtrinsicPayloadUnknown`. These will be constructed when the version the API is aware of does not match with the on-chain version.
|
||||
|
||||
While we will not provide a full example of all the code here, the above links will show the existing implementations. However, assuming we have a chain where neither the nonce or tip is applicable (or we just don't care) and we are ignoring the check to the runtime versioning.
|
||||
|
||||
Additionally assuming that we have made the required `SignedExtension` updates by removing `system::CheckVersion`, `system::CheckNonce` and `balances::TakeFees`, we can do the following -
|
||||
|
||||
```js
|
||||
...
|
||||
class OwnExtrinsic extends Struct {
|
||||
constructor (value) {
|
||||
super({
|
||||
signer: 'Address',
|
||||
signature: 'Signature',
|
||||
era: 'ExtrinsicEra', // extra via system::CheckEra
|
||||
method: 'Call'
|
||||
}, value);
|
||||
}
|
||||
...
|
||||
}
|
||||
|
||||
class OwnExtrinsicPayload extends Struct {
|
||||
constructor (value) {
|
||||
super({
|
||||
method: 'Bytes',
|
||||
era: 'ExtrinsicEra', // extra via system::CheckEra
|
||||
genesisHash: 'Hash', // additional via system::CheckGenesis
|
||||
blockHash: 'Hash' // additional via system::CheckEra
|
||||
}, value);
|
||||
}
|
||||
...
|
||||
// signing logic needs to be included, as per existing
|
||||
}
|
||||
...
|
||||
|
||||
// inject our types at API construction
|
||||
const api = ApiPromise.create({
|
||||
types: {
|
||||
'ExtrinsicV3': OwnExtrinsic,
|
||||
'ExtrinsicV3Payload': OwnExtrinsicPayload,
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
The above example is certainly an advanced example, but it shows that all data types in the API can be adjusted and these adjustment can be provided to the API. In all cases, if you made updates to the formats and types of the actual runtime, you need to ensure that the API is aware of these changes.
|
||||
|
||||
In the above example, should these updates only be made on the node side, without the required API adjustments, the API will generate invalid transactions for the node since it is unaware of the changes and adjusted formats. Making the adjustments on only one side will mean that the signature verification can fail and that the format will not be decodable via the node.
|
||||
|
||||
(These extensions are not exposed via metadata at all, and would be quite difficult to do as well - since each of these have specific logic as well as data types assigned.)
|
||||
|
||||
## Using with TypeScript
|
||||
|
||||
The API is built with TypeScript (as are all projects in the [polkadot-js organization](https://github.com/polkadot-js/)) and as such allows developers using TS to have access to all the type interfaces defined on the chain, as well as having access to typings on interacting with the `api.*` namespaces. In the next section we will provide an overview of [what is available in terms of types and TypeScript](typescript.md).
|
||||
@@ -4,11 +4,11 @@ Yes, it really is as simple as [installing from npm](https://www.npmjs.com/packa
|
||||
|
||||
`yarn add @polkadot/api`
|
||||
|
||||
And it will be added and ready for use. The above will always install the latest stable release, which should allow you to connect to testsnets and local nodes that are tracking versioned releases for [Polkadot](https://github.com/paritytech/polkadot) and [Substrate](https://github.com/paritytech/substrate).
|
||||
And it will be added and ready for use. The above will always install the latest stable release, which should allow you to connect to test networks and local nodes that are tracking versioned releases for [Polkadot](https://github.com/paritytech/polkadot) and [Substrate](https://github.com/paritytech/substrate).
|
||||
|
||||
## Betas
|
||||
|
||||
For users who have a slightly higher appetite for risk, or are using bleeding-edge master branches of either Polkadot/Substrate, we also publish a beta version as soon as anything is merged into the API master branch. This version really contains all the latest fixes and features and is the version we actually use inside the polkadot-js projects - eating our own dogfood.
|
||||
For users who have a slightly higher appetite for risk, or are using bleeding-edge master branches of either Polkadot/Substrate, we also publish a beta version as soon as anything is merged into the API master branch. This version really contains all the latest fixes and features and is the version we actually use inside the polkadot-js projects - eating our own dog food.
|
||||
|
||||
To install a beta version, either to test or for support of a feature that is available in Substrate master (and has not yet made it to a stable api release), you can install it via the `@beta` tag, i.e.
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ This section will give a quick introduction into the Keyring, including the addi
|
||||
|
||||
They [@polkadot/keyring](https://github.com/polkadot-js/common/tree/master/packages/keyring) keyring is included directly with the API as a dependency, so it is directly importable (since the 0.92 version) alongside the API.
|
||||
|
||||
If you do opt to install it seperately, ensure that the version of `@polkadot/util-crypto` that is included with the API matches with the version of `@polkadot/keyring` installed. So if the API depends on `util-crypto 1.4.1`, it would make sense to include `keyring 1.4.1` as the installed version. (This helps in making sure extra versions of the libraries are not included as duplicates, especially in the case where bundles are created. Additionally, this makes sure that weird side-effects in the WASM initialization is avoided.)
|
||||
If you do opt to install it separately, ensure that the version of `@polkadot/util-crypto` that is included with the API matches with the version of `@polkadot/keyring` installed. So if the API depends on `util-crypto 1.4.1`, it would make sense to include `keyring 1.4.1` as the installed version. (This helps in making sure extra versions of the libraries are not included as duplicates, especially in the case where bundles are created. Additionally, this makes sure that weird side-effects in the WASM initialization is avoided.)
|
||||
|
||||
## Creating a keyring instance
|
||||
|
||||
@@ -27,7 +27,7 @@ In the above example, the import is self-explanatory. Upon creation we pass thro
|
||||
|
||||
So effectively, when creating an account and not specifying a type, it will be `sr25519` by default based on the above construction params, however we can also add an `ed25519` account and use it transparently in the same keyring.
|
||||
|
||||
One "trick" that is done implictly in the above sample is that that keyring is only initialized after the API. In the case of `sr25519` the keyring relies on a [WASM build](https://github.com/polkadot-js/wasm) of the [schnorrkel libraries](https://github.com/w3f/schnorrkel). Since the API inlitialization is already async, it initializes the WASM libraries are part of the setup.
|
||||
One "trick" that is done implicitly in the above sample is that that keyring is only initialized after the API. In the case of `sr25519` the keyring relies on a [WASM build](https://github.com/polkadot-js/wasm) of the [schnorrkel libraries](https://github.com/w3f/schnorrkel). Since the API inlitialization is already async, it initializes the WASM libraries are part of the setup.
|
||||
|
||||
However, this initialization can also be done explicitly, mostly for more advances use-cases, or in cases where the API won't be attached until much later -
|
||||
|
||||
@@ -52,7 +52,7 @@ The recommended catch-all approach to adding accounts is via `.addFromUri(<suri>
|
||||
// Some mnemonic phrase
|
||||
const PHRASE = 'entire material egg meadow latin bargain dutch coral blood melt acoustic thought';
|
||||
|
||||
// Add an account, straight menemonic
|
||||
// Add an account, straight mnemonic
|
||||
const newPair = keyring.addFromUri(PHRASE);
|
||||
|
||||
// (Advanced) add an account with a derivation path (hard & soft)
|
||||
@@ -62,7 +62,7 @@ const newDeri = keyring.addFromUri(`${PHRASE}//hard-derived/soft-derived`);
|
||||
const alice = keyring.addFromUri('//Alice', { name: 'Alice default' });
|
||||
```
|
||||
|
||||
The above additions cater for most of the usecases and aligns with the you would find in the Substrate `subkey`. Be very wary of the last "dev-seed" option, it is explicitly added for `subkey` compatibility and implies using the "known-everywhere" dev seed. It is however useful when running Polkadot/Substrate with a `--dev` flag.
|
||||
The above additions cater for most of the use cases and aligns with the you would find in the Substrate `subkey`. Be very wary of the last "dev-seed" option, it is explicitly added for `subkey` compatibility and implies using the "known-everywhere" dev seed. It is however useful when running Polkadot/Substrate with a `--dev` flag.
|
||||
|
||||
## Adding accounts with raw seeds
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ We've touched upon types in most previous sections, i.e. that these are driven b
|
||||
|
||||
## Everything is a type
|
||||
|
||||
Just to re-iterate from the above. Eveything returned by the API is a type and has a consistent interface. This means that a `Vec<u32>` (an array of `u32` values) as well as a `Struct` (an pre-defined object) or an `Enum` has the same consistent base interface. Specific types types will have values, based on the type - decorated and available.
|
||||
Just to re-iterate from the above. Everything returned by the API is a type and has a consistent interface. This means that a `Vec<u32>` (an array of `u32` values) as well as a `Struct` (an pre-defined object) or an `Enum` has the same consistent base interface. Specific types types will have values, based on the type - decorated and available.
|
||||
|
||||
As a minimum, anything returned by the API, be it a `Vec<...>`, `Option<...>`, `Struct` or any normal type will always have the following methods -
|
||||
|
||||
@@ -16,7 +16,7 @@ As a minimum, anything returned by the API, be it a `Vec<...>`, `Option<...>`, `
|
||||
|
||||
Additionally, the following getters and utilities are available -
|
||||
|
||||
- `.isEmpty` - `true` if the value is an all-empy value, i.e. `0` in for numbers, all-zero for Arrays (or anything `Uint8Array`), `false` is non-zero
|
||||
- `.isEmpty` - `true` if the value is an all-empty value, i.e. `0` in for numbers, all-zero for Arrays (or anything `Uint8Array`), `false` is non-zero
|
||||
- `.hash` - a `Hash` (once again with all the methods above) that is a `blake2-256` representation of the contained value
|
||||
|
||||
## Comparing types
|
||||
@@ -63,7 +63,7 @@ As a real-world example, when an extrinsic is applied, the `Phase` enum has one
|
||||
|
||||
An `Option<Type>` attempts to mimic the Rust approach of having `None` and `Some` available. This means the following getters & methods are available on an `Option` -
|
||||
|
||||
- `.isNone` - is `true` if no underlying values is warpped, effectively the same as `.isEmpty`
|
||||
- `.isNone` - is `true` if no underlying values is wrapped, effectively the same as `.isEmpty`
|
||||
- `.isSome` - this is `true` is a value is wrapped, i.e. if a `Option<u32>` has an actual underlying `u32`
|
||||
- `.unwrap()` - when `isSome`, this will return the wrapped value, i.e. for `Option<u32>`, this would return the `u32`. When the value is `isNone`, this call will throw an exception.
|
||||
- `.unwrapOr(<default value>)` - this extends `unwrap()`, returning the wrapped value when `isSome` and in the case of `isNone` it will return the `<default value>` passed.
|
||||
|
||||
@@ -4,7 +4,7 @@ Circling back to metadata, by default the metadata information (at this point in
|
||||
|
||||
Therefore to cater for all types, a mapping in done on the [@polkadot/types library](https://github.com/polkadot-js/api/tree/master/packages/types/src/interfaces) to define each of the types and align with their underlying structures as it maps to a default Polkadot or Substrate chain.
|
||||
|
||||
Additionally, the API contains some logic for chain type detection, for instance in the case of Substrate 1.x based chains, it will define `BlockNumber` & `Index` (nonce) as a `u64`, while for current-generation chains, these will be defined as `u32`. Some of the work in maintaining the API for Polkadot/Substrate is the addition of types as they appear and gets used in the Rust codebases.
|
||||
Additionally, the API contains some logic for chain type detection, for instance in the case of Substrate 1.x based chains, it will define `BlockNumber` & `Index` (nonce) as a `u64`, while for current-generation chains, these will be defined as `u32`. Some of the work in maintaining the API for Polkadot/Substrate is the addition of types as they appear and gets used in the Rust codebase.
|
||||
|
||||
There is a the [recommendation](install.md#betas) to use a `@polkadot/api@beta` should you wish to track the master branches of Polkadot or Substrate, since master changes for the addition of new types do not make it into a stable release immediately.
|
||||
|
||||
@@ -24,7 +24,7 @@ const api = await ApiPromise.create({
|
||||
});
|
||||
```
|
||||
|
||||
The above introduces the `types` registry, effectively allowing overrides and the definition of new types. The override above would mean that immediately the API will treat all occurences of `Balance` not as the default, but rather as the defined size.
|
||||
The above introduces the `types` registry, effectively allowing overrides and the definition of new types. The override above would mean that immediately the API will treat all occurrences of `Balance` not as the default, but rather as the defined size.
|
||||
|
||||
## User-defined types
|
||||
|
||||
@@ -52,7 +52,7 @@ const api = await ApiPromise.create({
|
||||
})
|
||||
```
|
||||
|
||||
The example above defines non-primitive types (as found in the specific implementation) as structs. Additionally it also shows the user-defined types can depend on other user-defined types with `Transaction` referencing both `TransactionInput` and `TransactionOutput`. Here you can reference any known types, i.e. in the above we have referenced primitives such as `u32` and `Signature` (itself an alias for `H512`).
|
||||
The example above defines non-primitive types (as found in the specific implementation) as structures. Additionally it also shows the user-defined types can depend on other user-defined types with `Transaction` referencing both `TransactionInput` and `TransactionOutput`. Here you can reference any known types, i.e. in the above we have referenced primitives such as `u32` and `Signature` (itself an alias for `H512`).
|
||||
|
||||
One form of types that appear regularly is enums, these can be defined as follow -
|
||||
|
||||
@@ -137,6 +137,6 @@ const api = await ApiPromise.create({
|
||||
|
||||
`Balance` would be defined as an `u128` at the end. Effectively based on the flow it is first registered as a `u32`, then overridden as a `u64` and finally overridden once more as a `u128` by the chain types.
|
||||
|
||||
## Using with TypeScript
|
||||
## Extending extrinsics
|
||||
|
||||
The API is built with TypeScript (as are all projects in the [polkadot-js organization](https://github.com/polkadot-js/)) and as such allows developers using TS to have access to all the type interfaces defined on the chain, as well as having access to typings on interacting with the `api.*` namespaces. In the next section we will provide an overview of [what is available in terms of types and TypeScript](typescript.md).
|
||||
On customized chains, it is possible to [extend the format of the extrinsics and extrinsic payload as customized on the chain](extrinsic.extend.md), next up we will look at this advanced use-case.
|
||||
|
||||
@@ -35,6 +35,8 @@ Events are emitted for certain operations on the runtime. The following sections
|
||||
|
||||
- **[treasury](#treasury)**
|
||||
|
||||
- **[utility](#utility)**
|
||||
|
||||
|
||||
___
|
||||
|
||||
@@ -287,3 +289,10 @@ ___
|
||||
|
||||
▸ **Spending**(`Balance`)
|
||||
- **summary**: We have ended a spend period and will now allocate funds.
|
||||
|
||||
___
|
||||
|
||||
|
||||
### utility
|
||||
|
||||
▸ **BatchExecuted**(`Vec<DispatchResult>`)
|
||||
|
||||
@@ -37,6 +37,8 @@ The following sections contain Extrinsics methods are part of the default Substr
|
||||
|
||||
- **[treasury](#treasury)**
|
||||
|
||||
- **[utility](#utility)**
|
||||
|
||||
|
||||
___
|
||||
|
||||
@@ -161,7 +163,7 @@ ___
|
||||
▸ **presentWinner**(candidate: `Address`, total: `Compact<BalanceOf>`, index: `Compact<VoteIndex>`)
|
||||
- **summary**: Claim that `candidate` is one of the top `carry_count + desired_seats` candidates. Only works iff the presentation period is active. `candidate` should have at least collected some non-zero `total` votes and `origin` must have enough funds to pay for a potential slash. # <weight> - O(voters) compute. - One DB change. # </weight>
|
||||
|
||||
▸ **proxySetApprovals**(votes: `Vec<bool>`, index: `Compact<VoteIndex>`, hint: `SetIndex`, value: `BalanceOf`)
|
||||
▸ **proxySetApprovals**(votes: `Vec<bool>`, index: `Compact<VoteIndex>`, hint: `SetIndex`, value: `Compact<BalanceOf>`)
|
||||
- **summary**: Set candidate approvals from a proxy. Approval slots stay valid as long as candidates in those slots are registered. # <weight> - Same as `set_approvals` with one additional storage read. # </weight>
|
||||
|
||||
▸ **reapInactiveVoter**(reporter_index: `Compact<u32>`, who: `Address`, who_index: `Compact<u32>`, assumed_vote_index: `Compact<VoteIndex>`)
|
||||
@@ -173,7 +175,7 @@ ___
|
||||
▸ **retractVoter**(index: `Compact<u32>`)
|
||||
- **summary**: Remove a voter. All votes are cancelled and the voter deposit is returned. The index must be provided as explained in [`voter_at`] function. Also removes the lock on the balance of the voter. See [`do_set_approvals()`]. # <weight> - O(1). - Two fewer DB entries, one DB change. # </weight>
|
||||
|
||||
▸ **setApprovals**(votes: `Vec<bool>`, index: `Compact<VoteIndex>`, hint: `SetIndex`, value: `BalanceOf`)
|
||||
▸ **setApprovals**(votes: `Vec<bool>`, index: `Compact<VoteIndex>`, hint: `SetIndex`, value: `Compact<BalanceOf>`)
|
||||
- **summary**: Set candidate approvals. Approval slots stay valid as long as candidates in those slots are registered. Locks `value` from the balance of `origin` indefinitely. Only [`retract_voter`] or [`reap_inactive_voter`] can unlock the balance. `hint` argument is interpreted differently based on: - if `origin` is setting approvals for the first time: The index will be checked for being a valid _hole_ in the voter list. - if the hint is correctly pointing to a hole, no fee is deducted from `origin`. - Otherwise, the call will succeed but the index is ignored and simply a push to the last chunk with free space happens. If the new push causes a new chunk to be created, a fee indicated by [`VotingFee`] is deducted. - if `origin` is already a voter: the index __must__ be valid and point to the correct position of the `origin` in the current voters list. Note that any trailing `false` votes in `votes` is ignored; In approval voting, not voting for a candidate and voting false, are equal. # <weight> - O(1). - Two extra DB entries, one DB change. - Argument `votes` is limited in length to number of candidates. # </weight>
|
||||
|
||||
▸ **setDesiredSeats**(count: `Compact<u32>`)
|
||||
@@ -285,6 +287,9 @@ ___
|
||||
▸ **fillBlock**()
|
||||
- **summary**: A big dispatch that will disallow any other transaction to be included.
|
||||
|
||||
▸ **killPrefix**(prefix: `Key`)
|
||||
- **summary**: Kill all storage items with a key that starts with the given prefix.
|
||||
|
||||
▸ **killStorage**(keys: `Vec<Key>`)
|
||||
- **summary**: Kill some items from storage.
|
||||
|
||||
@@ -355,3 +360,11 @@ ___
|
||||
|
||||
▸ **rejectProposal**(proposal_id: `Compact<ProposalIndex>`)
|
||||
- **summary**: Reject a proposed spend. The original deposit will be slashed. # <weight> - O(1). - Limited storage reads. - One DB clear. # </weight>
|
||||
|
||||
___
|
||||
|
||||
|
||||
### utility
|
||||
|
||||
▸ **batch**(calls: `Vec<Call>`)
|
||||
- **summary**: Send a batch of dispatch calls (only root).
|
||||
|
||||
+1
-1
@@ -9,5 +9,5 @@
|
||||
"packages": [
|
||||
"packages/*"
|
||||
],
|
||||
"version": "0.93.1"
|
||||
"version": "0.95.2"
|
||||
}
|
||||
|
||||
+8
-11
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "0.93.1",
|
||||
"version": "0.95.2",
|
||||
"private": true,
|
||||
"engines": {
|
||||
"yarn": "^1.10.1"
|
||||
@@ -9,15 +9,13 @@
|
||||
],
|
||||
"resolutions": {
|
||||
"babel-core": "^7.0.0-bridge.0",
|
||||
"typescript": "^3.6.3"
|
||||
"typescript": "^3.6.4"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "yarn build:interfaces && polkadot-dev-build-ts && yarn run build:methodsdoc && polkadot-dev-build-docs",
|
||||
"build:htmldoc": "yarn clean && typedoc --theme default --out docs/html",
|
||||
"build": "yarn build:interfaces && polkadot-dev-build-ts",
|
||||
"build:interfaces": "node packages/types/src/scripts/interfacesTsWrapper.js",
|
||||
"build:methodsdoc": "node packages/types/src/scripts/MetadataMdWrapper.js",
|
||||
"docs": "node packages/types/src/scripts/MetadataMdWrapper.js && polkadot-dev-build-docs",
|
||||
"chain:info": "node packages/types/src/scripts/extractChainWrapper.js",
|
||||
"check": "yarn lint",
|
||||
"lint": "eslint --ext .js,.jsx,.ts,.tsx . && tsc --noEmit --pretty",
|
||||
"clean": "polkadot-dev-clean-build",
|
||||
"postinstall": "polkadot-dev-yarn-only",
|
||||
@@ -30,11 +28,10 @@
|
||||
"test:watch": "jest --coverage --watch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.6.2",
|
||||
"@babel/core": "^7.6.4",
|
||||
"@babel/register": "^7.6.2",
|
||||
"@babel/runtime": "^7.6.2",
|
||||
"@polkadot/dev": "^0.31.1",
|
||||
"@polkadot/ts": "^0.1.73",
|
||||
"gh-pages": "^2.1.1"
|
||||
"@babel/runtime": "^7.6.3",
|
||||
"@polkadot/dev": "^0.32.0-beta.11",
|
||||
"@polkadot/ts": "^0.1.82"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@polkadot/api-contract",
|
||||
"version": "0.93.1",
|
||||
"version": "0.95.2",
|
||||
"description": "Interfaces for interacting with contracts and contract ABIs",
|
||||
"main": "index.js",
|
||||
"keywords": [
|
||||
@@ -26,7 +26,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/api-contract#readme",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.6.2",
|
||||
"@polkadot/types": "^0.93.1"
|
||||
"@babel/runtime": "^7.6.3",
|
||||
"@polkadot/types": "^0.95.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,108 +2,11 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { ContractABIArg } from './types';
|
||||
|
||||
import typesAbi from '../test/abi/types.json';
|
||||
import erc20Abi from '../test/contracts/Erc20.json';
|
||||
|
||||
import { Abi } from '.';
|
||||
|
||||
describe('Abi', (): void => {
|
||||
describe('types encoding', (): void => {
|
||||
let abi: Abi;
|
||||
|
||||
beforeAll((): void => {
|
||||
abi = new Abi(typesAbi);
|
||||
});
|
||||
|
||||
function check (method: string, args: ContractABIArg[], type: string | null): void {
|
||||
const fn = abi.messages[method];
|
||||
|
||||
expect(fn.args).toEqual(args);
|
||||
expect(fn.type).toEqual(type);
|
||||
}
|
||||
|
||||
it('has the primitive method with args & return', (): void => {
|
||||
check(
|
||||
'primitive',
|
||||
[
|
||||
{ name: 'bool', type: 'bool' },
|
||||
{ name: 'u32', type: 'u32' }
|
||||
],
|
||||
'bool'
|
||||
);
|
||||
});
|
||||
|
||||
it('has the vector method with args & return', (): void => {
|
||||
check(
|
||||
'vector',
|
||||
[
|
||||
{ name: 'vecU8', type: 'Vec<u8>' },
|
||||
{ name: 'vecU32', type: 'Vec<u32>' }
|
||||
],
|
||||
'Vec<bool>'
|
||||
);
|
||||
});
|
||||
|
||||
it('has the vector_fixed method with args & return', (): void => {
|
||||
check(
|
||||
'vectorFixed',
|
||||
[
|
||||
{ name: 'vecU8Length32', type: '[u8;32]' }
|
||||
],
|
||||
'[u32;8]'
|
||||
);
|
||||
});
|
||||
|
||||
it('has the option method with args & return', (): void => {
|
||||
check(
|
||||
'option',
|
||||
[
|
||||
{ name: 'optionU32', type: 'Option<u32>' }
|
||||
],
|
||||
'Option<bool>'
|
||||
);
|
||||
});
|
||||
|
||||
it('has the result method with return (empty)', (): void => {
|
||||
check(
|
||||
'result',
|
||||
[],
|
||||
'()'
|
||||
);
|
||||
});
|
||||
|
||||
it('allows for nested args', (): void => {
|
||||
check(
|
||||
'nested',
|
||||
[
|
||||
{ name: 'optionVec', type: 'Option<Vec<u32>>' }
|
||||
],
|
||||
'Vec<(u32,u64)>'
|
||||
);
|
||||
});
|
||||
|
||||
describe('messages', (): void => {
|
||||
it('fails when invalid args are supplied', (): void => {
|
||||
expect(
|
||||
(): Uint8Array => abi.messages.primitive(false)
|
||||
).toThrow(/Expected 2 arguments to contract messages.primitive, found 1/);
|
||||
});
|
||||
|
||||
it('encodes primitives correctly', (): void => {
|
||||
expect(
|
||||
abi.messages.primitive(true, 0x12345678)
|
||||
).toEqual(new Uint8Array([
|
||||
9 << 2, // total length (4 + 1 + 4)
|
||||
0x67, 0x2b, 0, 0, // 11111 -> hex (LE)
|
||||
1, // true
|
||||
0x78, 0x56, 0x34, 0x12 // u32
|
||||
]));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('erc20', (): void => {
|
||||
let abi: Abi;
|
||||
|
||||
|
||||
@@ -2,30 +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 { ContractABI, ContractABIFn, InterfaceAbi, AbiMessages } from './types';
|
||||
|
||||
import { ContractABI, ContractABIPre, ContractABIFn, InterfaceAbi, AbiMessages } from './types';
|
||||
import { stringCamelCase } from '@polkadot/util';
|
||||
|
||||
import { createMethod } from './method';
|
||||
import { validateAbi } from './validation';
|
||||
import ContractRegistry from './ContractRegistry';
|
||||
|
||||
export default class ContractAbi implements InterfaceAbi {
|
||||
export default class ContractAbi extends ContractRegistry implements InterfaceAbi {
|
||||
public readonly abi: ContractABI;
|
||||
|
||||
public readonly deploy: ContractABIFn;
|
||||
public readonly constructors: ContractABIFn[];
|
||||
|
||||
public readonly messages: AbiMessages = {};
|
||||
|
||||
public constructor (abi: ContractABI) {
|
||||
validateAbi(abi);
|
||||
public constructor (abi: ContractABIPre) {
|
||||
super(abi);
|
||||
[this.abi, this.constructors, this.messages] = this.decodeAbi(abi);
|
||||
}
|
||||
|
||||
this.abi = abi;
|
||||
this.deploy = createMethod('deploy', abi.deploy);
|
||||
private decodeAbi (abiPre: ContractABIPre): [ContractABI, ContractABIFn[], AbiMessages] {
|
||||
this.validateAbi(abiPre);
|
||||
|
||||
abi.messages.forEach((method): void => {
|
||||
const abi = this.convertAbi(abiPre);
|
||||
const constructors = abi.contract.constructors.map(
|
||||
(constructor, index): ContractABIFn => {
|
||||
return this.createMethod(`constructor ${index}`, constructor);
|
||||
}
|
||||
);
|
||||
|
||||
const messages: AbiMessages = {};
|
||||
abi.contract.messages.forEach((method): void => {
|
||||
const name = stringCamelCase(method.name);
|
||||
|
||||
this.messages[name] = createMethod(`messages.${name}`, method);
|
||||
messages[name] = this.createMethod(`messages.${name}`, method);
|
||||
});
|
||||
|
||||
return [abi, constructors, messages];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
// Copyright 2017-2019 @polkadot/api-contract 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 { CodecArg, TypeDef } from '@polkadot/types/types';
|
||||
import { ContractABIArgBasePre, ContractABIContract, ContractABIContractPre, ContractABIEvent, ContractABIEventPre, ContractABIFn, ContractABIFnArg, ContractABIMethod, ContractABIMethodBase, ContractABIMethodPre, ContractABI, ContractABIPre, ContractABIRange, ContractABIRangePre, ContractABIStorage, ContractABIStorageLayout, ContractABIStorageLayoutPre, ContractABIStoragePre, ContractABIStorageStruct, ContractABIStorageStructPre, ContractABITypePre } from './types';
|
||||
import { Compact } from '@polkadot/types';
|
||||
|
||||
import { assert, isNumber, isString, isNull, isObject, isUndefined, stringCamelCase } from '@polkadot/util';
|
||||
|
||||
import MetaRegistry from './MetaRegistry';
|
||||
import { createArgClass } from './method';
|
||||
|
||||
export default class ContractRegistry extends MetaRegistry {
|
||||
// Contract ABI helpers
|
||||
public validateArgs (name: string, args: ContractABIArgBasePre[]): void {
|
||||
assert(Array.isArray(args), `Expected 'args' to exist on ${name}`);
|
||||
|
||||
args.forEach((arg): void => {
|
||||
const unknownKeys = Object.keys(arg).filter((key): boolean => !['name', 'type'].includes(key));
|
||||
|
||||
assert(unknownKeys.length === 0, `Unknown keys ${unknownKeys.join(', ')} found in ABI args for ${name}`);
|
||||
assert(isNumber(arg.name) && isString(this.stringAt(arg.name)), `${name} args should have valid name `);
|
||||
assert(isNumber(arg.type.ty) && isObject(this.typeDefAt(arg.type.ty)), `${name} args should have valid type`);
|
||||
});
|
||||
}
|
||||
|
||||
public validateConstructors ({ contract: { constructors } }: ContractABIPre): void {
|
||||
constructors.forEach((constructor: ContractABIMethodPre, index): void => {
|
||||
const unknownKeys = Object.keys(constructor).filter((key): boolean => !['args', 'docs', 'name', 'selector'].includes(key));
|
||||
|
||||
assert(unknownKeys.length === 0, `Unknown keys ${unknownKeys.join(', ')} found in ABI constructor`);
|
||||
|
||||
this.validateArgs(`constructor ${index}`, constructor.args);
|
||||
});
|
||||
}
|
||||
|
||||
public validateMethods ({ contract: { messages } }: ContractABIPre): void {
|
||||
messages.forEach((method): void => {
|
||||
const unknownKeys = Object.keys(method).filter((key): boolean => !['args', 'docs', 'mutates', 'name', 'selector', 'return_type'].includes(key));
|
||||
|
||||
assert(unknownKeys.length === 0, `Unknown keys ${unknownKeys.join(', ')} found in ABI args for messages.${method.name}`);
|
||||
const { name, selector, return_type: returnType } = method;
|
||||
assert(isNumber(name) && isString(this.stringAt(name)), `Expected name for messages.${method.name}`);
|
||||
assert(isNumber(selector), `Expected selector for messages.${method.name}`);
|
||||
assert(isNull(returnType) || (isNumber(returnType.ty) && isObject(this.typeDefAt(returnType.ty))), `Expected return_type for messages.${method.name}`);
|
||||
|
||||
this.validateArgs(`messages.${method.name}`, method.args);
|
||||
});
|
||||
}
|
||||
|
||||
public validateAbi (abi: ContractABIPre): void {
|
||||
const unknownKeys = Object.keys(abi.contract).filter((key): boolean => !['constructors', 'docs', 'events', 'messages', 'name'].includes(key));
|
||||
assert(unknownKeys.length === 0, `Unknown fields ${unknownKeys.join(', ')} found in ABI`);
|
||||
|
||||
const { contract: { constructors, messages, name } } = abi;
|
||||
assert(constructors && messages && isString(this.stringAt(name)), 'ABI should have constructors, messages & name sections');
|
||||
|
||||
this.validateConstructors(abi);
|
||||
this.validateMethods(abi);
|
||||
}
|
||||
|
||||
public createMethod (name: string, method: Partial<ContractABIMethod> & ContractABIMethodBase): ContractABIFn {
|
||||
const args = method.args.map(({ name, type }): ContractABIFnArg => {
|
||||
assert(isObject(type), `Invalid type at index ${type}`);
|
||||
return {
|
||||
name: stringCamelCase(name),
|
||||
type
|
||||
};
|
||||
});
|
||||
const Clazz = createArgClass(args, isUndefined(method.selector) ? {} : { __selector: 'u32' });
|
||||
const baseStruct: { [index: string]: any } = { __selector: method.selector };
|
||||
const encoder = (...params: CodecArg[]): Uint8Array => {
|
||||
assert(params.length === args.length, `Expected ${args.length} arguments to contract ${name}, found ${params.length}`);
|
||||
|
||||
const u8a = new Clazz(
|
||||
args.reduce((mapped, { name }, index): Record<string, CodecArg> => {
|
||||
mapped[name] = params[index];
|
||||
|
||||
return mapped;
|
||||
}, { ...baseStruct })
|
||||
).toU8a();
|
||||
|
||||
return Compact.addLengthPrefix(u8a);
|
||||
};
|
||||
|
||||
const fn = (encoder as ContractABIFn);
|
||||
|
||||
fn.args = args;
|
||||
fn.isConstant = !(method.mutates || false);
|
||||
fn.type = method.returnType || null;
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
public convertAbi ({ contract, storage }: ContractABIPre): ContractABI {
|
||||
return {
|
||||
contract: this.convertContract(contract),
|
||||
storage: this.convertStorage(storage)
|
||||
};
|
||||
}
|
||||
|
||||
public convertArgs (args: ContractABIArgBasePre[]): any[] {
|
||||
return args.map(({ name, type, ...arg }) => ({ ...arg, name: this.stringAt(name), type: this.convertType(type) }));
|
||||
}
|
||||
|
||||
public convertType ({ ty, display_name: displayNameIndices }: ContractABITypePre): TypeDef {
|
||||
const displayName = this.stringsAt(displayNameIndices).join('::');
|
||||
return this.typeDefAt(ty, { displayName });
|
||||
}
|
||||
|
||||
public convertContract ({ constructors, messages, name, events, ...contract }: ContractABIContractPre): ContractABIContract {
|
||||
return {
|
||||
constructors: this.convertConstructors(constructors),
|
||||
messages: messages.map(method => this.convertMethod(method)),
|
||||
name: this.stringAt(name),
|
||||
...(events
|
||||
? { events: events.map(event => this.convertEvent(event)) }
|
||||
: {}),
|
||||
...contract
|
||||
};
|
||||
}
|
||||
|
||||
public convertConstructors (constructors: ContractABIMethodPre[]): ContractABIMethod[] {
|
||||
return constructors.map(
|
||||
(constructor: ContractABIMethodPre): ContractABIMethod => {
|
||||
return this.convertMethod(constructor);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public convertMethod ({ args, name, return_type: returnType, ...method }: ContractABIMethodPre): ContractABIMethod {
|
||||
return {
|
||||
...method,
|
||||
args: this.convertArgs(args),
|
||||
name: this.stringAt(name),
|
||||
returnType: returnType ? this.convertType(returnType) : null
|
||||
};
|
||||
}
|
||||
|
||||
public convertEvent ({ args }: ContractABIEventPre): ContractABIEvent {
|
||||
return {
|
||||
args: this.convertArgs(args)
|
||||
};
|
||||
}
|
||||
|
||||
public convertStorage (storage: ContractABIStoragePre): ContractABIStorage {
|
||||
return this.convertStorageStruct(storage);
|
||||
}
|
||||
|
||||
public convertStorageLayout (storageLayout: ContractABIStorageLayoutPre): ContractABIStorageLayout {
|
||||
if ((storageLayout as ContractABIStorageStructPre)['struct.type']) {
|
||||
return this.convertStorageStruct(storageLayout as ContractABIStorageStructPre);
|
||||
} else {
|
||||
return this.convertStorageRange(storageLayout as ContractABIRangePre);
|
||||
}
|
||||
}
|
||||
|
||||
public convertStorageStruct ({ 'struct.type': structType, 'struct.fields': structFields }: ContractABIStorageStructPre): ContractABIStorageStruct {
|
||||
return {
|
||||
'struct.type': this.typeDefAt(structType),
|
||||
'struct.fields': structFields.map(({ name, layout }) => ({
|
||||
name: this.stringAt(name),
|
||||
layout: this.convertStorageLayout(layout)
|
||||
}))
|
||||
};
|
||||
}
|
||||
|
||||
public convertStorageRange ({ 'range.elem_type': type, ...range }: ContractABIRangePre): ContractABIRange {
|
||||
return {
|
||||
...range,
|
||||
'range.elem_type': this.typeDefAt(type)
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright 2017-2019 @polkadot/types 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 fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
import MetaRegistry from './MetaRegistry';
|
||||
|
||||
import erc20Abi from '../test/contracts/Erc20.json';
|
||||
import sharedVecAbi from '../test/contracts/SharedVecV2.json';
|
||||
|
||||
describe('MetaRegistry', (): void => {
|
||||
describe('construction', (): void => {
|
||||
it('initializes from a contract ABI (ERC20)', (): void => {
|
||||
const metaRegistry = new MetaRegistry(erc20Abi);
|
||||
fs.writeFile(path.join(__dirname, '../test/compare/erc20.test.json'), JSON.stringify(metaRegistry.typeDefs, null, 2), function (err): void {
|
||||
if (err) throw err;
|
||||
});
|
||||
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
|
||||
it('initializes from a contract ABI (SharedVec)', (): void => {
|
||||
const metaRegistry = new MetaRegistry(sharedVecAbi);
|
||||
fs.writeFile(path.join(__dirname, '../test/compare/shared-vec.test.json'), JSON.stringify(metaRegistry.typeDefs, null, 2), function (err): void {
|
||||
if (err) throw err;
|
||||
});
|
||||
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,348 @@
|
||||
// Copyright 2017-2019 @polkadot/api-contract 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 { MetaRegistryItem, MetaRegistryJson, MetaTypeDefClikeEnum, MetaType, MetaTypeDefEnum, MetaTypeDefEnumVariant, MetaTypeDefEnumVariantStruct, MetaTypeDefEnumVariantTupleStruct, MetaTypeDefEnumVariantUnit, MetaTypeDefStruct, MetaTypeDefStructField, MetaTypeDefTupleStruct, MetaTypeDefUnion, MetaTypeIdCustom, MetaTypeIdVec, MetaTypeIdVecFixed, MetaTypeInfo, StringIndex, TypeDef, TypeDefInfo, TypeIndex } from '@polkadot/types/types';
|
||||
|
||||
import { assert } from '@polkadot/util';
|
||||
import { displayType, withTypeString } from '@polkadot/types';
|
||||
|
||||
const builtinMap: [(id: any) => boolean, MetaTypeInfo][] = [
|
||||
[(id: any): boolean => typeof id === 'string', MetaTypeInfo.BuiltinPlain],
|
||||
[(id: any): boolean => Array.isArray(id), MetaTypeInfo.BuiltinTuple],
|
||||
[(id: any): boolean => !!(id['array.type']), MetaTypeInfo.BuiltinVecFixed],
|
||||
[(id: any): boolean => !!(id['slice.type']), MetaTypeInfo.BuiltinVec]
|
||||
];
|
||||
|
||||
const typeMap: [string, MetaTypeInfo][] = [
|
||||
['enum.variants', MetaTypeInfo.Enum],
|
||||
['clike_enum.variants', MetaTypeInfo.ClikeEnum],
|
||||
['struct.fields', MetaTypeInfo.Struct],
|
||||
['tuple_struct.types', MetaTypeInfo.TupleStruct]
|
||||
];
|
||||
|
||||
function detectedType ({ def, id }: MetaType): MetaTypeInfo {
|
||||
assert(!(def as MetaTypeDefUnion)['union.fields'], 'Invalid union type definition found');
|
||||
|
||||
const lookup = def === 'builtin'
|
||||
? builtinMap.find(([test]): boolean => test(id))
|
||||
: typeMap.find(([test]): boolean => !!(def as any)[test]);
|
||||
|
||||
return lookup
|
||||
? lookup[1]
|
||||
: MetaTypeInfo.Null;
|
||||
}
|
||||
|
||||
class MetadataRegistryLookup {
|
||||
protected _strings: string[] = [];
|
||||
|
||||
protected _types: MetaType[] = [];
|
||||
|
||||
public typeDefs: TypeDef[] = [];
|
||||
|
||||
public constructor ({ registry: { strings, types } }: MetaRegistryJson) {
|
||||
this._strings = strings;
|
||||
this._types = types;
|
||||
}
|
||||
|
||||
protected hasItemAt (index: number, variant: MetaRegistryItem): boolean {
|
||||
switch (variant) {
|
||||
case MetaRegistryItem.String:
|
||||
return this._strings && !!this._strings[index - 1];
|
||||
case MetaRegistryItem.Type:
|
||||
return this._types && !!this._types[index - 1];
|
||||
case MetaRegistryItem.TypeDef:
|
||||
return this.typeDefs && !!this.typeDefs[index - 1];
|
||||
}
|
||||
}
|
||||
|
||||
protected itemAt (index: number, variant: MetaRegistryItem): any {
|
||||
assert(this.hasItemAt(index, variant), `MetaRegistry: Invalid ${variant} index ${index} found in metadata`);
|
||||
|
||||
switch (variant) {
|
||||
case MetaRegistryItem.String:
|
||||
return this._strings[index - 1];
|
||||
case MetaRegistryItem.Type:
|
||||
return this._types[index - 1];
|
||||
case MetaRegistryItem.TypeDef:
|
||||
return this.typeDefs[index - 1];
|
||||
}
|
||||
}
|
||||
|
||||
protected itemsAt (indices: number[], variant: MetaRegistryItem): any[] {
|
||||
return indices.map((index: number): string => this.itemAt(index, variant));
|
||||
}
|
||||
|
||||
protected stringAt (index: StringIndex): string {
|
||||
return this.itemAt(index, MetaRegistryItem.String);
|
||||
}
|
||||
|
||||
public stringsAt (indices: StringIndex[]): string[] {
|
||||
return this.itemsAt(indices, MetaRegistryItem.String);
|
||||
}
|
||||
|
||||
public typeAt (index: TypeIndex): MetaType {
|
||||
return this.itemAt(index, MetaRegistryItem.Type);
|
||||
}
|
||||
|
||||
public typesAt (indices: TypeIndex[]): MetaType[] {
|
||||
return this.itemsAt(indices, MetaRegistryItem.Type);
|
||||
}
|
||||
|
||||
public hasTypeDefAt (index: TypeIndex): boolean {
|
||||
return this.hasItemAt(index, MetaRegistryItem.TypeDef);
|
||||
}
|
||||
|
||||
public typeDefAt (index: TypeIndex, extra: Pick<TypeDef, never> = {}): TypeDef {
|
||||
return {
|
||||
...this.itemAt(index, MetaRegistryItem.TypeDef),
|
||||
...extra
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default class MetaRegistry extends MetadataRegistryLookup {
|
||||
public constructor (json: MetaRegistryJson) {
|
||||
super(json);
|
||||
|
||||
// Generate TypeDefs for each provided registry type
|
||||
this._types.forEach((_, index: number): void => this.setTypeDefAtIndex(index + 1));
|
||||
}
|
||||
|
||||
public setTypeDefAtIndex (typeIndex: TypeIndex): void {
|
||||
this.typeDefs[typeIndex - 1] = this.typeDefFromMetaType(this.typeAt(typeIndex), typeIndex);
|
||||
}
|
||||
|
||||
private typeDefIdFields ({ id }: MetaType): Pick<TypeDef, never> {
|
||||
const { 'custom.name': nameIndex, 'custom.namespace': namespaceIndices, 'custom.params': paramsIndices } = id as MetaTypeIdCustom;
|
||||
|
||||
if (!nameIndex) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return {
|
||||
name: this.stringAt(nameIndex),
|
||||
...(namespaceIndices && namespaceIndices.length
|
||||
? { namespace: this.stringsAt(namespaceIndices).join('::') }
|
||||
: {}
|
||||
),
|
||||
...(paramsIndices && paramsIndices.length
|
||||
? { params: this.typesAt(paramsIndices).map((type): TypeDef => this.typeDefFromMetaType(type)) }
|
||||
: {}
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
private typeDefDefFields (metaType: MetaType, typeIndex?: TypeIndex): Pick<TypeDef, never> {
|
||||
let typeDef;
|
||||
|
||||
switch (detectedType(metaType)) {
|
||||
case MetaTypeInfo.BuiltinPlain:
|
||||
typeDef = this.typeDefForBuiltinPlain(metaType.id as string);
|
||||
break;
|
||||
case MetaTypeInfo.BuiltinTuple:
|
||||
typeDef = this.typeDefForBuiltinTuple(metaType.id as TypeIndex[]);
|
||||
break;
|
||||
case MetaTypeInfo.BuiltinVec:
|
||||
typeDef = this.typeDefForBuiltinVec(metaType.id as MetaTypeIdVec, typeIndex);
|
||||
break;
|
||||
case MetaTypeInfo.BuiltinVecFixed:
|
||||
typeDef = this.typeDefForBuiltinVecFixed(metaType.id as MetaTypeIdVecFixed, typeIndex);
|
||||
break;
|
||||
case MetaTypeInfo.Enum:
|
||||
typeDef = this.typeDefForEnum(metaType.def as MetaTypeDefEnum, metaType.id as MetaTypeIdCustom, typeIndex);
|
||||
break;
|
||||
case MetaTypeInfo.ClikeEnum:
|
||||
typeDef = this.typeDefForClikeEnum(metaType.def as MetaTypeDefClikeEnum);
|
||||
break;
|
||||
case MetaTypeInfo.Struct:
|
||||
typeDef = this.typeDefForStruct(metaType.def as MetaTypeDefStruct);
|
||||
break;
|
||||
case MetaTypeInfo.TupleStruct:
|
||||
typeDef = this.typeDefForTupleStruct(metaType.def as MetaTypeDefTupleStruct);
|
||||
break;
|
||||
case MetaTypeInfo.Null:
|
||||
default:
|
||||
throw new Error(`Invalid type detected at index ${typeIndex}`);
|
||||
}
|
||||
|
||||
return typeDef;
|
||||
}
|
||||
|
||||
public typeDefFromMetaType (metaType: MetaType, typeIndex?: TypeIndex): TypeDef {
|
||||
return withTypeString({
|
||||
info: TypeDefInfo.Null,
|
||||
type: '',
|
||||
...this.typeDefDefFields(metaType, typeIndex),
|
||||
...this.typeDefIdFields(metaType)
|
||||
}) as TypeDef;
|
||||
}
|
||||
|
||||
public typeDefFromMetaTypeAt (typeIndex: TypeIndex): TypeDef {
|
||||
if (!this.hasTypeDefAt(typeIndex)) {
|
||||
this.setTypeDefAtIndex(typeIndex);
|
||||
}
|
||||
|
||||
return this.typeDefAt(typeIndex);
|
||||
}
|
||||
|
||||
private typeDefForEnumVariant (variant: MetaTypeDefEnumVariant): Pick<TypeDef, any> {
|
||||
const { 'unit_variant.name': unitNameIndex } = variant as MetaTypeDefEnumVariantUnit;
|
||||
|
||||
if (unitNameIndex) {
|
||||
return {
|
||||
info: TypeDefInfo.Plain,
|
||||
name: this.stringAt(unitNameIndex),
|
||||
type: 'Null'
|
||||
};
|
||||
}
|
||||
|
||||
const { 'tuple_struct_variant.name': tupleStructVariantNameIndex } = variant as MetaTypeDefEnumVariantTupleStruct;
|
||||
|
||||
if (tupleStructVariantNameIndex) {
|
||||
return this.typeDefForTupleStruct(variant as MetaTypeDefEnumVariantTupleStruct);
|
||||
}
|
||||
|
||||
const { 'struct_variant.name': structVariantNameIndex } = variant as MetaTypeDefEnumVariantStruct;
|
||||
|
||||
if (structVariantNameIndex) {
|
||||
return this.typeDefForStruct(variant as MetaTypeDefEnumVariantStruct);
|
||||
}
|
||||
|
||||
return {
|
||||
info: TypeDefInfo.Null,
|
||||
type: 'Null'
|
||||
};
|
||||
}
|
||||
|
||||
private typeDefForBuiltinPlain (id: string): Pick<TypeDef, never> {
|
||||
return {
|
||||
info: TypeDefInfo.Plain,
|
||||
type: id
|
||||
};
|
||||
}
|
||||
|
||||
private typeDefForBuiltinTuple (id: TypeIndex[]): Pick<TypeDef, never> {
|
||||
const sub = id.map((tupleTypeIndex: number): TypeDef => this.typeDefFromMetaTypeAt(tupleTypeIndex));
|
||||
|
||||
return {
|
||||
info: TypeDefInfo.Tuple,
|
||||
sub
|
||||
};
|
||||
}
|
||||
|
||||
private typeDefForBuiltinVec (id: MetaTypeIdVec, typeIndex?: TypeIndex): Pick<TypeDef, never> {
|
||||
const { 'slice.type': vecTypeIndex } = id;
|
||||
|
||||
assert(!typeIndex || vecTypeIndex !== typeIndex, `MetaRegistry: self-referencing registry type at index ${typeIndex}`);
|
||||
|
||||
const type = displayType(this.typeDefFromMetaTypeAt(vecTypeIndex));
|
||||
assert(type && type.length > 0, `MetaRegistry: Invalid builtin Vec type found at index ${typeIndex}`);
|
||||
|
||||
return {
|
||||
info: TypeDefInfo.Vec,
|
||||
type: `Vec<${type}>`,
|
||||
sub: this.typeDefFromMetaTypeAt(vecTypeIndex)
|
||||
};
|
||||
}
|
||||
|
||||
private typeDefForBuiltinVecFixed (id: MetaTypeIdVecFixed, typeIndex?: TypeIndex): Pick<TypeDef, never> {
|
||||
const { 'array.type': vecTypeIndex, 'array.len': vecLength } = id;
|
||||
|
||||
assert(!vecLength || vecLength <= 256, 'MetaRegistry: Only support for [Type; <length>], where length <= 256');
|
||||
assert(!typeIndex || vecTypeIndex !== typeIndex, `MetaRegistry: self-referencing registry type at index ${typeIndex}`);
|
||||
|
||||
const type = displayType(this.typeDefFromMetaTypeAt(vecTypeIndex));
|
||||
assert(type && type.length > 0, `MetaRegistry: Invalid vector type found at index ${typeIndex}`);
|
||||
|
||||
return {
|
||||
info: TypeDefInfo.VecFixed,
|
||||
ext: { length: vecLength, type },
|
||||
type: `[${type};${vecLength}]`,
|
||||
sub: this.typeDefFromMetaTypeAt(vecTypeIndex)
|
||||
};
|
||||
}
|
||||
|
||||
private typeDefForEnum (def: MetaTypeDefEnum, id: MetaTypeIdCustom, typeIndex?: TypeIndex): Pick<TypeDef, any> {
|
||||
const name = id && this.stringAt(id['custom.name']);
|
||||
|
||||
switch (name) {
|
||||
case 'Option':
|
||||
return this.typeDefForOption(id, typeIndex);
|
||||
case 'Result':
|
||||
return this.typeDefForResult(id, typeIndex);
|
||||
default: {
|
||||
const sub = def['enum.variants'].map(variant => this.typeDefForEnumVariant(variant));
|
||||
|
||||
return {
|
||||
info: TypeDefInfo.Enum,
|
||||
sub
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private typeDefForClikeEnum (def: MetaTypeDefClikeEnum): Pick<TypeDef, never> {
|
||||
return {
|
||||
info: TypeDefInfo.Enum,
|
||||
sub: def['clike_enum.variants'].map(({ name: nameIndex, discriminant }): TypeDef => ({
|
||||
ext: { discriminant },
|
||||
info: TypeDefInfo.Plain,
|
||||
name: this.stringAt(nameIndex),
|
||||
type: 'Null'
|
||||
}))
|
||||
};
|
||||
}
|
||||
|
||||
public typeDefForOption (id: MetaTypeIdCustom, typeIndex?: TypeIndex): Pick<TypeDef, any> {
|
||||
assert(id['custom.params'] && id['custom.params'][0], `Invalid Option type defined at index ${typeIndex}`);
|
||||
|
||||
return {
|
||||
info: TypeDefInfo.Option,
|
||||
sub: this.typeDefFromMetaTypeAt(id['custom.params']![0])
|
||||
};
|
||||
}
|
||||
|
||||
public typeDefForResult (id: MetaTypeIdCustom, typeIndex?: TypeIndex): Pick<TypeDef, any> {
|
||||
assert(id['custom.params'] && id['custom.params'][0] && id['custom.params'][1], `Invalid Result type defined at index ${typeIndex}`);
|
||||
|
||||
return {
|
||||
info: TypeDefInfo.Result,
|
||||
sub: id['custom.params']!.map((typeIndex): TypeDef => this.typeDefFromMetaTypeAt(typeIndex))
|
||||
};
|
||||
}
|
||||
|
||||
public typeDefForStruct (def: MetaTypeDefStruct | MetaTypeDefEnumVariantStruct): Pick<TypeDef, any> {
|
||||
const structFields = (def as MetaTypeDefStruct)['struct.fields'] || (def as MetaTypeDefEnumVariantStruct)['struct_variant.fields'];
|
||||
const structNameIndex = (def as MetaTypeDefEnumVariantStruct)['struct_variant.name'];
|
||||
|
||||
return withTypeString({
|
||||
info: TypeDefInfo.Struct,
|
||||
...(structNameIndex
|
||||
? { name: this.stringAt(structNameIndex) }
|
||||
: {}
|
||||
),
|
||||
sub: structFields.map((field: MetaTypeDefStructField): TypeDef => ({
|
||||
...this.typeDefFromMetaTypeAt(field.type),
|
||||
name: this.stringAt(field.name)
|
||||
}))
|
||||
});
|
||||
}
|
||||
|
||||
private typeDefForTupleStruct (def: MetaTypeDefTupleStruct | MetaTypeDefEnumVariantTupleStruct): Pick<TypeDef, any> {
|
||||
const tupleStructTypes = (def as MetaTypeDefTupleStruct)['tuple_struct.types'] || (def as MetaTypeDefEnumVariantTupleStruct)['tuple_struct_variant.types'];
|
||||
const tupleStructNameIndex = (def as MetaTypeDefEnumVariantTupleStruct)['tuple_struct_variant.name'];
|
||||
|
||||
return withTypeString({
|
||||
info: TypeDefInfo.Tuple,
|
||||
...(tupleStructNameIndex
|
||||
? { name: this.stringAt(tupleStructNameIndex) }
|
||||
: {}
|
||||
),
|
||||
sub: tupleStructTypes.map((fieldIndex: number, index: number): TypeDef => ({
|
||||
...this.typeDefFromMetaTypeAt(fieldIndex),
|
||||
index
|
||||
}))
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { SubmittableModuleExtrinsics } from '@polkadot/api/types';
|
||||
import { ApiObject, ContractABI, ContractBase } from './types';
|
||||
import { ApiObject, ContractABIPre, ContractBase } from './types';
|
||||
|
||||
import { assert } from '@polkadot/util';
|
||||
|
||||
@@ -17,7 +17,7 @@ export default abstract class RxBase implements ContractBase<'rxjs'> {
|
||||
|
||||
public readonly apiContracts: SubmittableModuleExtrinsics<'rxjs'>;
|
||||
|
||||
public constructor (api: ApiObject<'rxjs'>, abi: ContractABI | Abi) {
|
||||
public constructor (api: ApiObject<'rxjs'>, abi: ContractABIPre | Abi) {
|
||||
this.abi = abi instanceof Abi
|
||||
? abi
|
||||
: new Abi(abi);
|
||||
|
||||
@@ -5,13 +5,14 @@
|
||||
import { SubmittableResultImpl } from '@polkadot/api/types';
|
||||
import { AccountId, Address, Hash } from '@polkadot/types/interfaces';
|
||||
import { IKeyringPair } from '@polkadot/types/types';
|
||||
import { ContractABI } from './types';
|
||||
import { ContractABIPre } from './types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { ApiRx, SubmittableResult } from '@polkadot/api';
|
||||
import { createType } from '@polkadot/types';
|
||||
import { assert } from '@polkadot/util';
|
||||
|
||||
import Abi from './Abi';
|
||||
import RxBase from './RxBase';
|
||||
@@ -37,16 +38,17 @@ class BlueprintCreateResult extends SubmittableResult {
|
||||
export default class Blueprint extends RxBase {
|
||||
public readonly codeHash: Hash;
|
||||
|
||||
public constructor (api: ApiRx, abi: ContractABI | Abi, codeHash: string | Hash) {
|
||||
public constructor (api: ApiRx, abi: ContractABIPre | Abi, codeHash: string | Hash) {
|
||||
super(api, abi);
|
||||
|
||||
this.codeHash = createType('Hash', codeHash);
|
||||
}
|
||||
|
||||
public deployContract (endowment: number | BN, maxGas: number | BN, ...params: any[]): BlueprintCreate {
|
||||
public deployContract (constructorIndex = 0, endowment: number | BN, maxGas: number | BN, ...params: any[]): BlueprintCreate {
|
||||
assert(!!this.abi.constructors[constructorIndex], `Specified constructor index ${constructorIndex} does not exist`);
|
||||
const signAndSend = (account: IKeyringPair | string | AccountId | Address): BlueprintCreateResultSubscription => {
|
||||
return this.apiContracts
|
||||
.create(endowment, maxGas, this.codeHash, this.abi.deploy(...params))
|
||||
.create(endowment, maxGas, this.codeHash, this.abi.constructors[constructorIndex](...params))
|
||||
.signAndSend(account)
|
||||
.pipe(map(this.createResult));
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import { SubmittableResultImpl } from '@polkadot/api/types';
|
||||
import { AccountId, Address, Hash } from '@polkadot/types/interfaces';
|
||||
import { IKeyringPair } from '@polkadot/types/types';
|
||||
import { ContractABI } from './types';
|
||||
import { ContractABIPre } from './types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import { Observable } from 'rxjs';
|
||||
@@ -50,7 +50,7 @@ class CodePutCodeResult extends SubmittableResult {
|
||||
export default class RxCode extends RxBase {
|
||||
public readonly code: Uint8Array;
|
||||
|
||||
public constructor (api: ApiRx, abi: ContractABI | Abi, wasm: string | Uint8Array) {
|
||||
public constructor (api: ApiRx, abi: ContractABIPre | Abi, wasm: string | Uint8Array) {
|
||||
super(api, abi);
|
||||
|
||||
this.code = u8aToU8a(wasm);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
import { AccountId, Address } from '@polkadot/types/interfaces';
|
||||
import { IKeyringPair } from '@polkadot/types/types';
|
||||
import { ContractABI, ContractABIFn, InterfaceContract, InterfaceContractCalls } from './types';
|
||||
import { ContractABIPre, ContractABIFn, InterfaceContract, InterfaceContractCalls } from './types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import { Observable } from 'rxjs';
|
||||
@@ -27,12 +27,12 @@ export default class RxContract extends RxBase implements InterfaceContract {
|
||||
|
||||
public readonly calls: InterfaceContractCalls = {};
|
||||
|
||||
public constructor (api: ApiRx, abi: ContractABI | Abi, address: string | AccountId | Address) {
|
||||
public constructor (api: ApiRx, abi: ContractABIPre | Abi, address: string | AccountId | Address) {
|
||||
super(api, abi);
|
||||
|
||||
this.address = createType('Address', address);
|
||||
|
||||
Object.entries(abi.messages).forEach(([name]): void => {
|
||||
Object.entries(this.abi.messages).forEach(([name]): void => {
|
||||
this.calls[name] = (fn: ContractABIFn): CallResult =>
|
||||
(value: BN | number, maxGas: BN | number, ...params: any[]): ContractCall =>
|
||||
this.apiContracts.call(this.address, value, maxGas, fn(...params));
|
||||
|
||||
@@ -2,68 +2,19 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { CodecArg, Constructor } from '@polkadot/types/types';
|
||||
import { ContractABIFn, ContractABIFnArg, ContractABIMethod, ContractABIMethodBase, ContractABITypes } from './types';
|
||||
import { Constructor } from '@polkadot/types/types';
|
||||
import { ContractABIFnArg } from './types';
|
||||
|
||||
import { Compact, createClass } from '@polkadot/types';
|
||||
import { assert, isString, isUndefined, stringCamelCase } from '@polkadot/util';
|
||||
|
||||
export function typeToString (type: ContractABITypes): string {
|
||||
if (isString(type)) {
|
||||
return type;
|
||||
} else if (Array.isArray(type)) {
|
||||
return `(${type.map((type): string => typeToString(type)).join(',')})`;
|
||||
} else if (type['Option<T>']) {
|
||||
return `Option<${typeToString(type['Option<T>'].T)}>`;
|
||||
} else if (type['Result<T,E>']) {
|
||||
return '()'; // Result is not supported, but only applicable for returns
|
||||
} else if (type['Vec<T>']) {
|
||||
return `Vec<${typeToString(type['Vec<T>'].T)}>`;
|
||||
} else if (type['[T;n]']) {
|
||||
return `[${typeToString(type['[T;n]'].T)};${type['[T;n]'].n}]`;
|
||||
}
|
||||
|
||||
throw new Error(`Unknown type specified ${JSON.stringify(type)}`);
|
||||
}
|
||||
import { createClass, encodeType } from '@polkadot/types';
|
||||
|
||||
export function createArgClass (args: ContractABIFnArg[], baseDef: Record<string, string>): Constructor {
|
||||
return createClass(
|
||||
JSON.stringify(
|
||||
args.reduce((base: Record<string, any>, { name, type }): Record<string, any> => {
|
||||
base[name] = type;
|
||||
base[name] = encodeType(type);
|
||||
|
||||
return base;
|
||||
}, baseDef)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export function createMethod (name: string, method: Partial<ContractABIMethod> & ContractABIMethodBase): ContractABIFn {
|
||||
const args: ContractABIFnArg[] = method.args.map(({ name, type }): ContractABIFnArg => ({
|
||||
name: stringCamelCase(name),
|
||||
type: typeToString(type)
|
||||
}));
|
||||
const Clazz = createArgClass(args, isUndefined(method.selector) ? {} : { __selector: 'u32' });
|
||||
const baseStruct: { [index: string]: any } = { __selector: method.selector };
|
||||
const encoder = (...params: CodecArg[]): Uint8Array => {
|
||||
assert(params.length === args.length, `Expected ${args.length} arguments to contract ${name}, found ${params.length}`);
|
||||
|
||||
const u8a = new Clazz(
|
||||
args.reduce((mapped, { name }, index): Record<string, CodecArg> => {
|
||||
mapped[name] = params[index];
|
||||
|
||||
return mapped;
|
||||
}, { ...baseStruct })
|
||||
).toU8a();
|
||||
|
||||
return Compact.addLengthPrefix(u8a);
|
||||
};
|
||||
|
||||
const fn = (encoder as ContractABIFn);
|
||||
|
||||
fn.args = args;
|
||||
fn.isConstant = !(method.mutates || false);
|
||||
fn.type = method.return_type ? typeToString(method.return_type) : null;
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
import { SubmittableModuleExtrinsics } from '@polkadot/api/types';
|
||||
import { Address } from '@polkadot/types/interfaces';
|
||||
import { CodecArg } from '@polkadot/types/types';
|
||||
import { MetaRegistryJson, StringIndex, TypeIndex, TypeDef } from '@polkadot/types/codec/create/types';
|
||||
|
||||
import { ApiPromise, ApiRx } from '@polkadot/api';
|
||||
|
||||
@@ -12,67 +13,159 @@ export type ApiObject<ApiType> = ApiType extends 'rxjs'
|
||||
? ApiRx
|
||||
: ApiPromise;
|
||||
|
||||
export interface ContractABITypesStruct {
|
||||
'Option<T>'?: {
|
||||
T: ContractABITypes;
|
||||
};
|
||||
'Result<T,E>'?: {
|
||||
T: ContractABITypes;
|
||||
E: ContractABITypes;
|
||||
};
|
||||
'Vec<T>'?: {
|
||||
T: ContractABITypes;
|
||||
};
|
||||
'[T;n]'?: {
|
||||
T: ContractABITypes;
|
||||
n: number;
|
||||
};
|
||||
export interface ContractABITypePre {
|
||||
ty: TypeIndex;
|
||||
display_name: StringIndex[];
|
||||
}
|
||||
|
||||
export type ContractABITypes = string | ContractABITypesStruct | (string | ContractABITypesStruct)[];
|
||||
export interface ContractABIArgBasePre {
|
||||
name: StringIndex;
|
||||
type: ContractABITypePre;
|
||||
}
|
||||
|
||||
export interface ContractABIArg {
|
||||
export interface ContractABIArgBase {
|
||||
name: string;
|
||||
type: ContractABITypes;
|
||||
type: TypeDef;
|
||||
}
|
||||
|
||||
export type ContractABIMethodArgPre = ContractABIArgBasePre;
|
||||
|
||||
export type ContractABIMethodArg = ContractABIArgBase;
|
||||
|
||||
export interface ContractABIMethodBase {
|
||||
args: ContractABIArg[];
|
||||
args: ContractABIMethodArg[];
|
||||
}
|
||||
|
||||
export interface ContractABIMethod extends ContractABIMethodBase {
|
||||
export interface ContractABIMethodBasePre {
|
||||
args: ContractABIMethodArgPre[];
|
||||
}
|
||||
|
||||
export interface ContractABIMethodCommon {
|
||||
docs?: ContractABIDocs;
|
||||
mutates?: boolean;
|
||||
name: string;
|
||||
selector: number;
|
||||
return_type: ContractABITypes | null;
|
||||
}
|
||||
|
||||
export interface ContractABIMethodPre extends ContractABIMethodCommon, ContractABIMethodBasePre {
|
||||
name: StringIndex;
|
||||
return_type: ContractABITypePre | null;
|
||||
}
|
||||
|
||||
export interface ContractABIMethod extends ContractABIMethodCommon {
|
||||
args: ContractABIMethodArg[];
|
||||
name: string;
|
||||
returnType: TypeDef | null;
|
||||
}
|
||||
|
||||
export interface ContractABIContractCommon {
|
||||
docs?: ContractABIDocs;
|
||||
}
|
||||
|
||||
export interface ContractABIContractPre extends ContractABIContractCommon {
|
||||
constructors: ContractABIMethodPre[];
|
||||
messages: ContractABIMethodPre[];
|
||||
name: StringIndex;
|
||||
events?: ContractABIEventPre[];
|
||||
docs?: ContractABIDocs;
|
||||
}
|
||||
|
||||
export interface ContractABIContract extends ContractABIContractCommon {
|
||||
constructors: ContractABIMethod[];
|
||||
messages: ContractABIMethod[];
|
||||
name: string;
|
||||
events?: ContractABIEvent[];
|
||||
docs?: ContractABIDocs;
|
||||
}
|
||||
|
||||
export interface ContractABIPre extends MetaRegistryJson {
|
||||
storage: ContractABIStoragePre;
|
||||
contract: ContractABIContractPre;
|
||||
}
|
||||
|
||||
export interface ContractABI {
|
||||
deploy: ContractABIMethodBase;
|
||||
messages: ContractABIMethod[];
|
||||
name: string;
|
||||
storage: ContractABIStorage;
|
||||
contract: ContractABIContract;
|
||||
}
|
||||
|
||||
export interface ContractABIFnArg {
|
||||
name: string;
|
||||
type: string;
|
||||
type: TypeDef;
|
||||
}
|
||||
|
||||
export interface ContractABIMeta {
|
||||
args: ContractABIFnArg[];
|
||||
isConstant: boolean;
|
||||
type: string | null;
|
||||
type: TypeDef | null;
|
||||
}
|
||||
|
||||
export interface ContractABIFn extends ContractABIMeta {
|
||||
(...args: CodecArg[]): Uint8Array;
|
||||
}
|
||||
|
||||
export interface ContractABIEventArgBase {
|
||||
indexed: boolean;
|
||||
}
|
||||
|
||||
export interface ContractABIEventArgPre extends ContractABIArgBasePre, ContractABIEventArgBase {}
|
||||
|
||||
export interface ContractABIEventArg extends ContractABIArgBase, ContractABIEventArgBase {}
|
||||
|
||||
export type ContractABIDocs = string[];
|
||||
|
||||
export interface ContractABIEventPre {
|
||||
args: ContractABIEventArgPre[];
|
||||
}
|
||||
|
||||
export interface ContractABIEvent {
|
||||
args: ContractABIEventArg[];
|
||||
}
|
||||
|
||||
export interface ContractABIRangeBase {
|
||||
'range.offset': number[];
|
||||
'range.len': number;
|
||||
}
|
||||
|
||||
export interface ContractABIRangePre extends ContractABIRangeBase {
|
||||
'range.elem_type': TypeIndex;
|
||||
}
|
||||
|
||||
export interface ContractABIRange extends ContractABIRangeBase {
|
||||
'range.elem_type': TypeDef;
|
||||
}
|
||||
|
||||
export type ContractABIStorageLayoutPre = ContractABIStorageStructPre | ContractABIRangePre;
|
||||
|
||||
export type ContractABIStorageLayout = ContractABIStorageStruct | ContractABIRange;
|
||||
|
||||
export interface ContractABIStorageStructFieldPre {
|
||||
name: StringIndex;
|
||||
layout: ContractABIStorageLayoutPre;
|
||||
}
|
||||
|
||||
export interface ContractABIStorageStructField {
|
||||
name: string;
|
||||
layout: ContractABIStorageLayout;
|
||||
}
|
||||
|
||||
export interface ContractABIStorageStructPre {
|
||||
'struct.type': TypeIndex;
|
||||
'struct.fields': ContractABIStorageStructFieldPre[];
|
||||
}
|
||||
|
||||
export interface ContractABIStorageStruct {
|
||||
'struct.type': TypeDef;
|
||||
'struct.fields': ContractABIStorageStructField[];
|
||||
}
|
||||
|
||||
export type ContractABIStoragePre = ContractABIStorageStructPre;
|
||||
|
||||
export type ContractABIStorage = ContractABIStorageStruct;
|
||||
|
||||
export type AbiMessages = Record<string, ContractABIFn>;
|
||||
|
||||
export interface InterfaceAbi {
|
||||
readonly abi: ContractABI;
|
||||
readonly deploy: ContractABIFn;
|
||||
readonly constructors: ContractABIFn[];
|
||||
readonly messages: AbiMessages;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,50 +0,0 @@
|
||||
// Copyright 2017-2019 @polkadot/api-contract 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 { ContractABI, ContractABIArg } from './types';
|
||||
|
||||
import { assert, isNumber, isNull, isString, isObject } from '@polkadot/util';
|
||||
|
||||
export function validateArgs (name: string, args: ContractABIArg[]): void {
|
||||
assert(Array.isArray(args), `Expected 'args' to exist on ${name}`);
|
||||
|
||||
args.forEach((arg): void => {
|
||||
const unknownKeys = Object.keys(arg).filter((key): boolean => !['name', 'type'].includes(key));
|
||||
|
||||
assert(unknownKeys.length === 0, `Unknown keys ${unknownKeys.join(', ')} found in ABI args for ${name}`);
|
||||
assert(isString(arg.name), `${name} args should have valid name `);
|
||||
assert(isString(arg.type) || isObject(arg.type), `${name} args should have valid type`);
|
||||
});
|
||||
}
|
||||
|
||||
export function validateDeploy ({ deploy }: ContractABI): void {
|
||||
const unknownKeys = Object.keys(deploy).filter((key): boolean => !['args'].includes(key));
|
||||
|
||||
assert(unknownKeys.length === 0, `Unknown keys ${unknownKeys.join(', ')} found in ABI deploy`);
|
||||
|
||||
validateArgs('deploy', deploy.args);
|
||||
}
|
||||
|
||||
export function validateMethods ({ messages }: ContractABI): void {
|
||||
messages.forEach((method): void => {
|
||||
const unknownKeys = Object.keys(method).filter((key): boolean => !['args', 'mutates', 'name', 'selector', 'return_type'].includes(key));
|
||||
|
||||
assert(unknownKeys.length === 0, `Unknown keys ${unknownKeys.join(', ')} found in ABI args for messages.${method.name}`);
|
||||
assert(isString(method.name), `Expected name for messages.${method.name}`);
|
||||
assert(isNumber(method.selector), `Expected selector for messages.${method.name}`);
|
||||
assert(isNull(method.return_type) || isString(method.return_type) || isObject(method.return_type), `Expected return_type for messages.${method.name}`);
|
||||
|
||||
validateArgs(`messages.${method.name}`, method.args);
|
||||
});
|
||||
}
|
||||
|
||||
export function validateAbi (abi: ContractABI): void {
|
||||
const unknownKeys = Object.keys(abi).filter((key): boolean => !['deploy', 'messages', 'name'].includes(key));
|
||||
|
||||
assert(unknownKeys.length === 0, `Unknown fields ${unknownKeys.join(', ')} found in ABI`);
|
||||
assert(abi.deploy && abi.messages && isString(abi.name), 'ABI should have deploy, messages & name sections');
|
||||
|
||||
validateDeploy(abi);
|
||||
validateMethods(abi);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,184 @@
|
||||
[
|
||||
{
|
||||
"info": 7,
|
||||
"type": "{\"value\": {\"cell\": {\"cell\": ([u8;32])}}}",
|
||||
"name": "Flipper",
|
||||
"namespace": "flipper::normal",
|
||||
"sub": [
|
||||
{
|
||||
"info": 7,
|
||||
"type": "{\"cell\": {\"cell\": ([u8;32])}}",
|
||||
"name": "value",
|
||||
"namespace": "ink_core::storage::value",
|
||||
"params": [
|
||||
{
|
||||
"info": 5,
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"sub": [
|
||||
{
|
||||
"info": 7,
|
||||
"type": "{\"cell\": ([u8;32])}",
|
||||
"name": "cell",
|
||||
"namespace": "ink_core::storage::cell::sync_cell",
|
||||
"params": [
|
||||
{
|
||||
"info": 5,
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"sub": [
|
||||
{
|
||||
"info": 8,
|
||||
"type": "([u8;32])",
|
||||
"name": "cell",
|
||||
"namespace": "ink_core::storage::key",
|
||||
"sub": [
|
||||
{
|
||||
"info": 10,
|
||||
"type": "[u8;32]",
|
||||
"ext": {
|
||||
"length": 32,
|
||||
"type": ""
|
||||
},
|
||||
"sub": {
|
||||
"info": 5,
|
||||
"type": "u8"
|
||||
},
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"info": 7,
|
||||
"type": "{\"cell\": {\"cell\": ([u8;32])}}",
|
||||
"name": "Value",
|
||||
"namespace": "ink_core::storage::value",
|
||||
"params": [
|
||||
{
|
||||
"info": 5,
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"sub": [
|
||||
{
|
||||
"info": 7,
|
||||
"type": "{\"cell\": ([u8;32])}",
|
||||
"name": "cell",
|
||||
"namespace": "ink_core::storage::cell::sync_cell",
|
||||
"params": [
|
||||
{
|
||||
"info": 5,
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"sub": [
|
||||
{
|
||||
"info": 8,
|
||||
"type": "([u8;32])",
|
||||
"name": "cell",
|
||||
"namespace": "ink_core::storage::key",
|
||||
"sub": [
|
||||
{
|
||||
"info": 10,
|
||||
"type": "[u8;32]",
|
||||
"ext": {
|
||||
"length": 32,
|
||||
"type": ""
|
||||
},
|
||||
"sub": {
|
||||
"info": 5,
|
||||
"type": "u8"
|
||||
},
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"info": 5,
|
||||
"type": "bool"
|
||||
},
|
||||
{
|
||||
"info": 7,
|
||||
"type": "{\"cell\": ([u8;32])}",
|
||||
"name": "SyncCell",
|
||||
"namespace": "ink_core::storage::cell::sync_cell",
|
||||
"params": [
|
||||
{
|
||||
"info": 5,
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"sub": [
|
||||
{
|
||||
"info": 8,
|
||||
"type": "([u8;32])",
|
||||
"name": "cell",
|
||||
"namespace": "ink_core::storage::key",
|
||||
"sub": [
|
||||
{
|
||||
"info": 10,
|
||||
"type": "[u8;32]",
|
||||
"ext": {
|
||||
"length": 32,
|
||||
"type": ""
|
||||
},
|
||||
"sub": {
|
||||
"info": 5,
|
||||
"type": "u8"
|
||||
},
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"info": 8,
|
||||
"type": "([u8;32])",
|
||||
"name": "Key",
|
||||
"namespace": "ink_core::storage::key",
|
||||
"sub": [
|
||||
{
|
||||
"info": 10,
|
||||
"type": "[u8;32]",
|
||||
"ext": {
|
||||
"length": 32,
|
||||
"type": ""
|
||||
},
|
||||
"sub": {
|
||||
"info": 5,
|
||||
"type": "u8"
|
||||
},
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"info": 10,
|
||||
"type": "[u8;32]",
|
||||
"ext": {
|
||||
"length": 32,
|
||||
"type": ""
|
||||
},
|
||||
"sub": {
|
||||
"info": 5,
|
||||
"type": "u8"
|
||||
}
|
||||
},
|
||||
{
|
||||
"info": 5,
|
||||
"type": "u8"
|
||||
}
|
||||
]
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,201 @@
|
||||
{
|
||||
"registry": {
|
||||
"strings": [
|
||||
"Flipper",
|
||||
"flipper",
|
||||
"normal",
|
||||
"value",
|
||||
"Value",
|
||||
"ink_core",
|
||||
"storage",
|
||||
"cell",
|
||||
"SyncCell",
|
||||
"sync_cell",
|
||||
"Key",
|
||||
"key",
|
||||
"flip",
|
||||
"get"
|
||||
],
|
||||
"types": [
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 1,
|
||||
"custom.namespace": [
|
||||
2,
|
||||
3
|
||||
],
|
||||
"custom.params": []
|
||||
},
|
||||
"def": {
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 4,
|
||||
"type": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 5,
|
||||
"custom.namespace": [
|
||||
6,
|
||||
7,
|
||||
4
|
||||
],
|
||||
"custom.params": [
|
||||
3
|
||||
]
|
||||
},
|
||||
"def": {
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 8,
|
||||
"type": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "bool",
|
||||
"def": "builtin"
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 9,
|
||||
"custom.namespace": [
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
10
|
||||
],
|
||||
"custom.params": [
|
||||
3
|
||||
]
|
||||
},
|
||||
"def": {
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 8,
|
||||
"type": 5
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 11,
|
||||
"custom.namespace": [
|
||||
6,
|
||||
7,
|
||||
12
|
||||
],
|
||||
"custom.params": []
|
||||
},
|
||||
"def": {
|
||||
"tuple_struct.types": [
|
||||
6
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"array.len": 32,
|
||||
"array.type": 7
|
||||
},
|
||||
"def": "builtin"
|
||||
},
|
||||
{
|
||||
"id": "u8",
|
||||
"def": "builtin"
|
||||
}
|
||||
]
|
||||
},
|
||||
"storage": {
|
||||
"struct.type": 1,
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 4,
|
||||
"layout": {
|
||||
"struct.type": 2,
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 8,
|
||||
"layout": {
|
||||
"range.offset": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"range.len": 1,
|
||||
"range.elem_type": 3
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"contract": {
|
||||
"name": 1,
|
||||
"deploy": {
|
||||
"args": [],
|
||||
"docs": [
|
||||
"Initializes our state to `false` upon deploying our smart contract."
|
||||
]
|
||||
},
|
||||
"messages": [
|
||||
{
|
||||
"name": 13,
|
||||
"selector": 970692492,
|
||||
"mutates": true,
|
||||
"args": [],
|
||||
"return_type": null,
|
||||
"docs": [
|
||||
"Flips the current state of our smart contract."
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": 14,
|
||||
"selector": 4266279973,
|
||||
"mutates": false,
|
||||
"args": [],
|
||||
"return_type": 3,
|
||||
"docs": [
|
||||
"Returns the current state."
|
||||
]
|
||||
}
|
||||
],
|
||||
"events": [],
|
||||
"docs": []
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,935 @@
|
||||
{
|
||||
"registry": {
|
||||
"strings": [
|
||||
"SharedVec",
|
||||
"shared_vec",
|
||||
"normal",
|
||||
"mutators",
|
||||
"HashMap",
|
||||
"ink_core",
|
||||
"storage",
|
||||
"collections",
|
||||
"hash_map",
|
||||
"impls",
|
||||
"AccountId",
|
||||
"env",
|
||||
"srml",
|
||||
"types",
|
||||
"Access",
|
||||
"begin",
|
||||
"Option",
|
||||
"None",
|
||||
"Some",
|
||||
"end",
|
||||
"len",
|
||||
"Value",
|
||||
"value",
|
||||
"cell",
|
||||
"SyncCell",
|
||||
"sync_cell",
|
||||
"Key",
|
||||
"key",
|
||||
"entries",
|
||||
"SyncChunk",
|
||||
"chunk",
|
||||
"sync_chunk",
|
||||
"Entry",
|
||||
"Occupied",
|
||||
"OccupiedEntry",
|
||||
"val",
|
||||
"Removed",
|
||||
"cells_key",
|
||||
"vec",
|
||||
"Vec",
|
||||
"cells",
|
||||
"on_deploy",
|
||||
"push",
|
||||
"i32",
|
||||
"Result",
|
||||
"Ok",
|
||||
"Err",
|
||||
"register",
|
||||
"mutator",
|
||||
"set",
|
||||
"at",
|
||||
"u32",
|
||||
"to",
|
||||
"get",
|
||||
"Mutate",
|
||||
"Push",
|
||||
"Register"
|
||||
],
|
||||
"types": [
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 1,
|
||||
"custom.namespace": [
|
||||
2,
|
||||
3
|
||||
],
|
||||
"custom.params": []
|
||||
},
|
||||
"def": {
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 4,
|
||||
"type": 2
|
||||
},
|
||||
{
|
||||
"name": 39,
|
||||
"type": 15
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 5,
|
||||
"custom.namespace": [
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10
|
||||
],
|
||||
"custom.params": [
|
||||
3,
|
||||
6
|
||||
]
|
||||
},
|
||||
"def": {
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 21,
|
||||
"type": 9
|
||||
},
|
||||
{
|
||||
"name": 29,
|
||||
"type": 12
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 11,
|
||||
"custom.namespace": [
|
||||
6,
|
||||
12,
|
||||
13,
|
||||
14
|
||||
],
|
||||
"custom.params": []
|
||||
},
|
||||
"def": {
|
||||
"tuple_struct.types": [
|
||||
4
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"array.len": 32,
|
||||
"array.type": 5
|
||||
},
|
||||
"def": "builtin"
|
||||
},
|
||||
{
|
||||
"id": "u8",
|
||||
"def": "builtin"
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 15,
|
||||
"custom.namespace": [
|
||||
2
|
||||
],
|
||||
"custom.params": []
|
||||
},
|
||||
"def": {
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 16,
|
||||
"type": 7
|
||||
},
|
||||
{
|
||||
"name": 20,
|
||||
"type": 7
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 17,
|
||||
"custom.namespace": [],
|
||||
"custom.params": [
|
||||
8
|
||||
]
|
||||
},
|
||||
"def": {
|
||||
"enum.variants": [
|
||||
{
|
||||
"unit_variant.name": 18
|
||||
},
|
||||
{
|
||||
"tuple_struct_variant.name": 19,
|
||||
"tuple_struct_variant.types": [
|
||||
8
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "u32",
|
||||
"def": "builtin"
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 22,
|
||||
"custom.namespace": [
|
||||
6,
|
||||
7,
|
||||
23
|
||||
],
|
||||
"custom.params": [
|
||||
8
|
||||
]
|
||||
},
|
||||
"def": {
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 24,
|
||||
"type": 10
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 25,
|
||||
"custom.namespace": [
|
||||
6,
|
||||
7,
|
||||
24,
|
||||
26
|
||||
],
|
||||
"custom.params": [
|
||||
8
|
||||
]
|
||||
},
|
||||
"def": {
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 24,
|
||||
"type": 11
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 27,
|
||||
"custom.namespace": [
|
||||
6,
|
||||
7,
|
||||
28
|
||||
],
|
||||
"custom.params": []
|
||||
},
|
||||
"def": {
|
||||
"tuple_struct.types": [
|
||||
4
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 30,
|
||||
"custom.namespace": [
|
||||
6,
|
||||
7,
|
||||
31,
|
||||
32,
|
||||
31
|
||||
],
|
||||
"custom.params": [
|
||||
13
|
||||
]
|
||||
},
|
||||
"def": {
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 38,
|
||||
"type": 11
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 33,
|
||||
"custom.namespace": [
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10
|
||||
],
|
||||
"custom.params": [
|
||||
3,
|
||||
6
|
||||
]
|
||||
},
|
||||
"def": {
|
||||
"enum.variants": [
|
||||
{
|
||||
"tuple_struct_variant.name": 34,
|
||||
"tuple_struct_variant.types": [
|
||||
14
|
||||
]
|
||||
},
|
||||
{
|
||||
"unit_variant.name": 37
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 35,
|
||||
"custom.namespace": [
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10
|
||||
],
|
||||
"custom.params": [
|
||||
3,
|
||||
6
|
||||
]
|
||||
},
|
||||
"def": {
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 28,
|
||||
"type": 3
|
||||
},
|
||||
{
|
||||
"name": 36,
|
||||
"type": 6
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 40,
|
||||
"custom.namespace": [
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
39,
|
||||
10
|
||||
],
|
||||
"custom.params": [
|
||||
16
|
||||
]
|
||||
},
|
||||
"def": {
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 21,
|
||||
"type": 9
|
||||
},
|
||||
{
|
||||
"name": 41,
|
||||
"type": 17
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "i32",
|
||||
"def": "builtin"
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 30,
|
||||
"custom.namespace": [
|
||||
6,
|
||||
7,
|
||||
31,
|
||||
32,
|
||||
31
|
||||
],
|
||||
"custom.params": [
|
||||
16
|
||||
]
|
||||
},
|
||||
"def": {
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 38,
|
||||
"type": 11
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 45,
|
||||
"custom.namespace": [],
|
||||
"custom.params": [
|
||||
19,
|
||||
8
|
||||
]
|
||||
},
|
||||
"def": {
|
||||
"enum.variants": [
|
||||
{
|
||||
"tuple_struct_variant.name": 46,
|
||||
"tuple_struct_variant.types": [
|
||||
19
|
||||
]
|
||||
},
|
||||
{
|
||||
"tuple_struct_variant.name": 47,
|
||||
"tuple_struct_variant.types": [
|
||||
8
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": [],
|
||||
"def": "builtin"
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 45,
|
||||
"custom.namespace": [],
|
||||
"custom.params": [
|
||||
16,
|
||||
8
|
||||
]
|
||||
},
|
||||
"def": {
|
||||
"enum.variants": [
|
||||
{
|
||||
"tuple_struct_variant.name": 46,
|
||||
"tuple_struct_variant.types": [
|
||||
16
|
||||
]
|
||||
},
|
||||
{
|
||||
"tuple_struct_variant.name": 47,
|
||||
"tuple_struct_variant.types": [
|
||||
8
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 17,
|
||||
"custom.namespace": [],
|
||||
"custom.params": [
|
||||
16
|
||||
]
|
||||
},
|
||||
"def": {
|
||||
"enum.variants": [
|
||||
{
|
||||
"unit_variant.name": 18
|
||||
},
|
||||
{
|
||||
"tuple_struct_variant.name": 19,
|
||||
"tuple_struct_variant.types": [
|
||||
16
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"storage": {
|
||||
"struct.type": 1,
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 4,
|
||||
"layout": {
|
||||
"struct.type": 2,
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 21,
|
||||
"layout": {
|
||||
"struct.type": 9,
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 24,
|
||||
"layout": {
|
||||
"range.offset": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"range.len": 1,
|
||||
"range.elem_type": 8
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": 29,
|
||||
"layout": {
|
||||
"range.offset": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1
|
||||
],
|
||||
"range.len": 4294967295,
|
||||
"range.elem_type": 13
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": 39,
|
||||
"layout": {
|
||||
"struct.type": 15,
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 21,
|
||||
"layout": {
|
||||
"struct.type": 9,
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 24,
|
||||
"layout": {
|
||||
"range.offset": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"range.len": 1,
|
||||
"range.elem_type": 8
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": 41,
|
||||
"layout": {
|
||||
"range.offset": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1
|
||||
],
|
||||
"range.len": 4294967295,
|
||||
"range.elem_type": 16
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"contract": {
|
||||
"name": 1,
|
||||
"constructors": [
|
||||
{
|
||||
"name": 42,
|
||||
"selector": 0,
|
||||
"args": [],
|
||||
"docs": [
|
||||
"Initializes the value to the initial value."
|
||||
]
|
||||
}
|
||||
],
|
||||
"messages": [
|
||||
{
|
||||
"name": 43,
|
||||
"selector": 865577567,
|
||||
"mutates": true,
|
||||
"args": [
|
||||
{
|
||||
"name": 23,
|
||||
"type": {
|
||||
"ty": 16,
|
||||
"display_name": [
|
||||
44
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"return_type": {
|
||||
"ty": 18,
|
||||
"display_name": [
|
||||
45
|
||||
]
|
||||
},
|
||||
"docs": [
|
||||
"Pushes a new value to the shared vector.",
|
||||
"",
|
||||
"# Errors",
|
||||
"",
|
||||
"- If the caller does not have unlimited access rights."
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": 48,
|
||||
"selector": 572030971,
|
||||
"mutates": true,
|
||||
"args": [
|
||||
{
|
||||
"name": 49,
|
||||
"type": {
|
||||
"ty": 3,
|
||||
"display_name": [
|
||||
11
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": 16,
|
||||
"type": {
|
||||
"ty": 7,
|
||||
"display_name": [
|
||||
17
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": 20,
|
||||
"type": {
|
||||
"ty": 7,
|
||||
"display_name": [
|
||||
17
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"return_type": {
|
||||
"ty": 18,
|
||||
"display_name": [
|
||||
45
|
||||
]
|
||||
},
|
||||
"docs": [
|
||||
"Registers a new user with the given access rights.",
|
||||
"",
|
||||
"Can also be used to change access rights of an already existing user.",
|
||||
"",
|
||||
"# Errors",
|
||||
"",
|
||||
"- If the caller does not have unlimited access rights."
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": 50,
|
||||
"selector": 2028185770,
|
||||
"mutates": true,
|
||||
"args": [
|
||||
{
|
||||
"name": 51,
|
||||
"type": {
|
||||
"ty": 8,
|
||||
"display_name": [
|
||||
52
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": 53,
|
||||
"type": {
|
||||
"ty": 16,
|
||||
"display_name": [
|
||||
44
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"return_type": {
|
||||
"ty": 20,
|
||||
"display_name": [
|
||||
45
|
||||
]
|
||||
},
|
||||
"docs": [
|
||||
"Sets the value at the given position to the given value.",
|
||||
"",
|
||||
"Returns the previous value.",
|
||||
"",
|
||||
"# Errors",
|
||||
"",
|
||||
"- If the given position is out of bounds.",
|
||||
"- If the caller does not have the required access rights."
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": 54,
|
||||
"selector": 4266279973,
|
||||
"mutates": false,
|
||||
"args": [
|
||||
{
|
||||
"name": 51,
|
||||
"type": {
|
||||
"ty": 8,
|
||||
"display_name": [
|
||||
52
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"return_type": {
|
||||
"ty": 21,
|
||||
"display_name": [
|
||||
17
|
||||
]
|
||||
},
|
||||
"docs": [
|
||||
"Returns the value of the shared vector at the given position",
|
||||
"or `None` if the access is out of bounds."
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": 21,
|
||||
"selector": 1403873684,
|
||||
"mutates": false,
|
||||
"args": [],
|
||||
"return_type": {
|
||||
"ty": 8,
|
||||
"display_name": [
|
||||
52
|
||||
]
|
||||
},
|
||||
"docs": [
|
||||
"Returns the length of the shared vector."
|
||||
]
|
||||
}
|
||||
],
|
||||
"events": [
|
||||
{
|
||||
"name": 55,
|
||||
"args": [
|
||||
{
|
||||
"name": 51,
|
||||
"indexed": false,
|
||||
"type": {
|
||||
"ty": 8,
|
||||
"display_name": [
|
||||
52
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": 23,
|
||||
"indexed": false,
|
||||
"type": {
|
||||
"ty": 16,
|
||||
"display_name": [
|
||||
44
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"docs": [
|
||||
"Fires whenever a mutator changes the vector."
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": 56,
|
||||
"args": [
|
||||
{
|
||||
"name": 49,
|
||||
"indexed": false,
|
||||
"type": {
|
||||
"ty": 3,
|
||||
"display_name": [
|
||||
11
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": 23,
|
||||
"indexed": false,
|
||||
"type": {
|
||||
"ty": 16,
|
||||
"display_name": [
|
||||
44
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"docs": [
|
||||
"Fires whenever a mutator pushes the vector successfully."
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": 57,
|
||||
"args": [
|
||||
{
|
||||
"name": 49,
|
||||
"indexed": false,
|
||||
"type": {
|
||||
"ty": 3,
|
||||
"display_name": [
|
||||
11
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": 16,
|
||||
"indexed": false,
|
||||
"type": {
|
||||
"ty": 7,
|
||||
"display_name": [
|
||||
17
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": 20,
|
||||
"indexed": false,
|
||||
"type": {
|
||||
"ty": 7,
|
||||
"display_name": [
|
||||
17
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"docs": [
|
||||
"Fires whenever a new mutator is registered",
|
||||
"or when a mutators access rights are changed."
|
||||
]
|
||||
}
|
||||
],
|
||||
"docs": []
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,697 @@
|
||||
{
|
||||
"registry": {
|
||||
"strings": [
|
||||
"RustStructures",
|
||||
"structures",
|
||||
"normal",
|
||||
"my_tuple_struct",
|
||||
"Value",
|
||||
"ink_core",
|
||||
"storage",
|
||||
"value",
|
||||
"TupleStruct",
|
||||
"cell",
|
||||
"SyncCell",
|
||||
"sync_cell",
|
||||
"Key",
|
||||
"key",
|
||||
"my_struct",
|
||||
"Struct",
|
||||
"first",
|
||||
"seconds",
|
||||
"my_clike_enum",
|
||||
"ClikeEnum",
|
||||
"FirstVariant",
|
||||
"SecondVariant",
|
||||
"ThirdVariant",
|
||||
"my_enum",
|
||||
"RustEnum",
|
||||
"NoData",
|
||||
"TupleVariant",
|
||||
"StructVariant",
|
||||
"second",
|
||||
"my_union",
|
||||
"Union"
|
||||
],
|
||||
"types": [
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 1,
|
||||
"custom.namespace": [
|
||||
2,
|
||||
3
|
||||
],
|
||||
"custom.params": []
|
||||
},
|
||||
"def": {
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 4,
|
||||
"type": 2
|
||||
},
|
||||
{
|
||||
"name": 15,
|
||||
"type": 9
|
||||
},
|
||||
{
|
||||
"name": 19,
|
||||
"type": 12
|
||||
},
|
||||
{
|
||||
"name": 24,
|
||||
"type": 15
|
||||
},
|
||||
{
|
||||
"name": 30,
|
||||
"type": 18
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 5,
|
||||
"custom.namespace": [
|
||||
6,
|
||||
7,
|
||||
8
|
||||
],
|
||||
"custom.params": [
|
||||
3
|
||||
]
|
||||
},
|
||||
"def": {
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 10,
|
||||
"type": 6
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 9,
|
||||
"custom.namespace": [
|
||||
2
|
||||
],
|
||||
"custom.params": []
|
||||
},
|
||||
"def": {
|
||||
"tuple_struct.types": [
|
||||
4,
|
||||
5
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "u8",
|
||||
"def": "builtin"
|
||||
},
|
||||
{
|
||||
"id": "u16",
|
||||
"def": "builtin"
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 11,
|
||||
"custom.namespace": [
|
||||
6,
|
||||
7,
|
||||
10,
|
||||
12
|
||||
],
|
||||
"custom.params": [
|
||||
3
|
||||
]
|
||||
},
|
||||
"def": {
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 10,
|
||||
"type": 7
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 13,
|
||||
"custom.namespace": [
|
||||
6,
|
||||
7,
|
||||
14
|
||||
],
|
||||
"custom.params": []
|
||||
},
|
||||
"def": {
|
||||
"tuple_struct.types": [
|
||||
8
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"array.len": 32,
|
||||
"array.type": 4
|
||||
},
|
||||
"def": "builtin"
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 5,
|
||||
"custom.namespace": [
|
||||
6,
|
||||
7,
|
||||
8
|
||||
],
|
||||
"custom.params": [
|
||||
10
|
||||
]
|
||||
},
|
||||
"def": {
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 10,
|
||||
"type": 11
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 16,
|
||||
"custom.namespace": [
|
||||
2
|
||||
],
|
||||
"custom.params": []
|
||||
},
|
||||
"def": {
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 17,
|
||||
"type": 4
|
||||
},
|
||||
{
|
||||
"name": 18,
|
||||
"type": 5
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 11,
|
||||
"custom.namespace": [
|
||||
6,
|
||||
7,
|
||||
10,
|
||||
12
|
||||
],
|
||||
"custom.params": [
|
||||
10
|
||||
]
|
||||
},
|
||||
"def": {
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 10,
|
||||
"type": 7
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 5,
|
||||
"custom.namespace": [
|
||||
6,
|
||||
7,
|
||||
8
|
||||
],
|
||||
"custom.params": [
|
||||
13
|
||||
]
|
||||
},
|
||||
"def": {
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 10,
|
||||
"type": 14
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 20,
|
||||
"custom.namespace": [
|
||||
2
|
||||
],
|
||||
"custom.params": []
|
||||
},
|
||||
"def": {
|
||||
"clike_enum.variants": [
|
||||
{
|
||||
"name": 21,
|
||||
"discriminant": 0
|
||||
},
|
||||
{
|
||||
"name": 22,
|
||||
"discriminant": 1
|
||||
},
|
||||
{
|
||||
"name": 23,
|
||||
"discriminant": 42
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 11,
|
||||
"custom.namespace": [
|
||||
6,
|
||||
7,
|
||||
10,
|
||||
12
|
||||
],
|
||||
"custom.params": [
|
||||
13
|
||||
]
|
||||
},
|
||||
"def": {
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 10,
|
||||
"type": 7
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 5,
|
||||
"custom.namespace": [
|
||||
6,
|
||||
7,
|
||||
8
|
||||
],
|
||||
"custom.params": [
|
||||
16
|
||||
]
|
||||
},
|
||||
"def": {
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 10,
|
||||
"type": 17
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 25,
|
||||
"custom.namespace": [
|
||||
2
|
||||
],
|
||||
"custom.params": []
|
||||
},
|
||||
"def": {
|
||||
"enum.variants": [
|
||||
{
|
||||
"unit_variant.name": 26
|
||||
},
|
||||
{
|
||||
"tuple_struct_variant.name": 27,
|
||||
"tuple_struct_variant.types": [
|
||||
4,
|
||||
5
|
||||
]
|
||||
},
|
||||
{
|
||||
"struct_variant.name": 28,
|
||||
"struct_variant.fields": [
|
||||
{
|
||||
"name": 17,
|
||||
"type": 4
|
||||
},
|
||||
{
|
||||
"name": 29,
|
||||
"type": 5
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 11,
|
||||
"custom.namespace": [
|
||||
6,
|
||||
7,
|
||||
10,
|
||||
12
|
||||
],
|
||||
"custom.params": [
|
||||
16
|
||||
]
|
||||
},
|
||||
"def": {
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 10,
|
||||
"type": 7
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 5,
|
||||
"custom.namespace": [
|
||||
6,
|
||||
7,
|
||||
8
|
||||
],
|
||||
"custom.params": [
|
||||
19
|
||||
]
|
||||
},
|
||||
"def": {
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 10,
|
||||
"type": 20
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 31,
|
||||
"custom.namespace": [
|
||||
2
|
||||
],
|
||||
"custom.params": []
|
||||
},
|
||||
"def": {
|
||||
"union.fields": [
|
||||
{
|
||||
"name": 17,
|
||||
"type": 4
|
||||
},
|
||||
{
|
||||
"name": 29,
|
||||
"type": 5
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"custom.name": 11,
|
||||
"custom.namespace": [
|
||||
6,
|
||||
7,
|
||||
10,
|
||||
12
|
||||
],
|
||||
"custom.params": [
|
||||
19
|
||||
]
|
||||
},
|
||||
"def": {
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 10,
|
||||
"type": 7
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"storage": {
|
||||
"struct.type": 1,
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 4,
|
||||
"layout": {
|
||||
"struct.type": 2,
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 10,
|
||||
"layout": {
|
||||
"range.offset": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"range.len": 1,
|
||||
"range.elem_type": 3
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": 15,
|
||||
"layout": {
|
||||
"struct.type": 9,
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 10,
|
||||
"layout": {
|
||||
"range.offset": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1
|
||||
],
|
||||
"range.len": 1,
|
||||
"range.elem_type": 10
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": 19,
|
||||
"layout": {
|
||||
"struct.type": 12,
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 10,
|
||||
"layout": {
|
||||
"range.offset": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
2
|
||||
],
|
||||
"range.len": 1,
|
||||
"range.elem_type": 13
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": 24,
|
||||
"layout": {
|
||||
"struct.type": 15,
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 10,
|
||||
"layout": {
|
||||
"range.offset": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
3
|
||||
],
|
||||
"range.len": 1,
|
||||
"range.elem_type": 16
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": 30,
|
||||
"layout": {
|
||||
"struct.type": 18,
|
||||
"struct.fields": [
|
||||
{
|
||||
"name": 10,
|
||||
"layout": {
|
||||
"range.offset": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
4
|
||||
],
|
||||
"range.len": 1,
|
||||
"range.elem_type": 19
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"contract": {
|
||||
"name": 1,
|
||||
"deploy": {
|
||||
"args": [],
|
||||
"docs": []
|
||||
},
|
||||
"messages": [],
|
||||
"events": [],
|
||||
"docs": []
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@polkadot/api-derive",
|
||||
"version": "0.93.1",
|
||||
"version": "0.95.2",
|
||||
"description": "Common functions used across Polkadot, derived from RPC calls and storage queries.",
|
||||
"main": "index.js",
|
||||
"keywords": [
|
||||
@@ -27,11 +27,11 @@
|
||||
},
|
||||
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/api-derive#readme",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.6.2",
|
||||
"@polkadot/api": "^0.93.1",
|
||||
"@polkadot/types": "^0.93.1"
|
||||
"@babel/runtime": "^7.6.3",
|
||||
"@polkadot/api": "^0.95.2",
|
||||
"@polkadot/types": "^0.95.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@polkadot/keyring": "^1.5.1"
|
||||
"@polkadot/keyring": "^1.6.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ export function indexes (api: ApiInterfaceRx): () => Observable<AccountIndexes>
|
||||
});
|
||||
|
||||
return result;
|
||||
}, {} as unknown as AccountIndexes)),
|
||||
}, {} as AccountIndexes)),
|
||||
drr()
|
||||
);
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@ import BN from 'bn.js';
|
||||
import { combineLatest, of, Observable } from 'rxjs';
|
||||
import { map, switchMap } from 'rxjs/operators';
|
||||
import { ApiInterfaceRx } from '@polkadot/api/types';
|
||||
import { ClassOf, Option, createType } from '@polkadot/types';
|
||||
import { Option, Vec, createType } from '@polkadot/types';
|
||||
import { bnMax } from '@polkadot/util';
|
||||
|
||||
import { idAndIndex } from '../accounts/idAndIndex';
|
||||
@@ -16,33 +16,35 @@ import { bestNumber } from '../chain/bestNumber';
|
||||
import { DerivedBalances } from '../types';
|
||||
import { drr } from '../util/drr';
|
||||
|
||||
type Result = [AccountId | undefined, BlockNumber | undefined, [Balance?, Balance?, BalanceLock[]?, Option<VestingSchedule>?, Index?]];
|
||||
type ResultBalance = [Balance, Balance, BalanceLock[], Option<VestingSchedule>];
|
||||
type Result = [AccountId, BlockNumber, ResultBalance, Index];
|
||||
|
||||
function calcBalances ([accountId = createType('AccountId'), bestNumber = createType('Balance'), [freeBalance = createType('Balance'), reservedBalance = createType('Balance'), locks = [], vesting = new Option<VestingSchedule>(ClassOf('VestingSchedule'), null), accountNonce = createType('Balance')]]: Result): DerivedBalances {
|
||||
function calcBalances ([accountId, bestNumber, [freeBalance, reservedBalance, locks, vesting], accountNonce]: Result): DerivedBalances {
|
||||
let lockedBalance = createType('Balance');
|
||||
|
||||
if (Array.isArray(locks)) {
|
||||
// only get the locks that are valid until passed the current block
|
||||
const totals = locks.filter((value): boolean => bestNumber && value.until.gt(bestNumber));
|
||||
|
||||
// get the maximum of the locks according to https://github.com/paritytech/substrate/blob/master/srml/balances/src/lib.rs#L699
|
||||
lockedBalance = totals[0]
|
||||
? bnMax(...totals.map(({ amount }): Balance => amount)) as Balance
|
||||
? createType('Balance', bnMax(...totals.map(({ amount }): Balance => amount)))
|
||||
: createType('Balance');
|
||||
}
|
||||
|
||||
// offset = balance locked at genesis, perBlock is the unlock amount
|
||||
const { offset, perBlock } = vesting.unwrapOr(createType('VestingSchedule'));
|
||||
const vestedNow: BN = perBlock.mul(bestNumber);
|
||||
const vestedBalance: BN = vestedNow.gt(offset)
|
||||
const vestedNow = createType('Balance', perBlock.mul(bestNumber));
|
||||
const vestedBalance = vestedNow.gt(offset)
|
||||
? freeBalance
|
||||
: freeBalance.sub(offset).add(vestedNow);
|
||||
: createType('Balance', freeBalance.sub(offset).add(vestedNow));
|
||||
|
||||
// NOTE Workaround for this account on Alex (one of a couple reported) -
|
||||
// 5F7BJL6Z4m8RLtK7nXEqqpEqhBbd535Z3CZeYF6ccvaQAY6N
|
||||
// The locked is > the vested and ended up with the locked > free,
|
||||
// i.e. related to https://github.com/paritytech/polkadot/issues/225
|
||||
// (most probably due to movements from stash -> controller -> free)
|
||||
const availableBalance: BN = bnMax(createType('Balance'), vestedBalance.sub(lockedBalance));
|
||||
const availableBalance = createType('Balance', bnMax(new BN(0), vestedBalance.sub(lockedBalance)));
|
||||
|
||||
return {
|
||||
accountId,
|
||||
@@ -52,22 +54,30 @@ function calcBalances ([accountId = createType('AccountId'), bestNumber = create
|
||||
lockedBalance,
|
||||
reservedBalance,
|
||||
vestedBalance,
|
||||
votingBalance: freeBalance.add(reservedBalance)
|
||||
} as unknown as DerivedBalances;
|
||||
votingBalance: createType('Balance', freeBalance.add(reservedBalance))
|
||||
};
|
||||
}
|
||||
|
||||
function queryBalances (api: ApiInterfaceRx, accountId: AccountId): Observable<ResultBalance> {
|
||||
return api.queryMulti<[Balance, Balance, Vec<BalanceLock>, Option<VestingSchedule>]>([
|
||||
[api.query.balances.freeBalance, accountId],
|
||||
[api.query.balances.reservedBalance, accountId],
|
||||
[api.query.balances.locks, accountId],
|
||||
[api.query.balances.vesting, accountId]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @name all
|
||||
* @param {( AccountIndex | AccountId | Address | string )} address - An accounts Id in different formats.
|
||||
* @returns An object containing the combined results of the storage queries for
|
||||
* all relevant fees as declared in the substrate chain spec.
|
||||
* @returns An object containing the results of various balance queries
|
||||
* @example
|
||||
* <BR>
|
||||
*
|
||||
* ```javascript
|
||||
* const ALICE = 'F7Hs';
|
||||
*
|
||||
* api.derive.balances.all(ALICE, ([accountId, lockedBalance]) => {
|
||||
* api.derive.balances.all(ALICE, ({ accountId, lockedBalance }) => {
|
||||
* console.log(`The account ${accountId} has a locked balance ${lockedBalance} units.`);
|
||||
* });
|
||||
* ```
|
||||
@@ -80,16 +90,16 @@ export function all (api: ApiInterfaceRx): (address: AccountIndex | AccountId |
|
||||
? combineLatest([
|
||||
of(accountId),
|
||||
bestNumber(api)(),
|
||||
api.queryMulti([
|
||||
[api.query.balances.freeBalance, accountId],
|
||||
[api.query.balances.reservedBalance, accountId],
|
||||
[api.query.balances.locks, accountId],
|
||||
[api.query.balances.vesting, accountId],
|
||||
[api.query.system.accountNonce, accountId]
|
||||
])
|
||||
queryBalances(api, accountId),
|
||||
// FIXME This is having issues with Kusama, only use accountNonce atm
|
||||
// api.rpc.account && api.rpc.account.nextIndex
|
||||
// ? api.rpc.account.nextIndex(accountId)
|
||||
// // otherwise we end up with this: type 'Codec | Index' is not assignable to type 'Index'.
|
||||
// : api.query.system.accountNonce<Index>(accountId)
|
||||
api.query.system.accountNonce<Index>(accountId)
|
||||
])
|
||||
: of([undefined, undefined, [undefined, undefined, undefined, undefined, undefined]])
|
||||
) as Observable<Result>
|
||||
: of([createType('AccountId'), createType('BlockNumber'), [createType('Balance'), createType('Balance'), createType('Vec<BalanceLock>'), createType('Option<VestingSchedule>', null)], createType('Index')])
|
||||
)
|
||||
),
|
||||
map(calcBalances),
|
||||
drr()
|
||||
|
||||
@@ -3,37 +3,39 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { ApiInterfaceRx } from '@polkadot/api/types';
|
||||
import { Balance } from '@polkadot/types/interfaces';
|
||||
import { DerivedFees } from '../types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
import { drr } from '../util/drr';
|
||||
|
||||
type Result = [BN, BN, BN, BN, BN];
|
||||
type Result = [Balance, Balance, Balance, Balance, Balance];
|
||||
|
||||
function queryV2 (api: ApiInterfaceRx): Observable<Result> {
|
||||
const paymentBase = api.consts.transactionPayment || api.consts.balances;
|
||||
|
||||
function querySubtrateV2 (api: ApiInterfaceRx): Observable<Result> {
|
||||
return of([
|
||||
// get values from api.const for substrate versions post spec_version: 101
|
||||
// https://github.com/paritytech/substrate/pull/2883/files#diff-5e5e1c3aec9ddfde0a9054d062ab3db9R131
|
||||
api.consts.balances.creationFee,
|
||||
api.consts.balances.existentialDeposit,
|
||||
api.consts.balances.transactionBaseFee,
|
||||
api.consts.balances.transactionByteFee,
|
||||
api.consts.balances.transferFee
|
||||
]) as any as Observable<Result>;
|
||||
api.consts.balances.creationFee as Balance,
|
||||
api.consts.balances.existentialDeposit as Balance,
|
||||
api.consts.balances.transferFee as Balance,
|
||||
paymentBase.transactionBaseFee as Balance,
|
||||
paymentBase.transactionByteFee as Balance
|
||||
]);
|
||||
}
|
||||
|
||||
function querySubtrateV1 (api: ApiInterfaceRx): Observable<Result> {
|
||||
return api.queryMulti([
|
||||
function queryV1 (api: ApiInterfaceRx): Observable<Result> {
|
||||
return api.queryMulti<Result>([
|
||||
// Support older versions and get values from storage
|
||||
api.query.balances.creationFee,
|
||||
api.query.balances.existentialDeposit,
|
||||
api.query.balances.transferFee,
|
||||
api.query.balances.transactionBaseFee,
|
||||
api.query.balances.transactionByteFee,
|
||||
api.query.balances.transferFee
|
||||
]) as any as Observable<Result>;
|
||||
api.query.balances.transactionByteFee
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -44,7 +46,7 @@ function querySubtrateV1 (api: ApiInterfaceRx): Observable<Result> {
|
||||
* <BR>
|
||||
*
|
||||
* ```javascript
|
||||
* api.derive.balances.fees(([creationFee, transferFee]) => {
|
||||
* api.derive.balances.fees(({ creationFee, transferFee }) => {
|
||||
* console.log(`The fee for creating a new account on this chain is ${creationFee} units. The fee required for making a transfer is ${transferFee} units.`);
|
||||
* });
|
||||
* ```
|
||||
@@ -53,16 +55,16 @@ export function fees (api: ApiInterfaceRx): () => Observable<DerivedFees> {
|
||||
return (): Observable<DerivedFees> => {
|
||||
return (
|
||||
api.consts.balances
|
||||
? querySubtrateV2(api)
|
||||
: querySubtrateV1(api)
|
||||
? queryV2(api)
|
||||
: queryV1(api)
|
||||
).pipe(
|
||||
map(([creationFee, existentialDeposit, transactionBaseFee, transactionByteFee, transferFee]): DerivedFees => ({
|
||||
map(([creationFee, existentialDeposit, transferFee, transactionBaseFee, transactionByteFee]): DerivedFees => ({
|
||||
creationFee,
|
||||
existentialDeposit,
|
||||
transactionBaseFee,
|
||||
transactionByteFee,
|
||||
transferFee
|
||||
} as unknown as DerivedFees)),
|
||||
})),
|
||||
drr()
|
||||
);
|
||||
};
|
||||
|
||||
@@ -24,21 +24,20 @@ import { drr } from '../util/drr';
|
||||
* ```
|
||||
*/
|
||||
export function approvalsOf (api: ApiInterfaceRx): (who: AccountId) => Observable<boolean[][]> {
|
||||
return (who: AccountId): Observable<boolean[][]> =>
|
||||
(api.query.elections.nextVoterSet<SetIndex>())
|
||||
.pipe(
|
||||
switchMap((nextVoterSet: SetIndex): Observable<Vec<ApprovalFlag>[]> =>
|
||||
api.query.elections.approvalsOf.multi(
|
||||
[...Array(nextVoterSet.toNumber() + 1).keys()].map((i): [string, number] => [
|
||||
who.toString(), i]
|
||||
)
|
||||
) as any as Observable<Vec<ApprovalFlag>[]>
|
||||
),
|
||||
map((votes: Vec<ApprovalFlag>[]): boolean[][] =>
|
||||
votes.map((flags: Vec<ApprovalFlag>): boolean[] =>
|
||||
approvalFlagsToBools(flags)
|
||||
return (who: AccountId | string): Observable<boolean[][]> =>
|
||||
api.query.elections.nextVoterSet<SetIndex>().pipe(
|
||||
switchMap((nextVoterSet: SetIndex): Observable<Vec<ApprovalFlag>[]> =>
|
||||
api.query.elections.approvalsOf.multi(
|
||||
[...Array(nextVoterSet.toNumber() + 1).keys()].map((i): [string, number] => [
|
||||
who.toString(), i]
|
||||
)
|
||||
),
|
||||
drr()
|
||||
);
|
||||
) as any as Observable<Vec<ApprovalFlag>[]>
|
||||
),
|
||||
map((votes: Vec<ApprovalFlag>[]): boolean[][] =>
|
||||
votes.map((flags: Vec<ApprovalFlag>): boolean[] =>
|
||||
approvalFlagsToBools(flags)
|
||||
)
|
||||
),
|
||||
drr()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,10 +4,12 @@
|
||||
|
||||
import { AccountId, ApprovalFlag, SetIndex } from '@polkadot/types/interfaces';
|
||||
|
||||
import { ApiInterfaceRx } from '@polkadot/api/types';
|
||||
import BN from 'bn.js';
|
||||
import { Observable } from 'rxjs';
|
||||
import { Vec } from '@polkadot/types';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { ApiInterfaceRx } from '@polkadot/api/types';
|
||||
import { Vec } from '@polkadot/types';
|
||||
|
||||
import { approvalFlagsToBools } from '../util/approvalFlagsToBools';
|
||||
import { drr } from '../util/drr';
|
||||
|
||||
@@ -24,10 +26,9 @@ import { drr } from '../util/drr';
|
||||
* ```
|
||||
*/
|
||||
export function approvalsOfAt (api: ApiInterfaceRx): (who: AccountId, at: SetIndex) => Observable<boolean[]> {
|
||||
return (who: AccountId, at: SetIndex): Observable<boolean[]> =>
|
||||
(api.query.elections.approvalsOf<Vec<ApprovalFlag>>([who.toString(), at]))
|
||||
.pipe(
|
||||
map((flags: Vec<ApprovalFlag>): boolean[] => approvalFlagsToBools(flags)),
|
||||
drr()
|
||||
);
|
||||
return (who: AccountId | string, at: SetIndex | BN | number): Observable<boolean[]> =>
|
||||
api.query.elections.approvalsOf<Vec<ApprovalFlag>>([who.toString(), at]).pipe(
|
||||
map((flags: Vec<ApprovalFlag>): boolean[] => approvalFlagsToBools(flags)),
|
||||
drr()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,17 +3,20 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { AccountId, BlockNumber, SetIndex, VoteIndex } from '@polkadot/types/interfaces';
|
||||
import { Codec } from '@polkadot/types/types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { ApiInterfaceRx } from '@polkadot/api/types';
|
||||
import { Vec, u32 } from '@polkadot/types';
|
||||
|
||||
import { DerivedElectionsInfo } from '../types';
|
||||
import { drr } from '../util/drr';
|
||||
|
||||
function query (api: ApiInterfaceRx): Observable<[[AccountId, BlockNumber][], AccountId[], BN, BN, SetIndex, BlockNumber, VoteIndex, SetIndex]> {
|
||||
return api.queryMulti([
|
||||
type Result = [Vec<[AccountId, BlockNumber] & Codec>, Vec<AccountId>, u32, u32, SetIndex, BlockNumber, VoteIndex, SetIndex];
|
||||
|
||||
function query (api: ApiInterfaceRx): Observable<Result> {
|
||||
return api.queryMulti<Result>([
|
||||
api.query.elections.members,
|
||||
api.query.elections.candidates,
|
||||
api.query.elections.candidateCount,
|
||||
@@ -22,7 +25,7 @@ function query (api: ApiInterfaceRx): Observable<[[AccountId, BlockNumber][], Ac
|
||||
api.query.elections.termDuration,
|
||||
api.query.elections.voteCount,
|
||||
api.query.elections.voterCount
|
||||
]) as any;
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -33,7 +36,7 @@ function query (api: ApiInterfaceRx): Observable<[[AccountId, BlockNumber][], Ac
|
||||
* <BR>
|
||||
*
|
||||
* ```javascript
|
||||
* api.derive.elections.info(([members, candidates]) => {
|
||||
* api.derive.elections.info(({ members, candidates }) => {
|
||||
* console.log(`There are currently ${members.length} council members and ${candidates.length} prospective council candidates.`);
|
||||
* });
|
||||
* ```
|
||||
@@ -56,7 +59,7 @@ export function info (api: ApiInterfaceRx): () => Observable<DerivedElectionsInf
|
||||
termDuration,
|
||||
voteCount,
|
||||
voterCount
|
||||
} as unknown as DerivedElectionsInfo)),
|
||||
})),
|
||||
drr()
|
||||
);
|
||||
};
|
||||
|
||||
@@ -7,7 +7,7 @@ import { AccountId, SessionIndex } from '@polkadot/types/interfaces';
|
||||
import { of, Observable } from 'rxjs';
|
||||
import { map, switchMap } from 'rxjs/operators';
|
||||
import { ApiInterfaceRx } from '@polkadot/api/types';
|
||||
import { Bytes } from '@polkadot/types';
|
||||
import { Bytes, Vec } from '@polkadot/types';
|
||||
|
||||
import { drr } from '../util/drr';
|
||||
|
||||
@@ -17,21 +17,22 @@ import { drr } from '../util/drr';
|
||||
export function receivedHeartbeats (api: ApiInterfaceRx): (addresses: (AccountId | string)[]) => Observable<boolean[]> {
|
||||
return (addresses: (AccountId | string)[]): Observable<boolean[]> => {
|
||||
return api.query.imOnline && api.query.imOnline.receivedHeartbeats
|
||||
? api.query.session
|
||||
.currentIndex<SessionIndex>()
|
||||
.pipe(
|
||||
switchMap((currentIndex): Observable<Bytes[]> =>
|
||||
api.query.imOnline.receivedHeartbeats.multi(
|
||||
addresses.map((address): [SessionIndex, AccountId | string] =>
|
||||
[currentIndex, address]
|
||||
)
|
||||
? api.queryMulti<[SessionIndex, Vec<AccountId>]>([
|
||||
api.query.session.currentIndex,
|
||||
api.query.imOnline.keys
|
||||
]).pipe(
|
||||
switchMap(([currentIndex, keys]): Observable<Bytes[]> =>
|
||||
api.query.imOnline.receivedHeartbeats.multi(
|
||||
addresses.map((address): [SessionIndex, number] =>
|
||||
[currentIndex, keys.indexOf(address)]
|
||||
)
|
||||
),
|
||||
map((heartbeats): boolean[] =>
|
||||
heartbeats.map((heartbeat): boolean => !heartbeat.isEmpty)
|
||||
),
|
||||
drr()
|
||||
)
|
||||
)
|
||||
),
|
||||
map((heartbeats): boolean[] =>
|
||||
heartbeats.map((heartbeat): boolean => !heartbeat.isEmpty)
|
||||
),
|
||||
drr()
|
||||
)
|
||||
: of([...new Array(addresses.length).keys()].map((): boolean => false));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,11 +6,11 @@ import { Observable, from } from 'rxjs';
|
||||
import ApiRx from '@polkadot/api/rx/Api';
|
||||
import MockProvider from '@polkadot/rpc-provider/mock';
|
||||
|
||||
import { Derive } from '.';
|
||||
import { ExactDerive } from '.';
|
||||
|
||||
const testFunction = (api: ApiRx): any => {
|
||||
return <
|
||||
Section extends keyof Derive,
|
||||
Section extends keyof ExactDerive,
|
||||
Method extends keyof (typeof api.derive[Section])
|
||||
>(section: Section, method: Method, inputs: any[]): void => {
|
||||
describe(`derive.${section}.${method}`, (): void => {
|
||||
|
||||
@@ -19,14 +19,13 @@ import * as staking from './staking';
|
||||
|
||||
export * from './type';
|
||||
|
||||
export type ReturnTypes<Section> = {
|
||||
type DeriveSection<Section> = {
|
||||
[Method in keyof Section]: Section[Method] extends AnyFunction
|
||||
? ReturnType<Section[Method]> // ReturnType<Section[Method]> will be the inner function, i.e. without (api) argument
|
||||
: never;
|
||||
};
|
||||
|
||||
export type DeriveSections<AllSections> = {
|
||||
[Section in keyof AllSections]: ReturnTypes<AllSections[Section]>
|
||||
type DeriveAllSections<AllSections> = {
|
||||
[Section in keyof AllSections]: DeriveSection<AllSections[Section]>
|
||||
};
|
||||
|
||||
export type DeriveCustom = Record<string, Record<string, (api: ApiInterfaceRx) => (...args: any[]) => Observable<any>>>;
|
||||
@@ -35,15 +34,15 @@ export type DeriveCustom = Record<string, Record<string, (api: ApiInterfaceRx) =
|
||||
* Returns an object that will inject `api` into all the functions inside
|
||||
* `allSections`, and keep the object architecture of `allSections`.
|
||||
*/
|
||||
function injectFunctions<AllSections> (api: ApiInterfaceRx, allSections: AllSections): DeriveSections<AllSections> {
|
||||
function injectFunctions<AllSections> (api: ApiInterfaceRx, allSections: AllSections): DeriveAllSections<AllSections> {
|
||||
return Object
|
||||
.keys(allSections)
|
||||
.reduce((deriveAcc, sectionName): DeriveSections<AllSections> => {
|
||||
.reduce((deriveAcc, sectionName): DeriveAllSections<AllSections> => {
|
||||
const section = allSections[sectionName as keyof AllSections];
|
||||
|
||||
deriveAcc[sectionName as keyof AllSections] = Object
|
||||
.keys(section)
|
||||
.reduce((sectionAcc, _methodName): ReturnTypes<typeof section> => {
|
||||
.reduce((sectionAcc, _methodName): DeriveSection<typeof section> => {
|
||||
const methodName = _methodName as keyof typeof section;
|
||||
// Not sure what to do here, casting as any. Though the final types are good
|
||||
const method = (section[methodName] as any)(api);
|
||||
@@ -51,18 +50,18 @@ function injectFunctions<AllSections> (api: ApiInterfaceRx, allSections: AllSect
|
||||
(sectionAcc as any)[methodName] = method;
|
||||
|
||||
return sectionAcc;
|
||||
}, {} as unknown as ReturnTypes<typeof section>);
|
||||
}, {} as DeriveSection<typeof section>);
|
||||
|
||||
return deriveAcc;
|
||||
}, {} as unknown as DeriveSections<AllSections>);
|
||||
}, {} as DeriveAllSections<AllSections>);
|
||||
}
|
||||
|
||||
export const derive = { accounts, balances, chain, contracts, democracy, elections, imOnline, session, staking };
|
||||
export type Derive = typeof derive;
|
||||
export type ExactDerive = DeriveAllSections<typeof derive>;
|
||||
|
||||
// FIXME I have no idea how to get this done
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
||||
export default function decorateDerive (api: ApiInterfaceRx, custom: DeriveCustom = {}) {
|
||||
// FIXME The return type of this function should be {...ExactDerive, ...DeriveCustom}
|
||||
// For now we just drop the custom derive typings
|
||||
export default function decorateDerive (api: ApiInterfaceRx, custom: DeriveCustom = {}): ExactDerive {
|
||||
return {
|
||||
...injectFunctions(api, derive),
|
||||
...injectFunctions(api, custom)
|
||||
|
||||
@@ -5,51 +5,51 @@
|
||||
import { BlockNumber, EraIndex, SessionIndex } from '@polkadot/types/interfaces';
|
||||
import { DerivedSessionInfo } from '../types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import { Observable, combineLatest, of } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { ApiInterfaceRx } from '@polkadot/api/types';
|
||||
import { Option, u64 } from '@polkadot/types';
|
||||
import { Option, u64, createType } from '@polkadot/types';
|
||||
|
||||
import { drr } from '../util/drr';
|
||||
import { bestNumber } from '../chain';
|
||||
|
||||
type Result0to94 = [BlockNumber, [SessionIndex, Option<BlockNumber>, BN, BN, SessionIndex]];
|
||||
type Result = [[boolean, boolean, u64, SessionIndex], [u64, u64, u64], [SessionIndex, EraIndex]];
|
||||
type Result94Session = [SessionIndex, Option<BlockNumber>, BlockNumber, BlockNumber, SessionIndex];
|
||||
type Result94 = [BlockNumber, Result94Session];
|
||||
|
||||
const ZERO = new BN(0);
|
||||
const ONE = new BN(1);
|
||||
type ResultIndex = [SessionIndex, EraIndex];
|
||||
type ResultSlots = [u64, u64, u64];
|
||||
type ResultType = [boolean, boolean, u64, SessionIndex];
|
||||
type Result = [ResultType, ResultSlots, ResultIndex];
|
||||
|
||||
// internal helper to just split the logic - take all inputs, do the calculations and combine
|
||||
function createDerived0to94 ([bestNumber, [currentIndex, _lastLengthChange, sessionLength, lastEraLengthChange, sessionsPerEra]]: Result0to94): DerivedSessionInfo {
|
||||
const lastLengthChange = _lastLengthChange
|
||||
? _lastLengthChange.unwrapOr(ZERO)
|
||||
: ZERO;
|
||||
function createDerived94 ([bestNumber, [currentIndex, _lastLengthChange, sessionLength, lastEraLengthChange, sessionsPerEra]]: Result94): DerivedSessionInfo {
|
||||
const lastLengthChange = (_lastLengthChange && _lastLengthChange.unwrapOr(null)) || createType('BlockNumber');
|
||||
const sessionProgress = bestNumber
|
||||
.sub(lastLengthChange)
|
||||
.add(sessionLength)
|
||||
.mod(sessionLength);
|
||||
const currentEra = (currentIndex)
|
||||
const currentEra = currentIndex
|
||||
.sub(lastEraLengthChange)
|
||||
.mod(sessionsPerEra);
|
||||
const eraProgress = currentEra
|
||||
.mul(sessionLength)
|
||||
.add(sessionProgress);
|
||||
|
||||
return {
|
||||
currentEra,
|
||||
currentEra: createType('EraIndex', currentEra),
|
||||
currentIndex,
|
||||
eraLength: sessionLength.mul(sessionsPerEra),
|
||||
eraProgress: currentEra
|
||||
.mul(sessionLength)
|
||||
.add(sessionProgress),
|
||||
eraLength: createType('BlockNumber', sessionLength.mul(sessionsPerEra)),
|
||||
eraProgress: createType('BlockNumber', eraProgress),
|
||||
isEpoch: false,
|
||||
lastEraLengthChange,
|
||||
lastLengthChange,
|
||||
sessionLength,
|
||||
sessionsPerEra,
|
||||
sessionProgress
|
||||
} as unknown as DerivedSessionInfo;
|
||||
sessionProgress: createType('BlockNumber', sessionProgress)
|
||||
};
|
||||
}
|
||||
|
||||
function createDerived ([[hasBabe, isGenesisSlot, epochDuration, sessionsPerEra], [currentSlot, epochIndex, epochOrGenesisStartSlot], [currentIndex, currentEra]]: Result): DerivedSessionInfo {
|
||||
function createDerivedLatest ([[hasBabe, isGenesisSlot, epochDuration, sessionsPerEra], [currentSlot, epochIndex, epochOrGenesisStartSlot], [currentIndex, currentEra]]: Result): DerivedSessionInfo {
|
||||
const epochStartSlot = isGenesisSlot
|
||||
? epochIndex
|
||||
.mul(epochDuration)
|
||||
@@ -64,73 +64,74 @@ function createDerived ([[hasBabe, isGenesisSlot, epochDuration, sessionsPerEra]
|
||||
return {
|
||||
currentEra,
|
||||
currentIndex,
|
||||
eraLength: sessionsPerEra.mul(epochDuration),
|
||||
eraProgress,
|
||||
eraLength: createType('BlockNumber', sessionsPerEra.mul(epochDuration)),
|
||||
eraProgress: createType('BlockNumber', eraProgress),
|
||||
isEpoch: hasBabe,
|
||||
lastEraLengthChange: ZERO,
|
||||
lastLengthChange: epochStartSlot,
|
||||
lastEraLengthChange: createType('BlockNumber'),
|
||||
lastLengthChange: createType('BlockNumber', epochStartSlot),
|
||||
sessionLength: epochDuration,
|
||||
sessionsPerEra,
|
||||
sessionProgress: sessionProgress
|
||||
} as unknown as DerivedSessionInfo;
|
||||
sessionProgress: createType('BlockNumber', sessionProgress)
|
||||
};
|
||||
}
|
||||
|
||||
function info94 (api: ApiInterfaceRx): Observable<DerivedSessionInfo> {
|
||||
return combineLatest([
|
||||
bestNumber(api)(),
|
||||
api.queryMulti<Result94Session>([
|
||||
api.query.session.currentIndex,
|
||||
api.query.session.lastLengthChange,
|
||||
api.query.session.sessionLength,
|
||||
api.query.staking.lastEraLengthChange,
|
||||
api.query.staking.sessionsPerEra
|
||||
])
|
||||
]).pipe(
|
||||
map(createDerived94),
|
||||
drr()
|
||||
);
|
||||
}
|
||||
|
||||
function infoLatest (api: ApiInterfaceRx): Observable<DerivedSessionInfo> {
|
||||
const hasBabe = !!api.consts.babe;
|
||||
|
||||
return combineLatest([
|
||||
of([
|
||||
hasBabe,
|
||||
hasBabe && !!api.query.babe.genesisSlot,
|
||||
hasBabe
|
||||
? api.consts.babe.epochDuration as u64
|
||||
: createType('u64', 1),
|
||||
api.consts.staking.sessionsPerEra as SessionIndex
|
||||
] as ResultType),
|
||||
hasBabe
|
||||
? api.queryMulti<ResultSlots>([
|
||||
api.query.babe.currentSlot,
|
||||
api.query.babe.epochIndex,
|
||||
api.query.babe.genesisSlot
|
||||
? api.query.babe.genesisSlot
|
||||
: api.query.babe.epochStartSlot
|
||||
])
|
||||
: of([createType('u64', 1), createType('u64', 1), createType('u64', 1)] as ResultSlots),
|
||||
api.queryMulti<ResultIndex>([
|
||||
api.query.session.currentIndex,
|
||||
api.query.staking.currentEra
|
||||
])
|
||||
]).pipe(
|
||||
map(createDerivedLatest),
|
||||
drr()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Retrieves all the session and era info and calculates specific values on it as the length of the session and eras
|
||||
*/
|
||||
export function info (api: ApiInterfaceRx): () => Observable<DerivedSessionInfo> {
|
||||
const hasBabe = !!api.consts.babe;
|
||||
|
||||
return (): Observable<DerivedSessionInfo> => {
|
||||
// With substrate `spec_version 94`, the era and session has been explicitly exposed as `parameter_types`.
|
||||
// pre-94 we had more info and needed to calculate (handle old/Alex first)
|
||||
// https://github.com/paritytech/substrate/commit/dbf322620948935d2bbae214504e6c668c3073ed#diff-c29f42d6b931fa93ba038dbbbfec3055
|
||||
return api.query.session.lastLengthChange
|
||||
? (
|
||||
combineLatest([
|
||||
bestNumber(api)(),
|
||||
api.queryMulti([
|
||||
api.query.session.currentIndex,
|
||||
api.query.session.lastLengthChange,
|
||||
api.query.session.sessionLength,
|
||||
api.query.staking.lastEraLengthChange,
|
||||
api.query.staking.sessionsPerEra
|
||||
])
|
||||
]) as any as Observable<Result0to94>
|
||||
).pipe(
|
||||
map(createDerived0to94),
|
||||
drr()
|
||||
)
|
||||
: (
|
||||
combineLatest([
|
||||
// sessionsPerEra:
|
||||
// substrate spec_version >= 94 : get from parameter_types exposed as api.consts
|
||||
// https://github.com/paritytech/substrate/pull/2802/files#diff-5e5e1c3aec9ddfde0a9054d062ab3db9R156
|
||||
of([
|
||||
hasBabe,
|
||||
!!api.query.babe.genesisSlot,
|
||||
hasBabe
|
||||
? api.consts.babe.epochDuration
|
||||
: ONE,
|
||||
api.consts.staking.sessionsPerEra
|
||||
]),
|
||||
hasBabe
|
||||
? api.queryMulti([
|
||||
api.query.babe.currentSlot,
|
||||
api.query.babe.epochIndex,
|
||||
api.query.babe.genesisSlot
|
||||
? api.query.babe.genesisSlot
|
||||
: api.query.babe.epochStartSlot
|
||||
])
|
||||
: of([ONE, ONE, ONE]),
|
||||
api.queryMulti([
|
||||
api.query.session.currentIndex,
|
||||
api.query.staking.currentEra
|
||||
])
|
||||
]) as unknown as Observable<Result>
|
||||
).pipe(
|
||||
map(createDerived),
|
||||
drr()
|
||||
);
|
||||
? info94(api) // 1.x
|
||||
: infoLatest(api); // 2.x
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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 { AccountId, BlockNumber } from '@polkadot/types/interfaces/runtime';
|
||||
import { AccountId, Balance, BlockNumber } from '@polkadot/types/interfaces/runtime';
|
||||
import { Keys } from '@polkadot/types/interfaces/session';
|
||||
import { Exposure, RewardDestination, StakingLedger, UnlockChunk, ValidatorPrefs } from '@polkadot/types/interfaces/staking';
|
||||
import { Codec } from '@polkadot/types/types';
|
||||
@@ -40,15 +40,16 @@ function groupByEra (list: UnlockChunk[]): Record<string, BN> {
|
||||
}
|
||||
|
||||
// calculate the remining blocks in a specific unlock era
|
||||
function remainingBlocks (era: BN, eraLength: BN, bestNumber: BlockNumber): BN {
|
||||
function remainingBlocks (era: BN, eraLength: BN, bestNumber: BlockNumber): BlockNumber {
|
||||
const remaining = eraLength.mul(era).sub(bestNumber);
|
||||
|
||||
return remaining.lten(0)
|
||||
return createType('BlockNumber', remaining.lten(0)
|
||||
? new BN(0)
|
||||
: remaining;
|
||||
: remaining
|
||||
);
|
||||
}
|
||||
|
||||
function calculateUnlocking (stakingLedger: StakingLedger | undefined, eraLength: BN, bestNumber: BlockNumber): DerivedUnlocking | undefined {
|
||||
function calculateUnlocking (stakingLedger: StakingLedger | undefined, eraLength: BN, bestNumber: BlockNumber): DerivedUnlocking[] | undefined {
|
||||
if (isUndefined(stakingLedger)) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -63,24 +64,24 @@ function calculateUnlocking (stakingLedger: StakingLedger | undefined, eraLength
|
||||
|
||||
// group the Unlockchunks that have the same era and sum their values
|
||||
const groupedResult = groupByEra(unlockingChunks);
|
||||
const results = Object.entries(groupedResult).map(([eraString, value]): { value: BN; remainingBlocks: BN } => ({
|
||||
value,
|
||||
const results = Object.entries(groupedResult).map(([eraString, value]): DerivedUnlocking => ({
|
||||
value: createType('Balance', value),
|
||||
remainingBlocks: remainingBlocks(createType('BlockNumber', eraString), eraLength, bestNumber)
|
||||
}));
|
||||
|
||||
return results.length ? results : undefined;
|
||||
}
|
||||
|
||||
function redeemableSum (stakingLedger: StakingLedger | undefined, eraLength: BN, bestNumber: BlockNumber): BN {
|
||||
function redeemableSum (stakingLedger: StakingLedger | undefined, eraLength: BN, bestNumber: BlockNumber): Balance {
|
||||
if (isUndefined(stakingLedger)) {
|
||||
return new BN(0);
|
||||
return createType('Balance');
|
||||
}
|
||||
|
||||
return stakingLedger.unlocking.reduce((total, { era, value }): BN => {
|
||||
return createType('Balance', stakingLedger.unlocking.reduce((total, { era, value }): BN => {
|
||||
return remainingBlocks(era.unwrap(), eraLength, bestNumber).eqn(0)
|
||||
? total.add(value.unwrap())
|
||||
: total;
|
||||
}, new BN(0));
|
||||
}, new BN(0)));
|
||||
}
|
||||
|
||||
function unwrapSessionIds (stashId: AccountId, queuedKeys: Option<AccountId> | Vec<[AccountId, Keys] & Codec>, nextKeys: Option<Keys>): { nextSessionIds: AccountId[]; nextSessionId?: AccountId; sessionIds: AccountId[]; sessionId?: AccountId } {
|
||||
@@ -132,7 +133,7 @@ function retrieveMulti (api: ApiInterfaceRx, stashId: AccountId, controllerId: A
|
||||
]) as Observable<MultiResult>;
|
||||
}
|
||||
|
||||
function retrieveInfo (api: ApiInterfaceRx, stashId: AccountId, controllerId: AccountId): Observable<DerivedStaking> {
|
||||
function retrieveInfo (api: ApiInterfaceRx, accountId: AccountId, stashId: AccountId, controllerId: AccountId): Observable<DerivedStaking> {
|
||||
return combineLatest([
|
||||
eraLength(api)(),
|
||||
bestNumber(api)(),
|
||||
@@ -143,7 +144,7 @@ function retrieveInfo (api: ApiInterfaceRx, stashId: AccountId, controllerId: Ac
|
||||
const stakingLedger = _stakingLedger.unwrapOr(undefined);
|
||||
|
||||
return {
|
||||
accountId: stashId,
|
||||
accountId,
|
||||
controllerId,
|
||||
nominators,
|
||||
offline: recentlyOffline[stashId.toString()],
|
||||
@@ -178,9 +179,9 @@ export function info (api: ApiInterfaceRx): (_accountId: Uint8Array | string) =>
|
||||
).pipe(
|
||||
switchMap(([controllerId, stakingLedger]): Observable<DerivedStaking> =>
|
||||
controllerId.isSome
|
||||
? retrieveInfo(api, accountId, controllerId.unwrap())
|
||||
? retrieveInfo(api, accountId, accountId, controllerId.unwrap())
|
||||
: stakingLedger.isSome
|
||||
? retrieveInfo(api, stakingLedger.unwrap().stash, accountId)
|
||||
? retrieveInfo(api, accountId, stakingLedger.unwrap().stash, accountId)
|
||||
: of({ accountId, nextSessionIds: [], sessionIds: [] })
|
||||
),
|
||||
drr()
|
||||
|
||||
@@ -2,19 +2,20 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { AccountId, Balance, BlockNumber, Exposure, Index, RewardDestination, SetIndex, StakingLedger, ValidatorPrefs, Vote, VoteIndex } from '@polkadot/types/interfaces';
|
||||
import { AccountId, Balance, BlockNumber, EraIndex, Exposure, Index, RewardDestination, SessionIndex, SetIndex, StakingLedger, ValidatorPrefs, Vote, VoteIndex } from '@polkadot/types/interfaces';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import { u32 } from '@polkadot/types';
|
||||
|
||||
export interface DerivedBalances {
|
||||
accountId: AccountId;
|
||||
accountNonce: Index;
|
||||
freeBalance: BN;
|
||||
lockedBalance: BN;
|
||||
availableBalance: BN;
|
||||
reservedBalance: BN;
|
||||
votingBalance: BN;
|
||||
vestedBalance: BN;
|
||||
freeBalance: Balance;
|
||||
lockedBalance: Balance;
|
||||
availableBalance: Balance;
|
||||
reservedBalance: Balance;
|
||||
votingBalance: Balance;
|
||||
vestedBalance: Balance;
|
||||
}
|
||||
|
||||
export type DerivedBalancesMap = Record<string, DerivedBalances>;
|
||||
@@ -35,8 +36,8 @@ export interface DerivedContractFees {
|
||||
export interface DerivedElectionsInfo {
|
||||
members: Record<string, BlockNumber>;
|
||||
candidates: AccountId[];
|
||||
candidateCount: BN;
|
||||
desiredSeats: BN;
|
||||
candidateCount: u32;
|
||||
desiredSeats: u32;
|
||||
nextVoterSet: SetIndex;
|
||||
termDuration: BlockNumber;
|
||||
voteCount: VoteIndex;
|
||||
@@ -44,11 +45,11 @@ export interface DerivedElectionsInfo {
|
||||
}
|
||||
|
||||
export interface DerivedFees {
|
||||
creationFee: BN;
|
||||
existentialDeposit: BN;
|
||||
transactionBaseFee: BN;
|
||||
transactionByteFee: BN;
|
||||
transferFee: BN;
|
||||
creationFee: Balance;
|
||||
existentialDeposit: Balance;
|
||||
transactionBaseFee: Balance;
|
||||
transactionByteFee: Balance;
|
||||
transferFee: Balance;
|
||||
}
|
||||
|
||||
export interface RecentlyOffline {
|
||||
@@ -65,16 +66,16 @@ export interface DerivedReferendumVote {
|
||||
}
|
||||
|
||||
export interface DerivedSessionInfo {
|
||||
currentEra: BN;
|
||||
currentIndex: BN;
|
||||
eraLength: BN;
|
||||
eraProgress: BN;
|
||||
currentEra: EraIndex;
|
||||
currentIndex: SessionIndex;
|
||||
eraLength: BlockNumber;
|
||||
eraProgress: BlockNumber;
|
||||
isEpoch: boolean;
|
||||
lastEraLengthChange: BN;
|
||||
lastLengthChange: BN;
|
||||
sessionLength: BN;
|
||||
sessionsPerEra: BN;
|
||||
sessionProgress: BN;
|
||||
lastEraLengthChange: BlockNumber;
|
||||
lastLengthChange: BlockNumber;
|
||||
sessionLength: BlockNumber;
|
||||
sessionsPerEra: SessionIndex;
|
||||
sessionProgress: BlockNumber;
|
||||
}
|
||||
|
||||
export type DerivedStakingAccount = [AccountId, DerivedStakingOnlineStatus];
|
||||
@@ -99,7 +100,7 @@ export interface DerivedStaking extends DerivedStakingOnlineStatus {
|
||||
nextSessionId?: AccountId;
|
||||
nextSessionIds: AccountId[];
|
||||
nominators?: AccountId[];
|
||||
redeemable?: BN;
|
||||
redeemable?: Balance;
|
||||
rewardDestination?: RewardDestination;
|
||||
// @deprecated Use sessionIds instead
|
||||
sessionId?: AccountId;
|
||||
@@ -107,11 +108,11 @@ export interface DerivedStaking extends DerivedStakingOnlineStatus {
|
||||
stakers?: Exposure;
|
||||
stakingLedger?: StakingLedger;
|
||||
stashId?: AccountId;
|
||||
unlocking?: DerivedUnlocking;
|
||||
unlocking?: DerivedUnlocking[];
|
||||
validatorPrefs?: ValidatorPrefs;
|
||||
}
|
||||
|
||||
export type DerivedUnlocking = { remainingBlocks: BN; value: BN }[];
|
||||
export type DerivedUnlocking = { remainingBlocks: BlockNumber; value: Balance };
|
||||
|
||||
export interface VoterPosition {
|
||||
globalIndex: BN;
|
||||
|
||||
@@ -22,7 +22,9 @@ export const drr = (): DrrResult => <T> (source$: Observable<T>): Observable<T>
|
||||
|
||||
throw error;
|
||||
}),
|
||||
distinctUntilChanged(),
|
||||
distinctUntilChanged((a: any, b: any): boolean =>
|
||||
JSON.stringify({ value: a }) === JSON.stringify({ value: b })
|
||||
),
|
||||
publishReplay(1),
|
||||
refCount()
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@polkadot/api-metadata",
|
||||
"version": "0.93.1",
|
||||
"version": "0.95.2",
|
||||
"description": "Helpers to extract information from runtime metadata",
|
||||
"main": "index.js",
|
||||
"publishConfig": {
|
||||
@@ -26,12 +26,12 @@
|
||||
},
|
||||
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/type-metadata#readme",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.6.2",
|
||||
"@polkadot/types": "^0.93.1",
|
||||
"@polkadot/util": "^1.5.1",
|
||||
"@polkadot/util-crypto": "^1.5.1"
|
||||
"@babel/runtime": "^7.6.3",
|
||||
"@polkadot/types": "^0.95.2",
|
||||
"@polkadot/util": "^1.6.1",
|
||||
"@polkadot/util-crypto": "^1.6.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@polkadot/keyring": "^1.5.1"
|
||||
"@polkadot/keyring": "^1.6.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import { stringCamelCase } from '@polkadot/util';
|
||||
* @param metadata - The metadata
|
||||
*/
|
||||
export default function fromMetadata (metadata: Metadata): Constants {
|
||||
return metadata.asLatest.modules.reduce((result, moduleMetadata): Constants => {
|
||||
return metadata.asLatest.modules.reduce((result: Constants, moduleMetadata): Constants => {
|
||||
if (moduleMetadata.constants.isEmpty) {
|
||||
return result;
|
||||
}
|
||||
@@ -22,7 +22,7 @@ export default function fromMetadata (metadata: Metadata): Constants {
|
||||
const { name } = moduleMetadata;
|
||||
|
||||
// For access, we change the index names, i.e. Democracy.EnactmentPeriod -> democracy.enactmentPeriod
|
||||
result[stringCamelCase(name.toString())] = moduleMetadata.constants.reduce((newModule, meta): ModuleConstants => {
|
||||
result[stringCamelCase(name.toString())] = moduleMetadata.constants.reduce((newModule: ModuleConstants, meta): ModuleConstants => {
|
||||
const codec = createTypeUnsafe(meta.type.toString(), [meta.value]);
|
||||
|
||||
// This is not a perfect idea, however as it stands with number-only constants on the metadata
|
||||
@@ -33,8 +33,8 @@ export default function fromMetadata (metadata: Metadata): Constants {
|
||||
newModule[stringCamelCase(meta.name.toString())] = codec;
|
||||
|
||||
return newModule;
|
||||
}, {} as unknown as ModuleConstants);
|
||||
}, {});
|
||||
|
||||
return result;
|
||||
}, {} as unknown as Constants);
|
||||
}, {});
|
||||
}
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { Codec } from '@polkadot/types/types';
|
||||
import { ModuleConstantMetadataV7 } from '@polkadot/types/interfaces';
|
||||
import { ModuleConstantMetadataLatest } from '@polkadot/types/interfaces';
|
||||
|
||||
export interface ConstantCodec extends Codec {
|
||||
meta: ModuleConstantMetadataV7;
|
||||
meta: ModuleConstantMetadataLatest;
|
||||
}
|
||||
|
||||
export type ModuleConstants = Record<string, Codec>;
|
||||
|
||||
@@ -2,10 +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 { Call, FunctionMetadataV7 } from '@polkadot/types/interfaces';
|
||||
import { Call, FunctionMetadataLatest } from '@polkadot/types/interfaces';
|
||||
import { CallFunction } from '@polkadot/types/types';
|
||||
|
||||
import { createType } from '@polkadot/types';
|
||||
import { createType } from '@polkadot/types/codec';
|
||||
import { assert, stringCamelCase } from '@polkadot/util';
|
||||
|
||||
/**
|
||||
@@ -21,7 +21,7 @@ export default function createDescriptor (
|
||||
section: string,
|
||||
sectionIndex: number,
|
||||
methodIndex: number,
|
||||
callMetadata: FunctionMetadataV7
|
||||
callMetadata: FunctionMetadataLatest
|
||||
): CallFunction {
|
||||
const callIndex = new Uint8Array([sectionIndex, methodIndex]);
|
||||
const expectedArgs = callMetadata.args;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import '@polkadot/types/injector';
|
||||
|
||||
import { createType, Metadata } from '@polkadot/types';
|
||||
import json from '@polkadot/types/Metadata/v7/static';
|
||||
import json from '@polkadot/types/Metadata/static';
|
||||
|
||||
import fromMetadata from '.';
|
||||
|
||||
@@ -32,7 +32,7 @@ describe('fromMetadata', (): void => {
|
||||
// version, no signature
|
||||
1,
|
||||
// index
|
||||
2, 0,
|
||||
3, 0,
|
||||
// values, Compact<Moment>
|
||||
116
|
||||
])
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
import { Calls, ModulesWithCalls } from '@polkadot/types/types';
|
||||
|
||||
import { ModuleMetadataV7 } from '@polkadot/types/Metadata/v7/Metadata';
|
||||
import { ModuleMetadataV8 } from '@polkadot/types/Metadata/v8/Metadata';
|
||||
import Metadata from '@polkadot/types/Metadata';
|
||||
import { stringCamelCase } from '@polkadot/util';
|
||||
|
||||
@@ -19,16 +19,16 @@ import createUnchecked from './createUnchecked';
|
||||
export default function fromMetadata (metadata: Metadata): ModulesWithCalls {
|
||||
return metadata.asLatest.modules
|
||||
.filter(({ calls }): boolean => calls.isSome)
|
||||
.reduce((result, modul: ModuleMetadataV7, sectionIndex): ModulesWithCalls => {
|
||||
const section = stringCamelCase(modul.name.toString());
|
||||
.reduce((result, { calls, name }: ModuleMetadataV8, sectionIndex): ModulesWithCalls => {
|
||||
const section = stringCamelCase(name.toString());
|
||||
|
||||
result[section] = modul.calls.unwrap().reduce((newModule, callMetadata, methodIndex): Calls => {
|
||||
result[section] = calls.unwrap().reduce((newModule: Calls, callMetadata, methodIndex): Calls => {
|
||||
const method = stringCamelCase(callMetadata.name.toString());
|
||||
|
||||
newModule[method] = createUnchecked(section, sectionIndex, methodIndex, callMetadata);
|
||||
|
||||
return newModule;
|
||||
}, {} as unknown as Calls);
|
||||
}, {});
|
||||
|
||||
return result;
|
||||
}, { ...extrinsics });
|
||||
|
||||
@@ -2,17 +2,26 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { ModulesWithCalls } from '@polkadot/types/types';
|
||||
|
||||
import '@polkadot/types/injector';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import testingPairs from '@polkadot/keyring/testingPairs';
|
||||
import { createType } from '@polkadot/types';
|
||||
import { createType, Metadata } from '@polkadot/types';
|
||||
import metadataStatic from '@polkadot/types/Metadata/static';
|
||||
|
||||
import extrinsics from './static';
|
||||
import fromMetadata from './fromMetadata';
|
||||
|
||||
const keyring = testingPairs({ type: 'ed25519' }, false);
|
||||
|
||||
describe('extrinsics', (): void => {
|
||||
let extrinsics: ModulesWithCalls;
|
||||
|
||||
beforeEach((): void => {
|
||||
extrinsics = fromMetadata(new Metadata(metadataStatic));
|
||||
});
|
||||
|
||||
it('encodes an actual transfer (actual data)', (): void => {
|
||||
expect(
|
||||
createType('Extrinsic',
|
||||
@@ -35,10 +44,10 @@ describe('extrinsics', (): void => {
|
||||
'2502' + // length
|
||||
'81' + // signed flag
|
||||
'ffd172a74cda4c865912c32ba0a80a57ae69abae410e5ccb59dee84e2f4432db4f' + // who
|
||||
'fa4c192f6960a3bcdbdee5bcd9c26a3f971b131081912abcc31eab6a0b7589ab' + // sig1
|
||||
'7f99b81a01738cb5e2a911a19d5daa5c0b654d4b8dbc521a6b29090c6d205903' + // sig2
|
||||
'5322aca55349f72dbfa57f3e2484f3457c960fbd7f540fcf70433180c70f8af5' + // sig1
|
||||
'0f3c8dd7a7fbc8e23cfd9e3bc87f31008598e2be3feef512ed942f0240e1a908' + // sig2
|
||||
'0000' + // nonce & era
|
||||
'0500' + // balances.transfer
|
||||
'0600' + // balances.transfer
|
||||
'ffd7568e5f0a7eda67a82691ff379ac4bba4f9c9b859fe779b5d46363b61ad2db9' + // to
|
||||
'e56c' // value
|
||||
);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
import { ModulesWithCalls } from '@polkadot/types/types';
|
||||
|
||||
import { Metadata } from '@polkadot/types';
|
||||
import Metadata from '@polkadot/types/Metadata';
|
||||
import metadataRpc from '@polkadot/types/Metadata/static';
|
||||
|
||||
import fromMetadata from './fromMetadata';
|
||||
|
||||
@@ -5,9 +5,8 @@
|
||||
import { Codec } from '@polkadot/types/types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import { Bytes, Compact, StorageKey, U8a } from '@polkadot/types';
|
||||
import { createType, createTypeUnsafe } from '@polkadot/types/codec';
|
||||
import { StorageEntryMetadata, StorageEntryType } from '@polkadot/types/Metadata/v7/Storage';
|
||||
import { Compact, U8a, createType, createTypeUnsafe } from '@polkadot/types/codec';
|
||||
import { StorageEntryMetadata, StorageEntryType } from '@polkadot/types/Metadata/v8/Storage';
|
||||
import { StorageEntry } from '@polkadot/types/primitive/StorageKey';
|
||||
import { assert, isNull, isUndefined, stringLowerFirst, stringToU8a, u8aConcat } from '@polkadot/util';
|
||||
|
||||
@@ -121,15 +120,15 @@ function extendLinkedMap ({ meta: { documentation, name, type } }: CreateItemFn,
|
||||
// meta fallback only applies to actual entry values, create one for head
|
||||
headFn.meta = new StorageEntryMetadata({
|
||||
name,
|
||||
modifier: createType('StorageEntryModifierV7', 1), // required
|
||||
type: new StorageEntryType(createType('PlainTypeV7', type.asMap.key), 0),
|
||||
fallback: new Bytes(createTypeUnsafe(type.asMap.key.toString()).toHex()),
|
||||
modifier: createType('StorageEntryModifierLatest', 1), // required
|
||||
type: new StorageEntryType(createType('PlainTypeLatest', type.asMap.key), 0),
|
||||
fallback: createType('Bytes', createTypeUnsafe(type.asMap.key.toString()).toHex()),
|
||||
documentation
|
||||
});
|
||||
|
||||
// here we pass the section/method through as well - these are not on
|
||||
// the function itself, so specify these explicitly to the constructor
|
||||
storageFn.headKey = new StorageKey(headFn, {
|
||||
storageFn.headKey = createType('StorageKey', headFn, {
|
||||
method: storageFn.method,
|
||||
section: `head of ${storageFn.section}`
|
||||
});
|
||||
|
||||
@@ -5,18 +5,12 @@
|
||||
import '@polkadot/types/injector';
|
||||
|
||||
import testingPairs from '@polkadot/keyring/testingPairs';
|
||||
import { Metadata } from '@polkadot/types';
|
||||
import json from '@polkadot/types/Metadata/static';
|
||||
import { u8aToHex } from '@polkadot/util';
|
||||
|
||||
import fromMetadata from '../fromMetadata';
|
||||
import storage from '../static';
|
||||
|
||||
const keyring = testingPairs({ type: 'ed25519' });
|
||||
|
||||
// Use the pre-generated metadata
|
||||
const metadata = new Metadata(json);
|
||||
const storage = fromMetadata(metadata);
|
||||
|
||||
describe('fromMetadata', (): void => {
|
||||
it('should throw if the storage function expects an argument', (): void => {
|
||||
expect((): any => storage.balances.freeBalance()).toThrowError(/requires one argument/);
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { StorageEntryMetadata, StorageEntryType } from '@polkadot/types/Metadata/v7/Storage';
|
||||
import { StorageEntryMetadata, StorageEntryType } from '@polkadot/types/Metadata/v8/Storage';
|
||||
import { StorageEntry } from '@polkadot/types/primitive/StorageKey';
|
||||
import { createType, Text, Vec } from '@polkadot/types';
|
||||
import { createType } from '@polkadot/types/codec';
|
||||
|
||||
import createFunction from './createFunction';
|
||||
|
||||
@@ -18,8 +18,8 @@ const createRuntimeFunction = (method: string, key: string, { documentation, typ
|
||||
createFunction(
|
||||
{
|
||||
meta: {
|
||||
documentation: new Vec(Text, [documentation]),
|
||||
modifier: createType('StorageEntryModifierV7', 1), // required
|
||||
documentation: createType('Vec<Text>', [documentation]),
|
||||
modifier: createType('StorageEntryModifierLatest', 1), // required
|
||||
type: new StorageEntryType(type, 0),
|
||||
toJSON: (): any => key
|
||||
} as unknown as StorageEntryMetadata,
|
||||
|
||||
+10
-10
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@polkadot/api",
|
||||
"version": "0.93.1",
|
||||
"version": "0.95.2",
|
||||
"description": "Promise and RxJS wrappers around the Polkadot JS RPC",
|
||||
"main": "index.js",
|
||||
"keywords": [
|
||||
@@ -26,16 +26,16 @@
|
||||
},
|
||||
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/api#readme",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.6.2",
|
||||
"@polkadot/api-derive": "^0.93.1",
|
||||
"@polkadot/api-metadata": "^0.93.1",
|
||||
"@polkadot/keyring": "^1.5.1",
|
||||
"@polkadot/rpc-core": "^0.93.1",
|
||||
"@polkadot/rpc-provider": "^0.93.1",
|
||||
"@polkadot/types": "^0.93.1",
|
||||
"@polkadot/util-crypto": "^1.5.1"
|
||||
"@babel/runtime": "^7.6.3",
|
||||
"@polkadot/api-derive": "^0.95.2",
|
||||
"@polkadot/api-metadata": "^0.95.2",
|
||||
"@polkadot/keyring": "^1.6.1",
|
||||
"@polkadot/rpc-core": "^0.95.2",
|
||||
"@polkadot/rpc-provider": "^0.95.2",
|
||||
"@polkadot/types": "^0.95.2",
|
||||
"@polkadot/util-crypto": "^1.6.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@polkadot/keyring": "^1.5.1"
|
||||
"@polkadot/keyring": "^1.6.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,20 +2,23 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { RpcMethod } from '@polkadot/jsonrpc/types';
|
||||
import { RpcInterface } from '@polkadot/rpc-core/jsonrpc.types';
|
||||
import { Call, Hash, RuntimeVersion } from '@polkadot/types/interfaces';
|
||||
import { AnyFunction, CallFunction, Codec, CodecArg as Arg, ModulesWithCalls } from '@polkadot/types/types';
|
||||
import { SubmittableExtrinsic } from '../submittable/types';
|
||||
import { ApiInterfaceRx, ApiOptions, ApiTypes, DecorateMethod, DecoratedRpc, DecoratedRpcSection, QueryableModuleStorage, QueryableStorage, QueryableStorageEntry, QueryableStorageMulti, QueryableStorageMultiArg, SubmittableExtrinsicFunction, SubmittableExtrinsics, SubmittableModuleExtrinsics } from '../types';
|
||||
import {
|
||||
ApiInterfaceRx, ApiOptions, ApiTypes,
|
||||
DecorateMethod, DecoratedRpc, DecoratedRpcSection,
|
||||
QueryableModuleStorage, QueryableStorage, QueryableStorageEntry, QueryableStorageMulti, QueryableStorageMultiArg,
|
||||
SubmittableExtrinsicFunction, SubmittableExtrinsics, SubmittableModuleExtrinsics
|
||||
} from '../types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { map, switchMap } from 'rxjs/operators';
|
||||
import decorateDerive from '@polkadot/api-derive';
|
||||
import decorateDerive, { ExactDerive } from '@polkadot/api-derive';
|
||||
import { Constants } from '@polkadot/api-metadata/consts/types';
|
||||
import { Storage } from '@polkadot/api-metadata/storage/types';
|
||||
import jsonrpc from '@polkadot/jsonrpc';
|
||||
import RpcCore from '@polkadot/rpc-core';
|
||||
import { WsProvider } from '@polkadot/rpc-provider';
|
||||
import { Metadata, Null, u64 } from '@polkadot/types';
|
||||
@@ -25,7 +28,7 @@ import { StorageEntry } from '@polkadot/types/primitive/StorageKey';
|
||||
import { compactStripLength, u8aToHex } from '@polkadot/util';
|
||||
|
||||
import { createSubmittable } from '../submittable';
|
||||
import { decorateSections } from '../util/decorate';
|
||||
import { decorateSections, DeriveAllSections } from '../util/decorate';
|
||||
import Events from './Events';
|
||||
|
||||
interface MetaDecoration {
|
||||
@@ -64,8 +67,6 @@ export default abstract class Decorate<ApiType> extends Events {
|
||||
|
||||
protected _rpcCore: RpcCore;
|
||||
|
||||
private _rpcMap: Map<string, RpcMethod> = new Map();
|
||||
|
||||
protected _runtimeMetadata?: Metadata;
|
||||
|
||||
protected _runtimeVersion?: RuntimeVersion;
|
||||
@@ -90,7 +91,7 @@ export default abstract class Decorate<ApiType> extends Events {
|
||||
* implemented by transforming the Observable to Stream/Iterator/Kefir/Bacon
|
||||
* via `deocrateMethod`.
|
||||
*/
|
||||
protected decorateMethod: DecorateMethod;
|
||||
protected decorateMethod: DecorateMethod<ApiType>;
|
||||
|
||||
/**
|
||||
* @description Create an instance of the class
|
||||
@@ -110,7 +111,7 @@ export default abstract class Decorate<ApiType> extends Events {
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
public constructor (options: ApiOptions, type: ApiTypes, decorateMethod: DecorateMethod) {
|
||||
public constructor (options: ApiOptions, type: ApiTypes, decorateMethod: DecorateMethod<ApiType>) {
|
||||
super();
|
||||
|
||||
const thisProvider = options.source
|
||||
@@ -120,8 +121,16 @@ export default abstract class Decorate<ApiType> extends Events {
|
||||
this.decorateMethod = decorateMethod;
|
||||
this._options = options;
|
||||
this._type = type;
|
||||
this._rpcCore = new RpcCore(thisProvider);
|
||||
this._rpcCore = new RpcCore(thisProvider, this._options.rpc);
|
||||
this._isConnected = new BehaviorSubject(this._rpcCore.provider.isConnected());
|
||||
this._rx.hasSubscriptions = this._rpcCore.provider.hasSubscriptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns `true` if the API operates with subscriptions
|
||||
*/
|
||||
get hasSubscriptions (): boolean {
|
||||
return this._rpcCore.provider.hasSubscriptions;
|
||||
}
|
||||
|
||||
private decorateFunctionMeta (input: MetaDecoration, output: MetaDecoration): MetaDecoration {
|
||||
@@ -141,7 +150,7 @@ export default abstract class Decorate<ApiType> extends Events {
|
||||
// manner to cater for both old and new:
|
||||
// - when the number of entries are 0, only remove the ones with isOptional (account & contracts)
|
||||
// - when non-zero, remove anything that is not in the array (we don't do this)
|
||||
protected async filterRpcMethods (): Promise<void> {
|
||||
protected async filterRpc (): Promise<void> {
|
||||
let methods: string[];
|
||||
|
||||
try {
|
||||
@@ -152,11 +161,15 @@ export default abstract class Decorate<ApiType> extends Events {
|
||||
methods = [];
|
||||
}
|
||||
|
||||
this.filterRpcMethods(methods);
|
||||
}
|
||||
|
||||
protected filterRpcMethods (methods: string[]): void{
|
||||
// this is true when the RPC has entries
|
||||
const hasResults = methods.length !== 0;
|
||||
|
||||
// loop through all entries we have (populated in decorate) and filter as required
|
||||
[...this._rpcMap.entries()]
|
||||
[...this._rpcCore.mapping.entries()]
|
||||
.filter(([key, { isOptional }]): boolean =>
|
||||
// only remove when we have results and method missing, or with no results if optional
|
||||
hasResults
|
||||
@@ -170,16 +183,16 @@ export default abstract class Decorate<ApiType> extends Events {
|
||||
});
|
||||
}
|
||||
|
||||
protected decorateRpc<ApiType> (rpc: RpcCore, decorateMethod: Decorate<ApiType>['decorateMethod']): DecoratedRpc<ApiType, RpcInterface> {
|
||||
return Object.keys(jsonrpc).reduce((out, _sectionName): DecoratedRpc<ApiType, RpcInterface> => {
|
||||
protected decorateRpc<ApiType> (rpc: RpcCore, decorateMethod: DecorateMethod<ApiType>): DecoratedRpc<ApiType, RpcInterface> {
|
||||
return rpc.sections.reduce((out, _sectionName): DecoratedRpc<ApiType, RpcInterface> => {
|
||||
const sectionName = _sectionName as keyof DecoratedRpc<ApiType, RpcInterface>;
|
||||
|
||||
// out and section here are horrors to get right from a typing perspective :()
|
||||
// out and section here are horrors to get right from a typing perspective :(
|
||||
(out as any)[sectionName] = Object.entries(rpc[sectionName]).reduce((section, [methodName, method]): DecoratedRpcSection<ApiType, RpcInterface[typeof sectionName]> => {
|
||||
(section as any)[methodName] = decorateMethod(method, { methodName });
|
||||
|
||||
// add this endpoint mapping to our internal map - we use this for filters
|
||||
this._rpcMap.set(`${sectionName}_${methodName}`, jsonrpc[sectionName].methods[methodName]);
|
||||
// skip subscriptions where we have a non-subscribe interface
|
||||
if (this.hasSubscriptions || !(methodName.startsWith('subscribe') || methodName.startsWith('unsubscribe'))) {
|
||||
(section as any)[methodName] = decorateMethod(method, { methodName });
|
||||
}
|
||||
|
||||
return section;
|
||||
}, {} as unknown as DecoratedRpcSection<ApiType, RpcInterface[typeof sectionName]>);
|
||||
@@ -188,7 +201,7 @@ export default abstract class Decorate<ApiType> extends Events {
|
||||
}, {} as unknown as DecoratedRpc<ApiType, RpcInterface>);
|
||||
}
|
||||
|
||||
protected decorateMulti<ApiType> (decorateMethod: Decorate<ApiType>['decorateMethod']): QueryableStorageMulti<ApiType> {
|
||||
protected decorateMulti<ApiType> (decorateMethod: DecorateMethod<ApiType>): QueryableStorageMulti<ApiType> {
|
||||
return decorateMethod((calls: QueryableStorageMultiArg<ApiType>[]): Observable<Codec[]> =>
|
||||
this._rpcCore.state.subscribeStorage(
|
||||
calls.map((arg: QueryableStorageMultiArg<ApiType>): [QueryableStorageEntry<ApiType>, ...Arg[]] =>
|
||||
@@ -198,7 +211,7 @@ export default abstract class Decorate<ApiType> extends Events {
|
||||
: [arg.creator] as any)));
|
||||
}
|
||||
|
||||
protected decorateExtrinsics<ApiType> (extrinsics: ModulesWithCalls, decorateMethod: Decorate<ApiType>['decorateMethod']): SubmittableExtrinsics<ApiType> {
|
||||
protected decorateExtrinsics<ApiType> (extrinsics: ModulesWithCalls, decorateMethod: DecorateMethod<ApiType>): SubmittableExtrinsics<ApiType> {
|
||||
const creator = createSubmittable(this._type, this._rx as ApiInterfaceRx, decorateMethod);
|
||||
|
||||
return Object.entries(extrinsics).reduce((out, [name, section]): SubmittableExtrinsics<ApiType> => {
|
||||
@@ -219,7 +232,7 @@ export default abstract class Decorate<ApiType> extends Events {
|
||||
return this.decorateFunctionMeta(method, decorated as any) as SubmittableExtrinsicFunction<ApiType>;
|
||||
}
|
||||
|
||||
protected decorateStorage<ApiType> (storage: Storage, decorateMethod: Decorate<ApiType>['decorateMethod']): QueryableStorage<ApiType> {
|
||||
protected decorateStorage<ApiType> (storage: Storage, decorateMethod: DecorateMethod<ApiType>): QueryableStorage<ApiType> {
|
||||
return Object.entries(storage).reduce((out, [name, section]): QueryableStorage<ApiType> => {
|
||||
out[name] = Object.entries(section).reduce((out, [name, method]): QueryableModuleStorage<ApiType> => {
|
||||
out[name] = this.decorateStorageEntry(method, decorateMethod);
|
||||
@@ -231,21 +244,25 @@ export default abstract class Decorate<ApiType> extends Events {
|
||||
}, {} as unknown as QueryableStorage<ApiType>);
|
||||
}
|
||||
|
||||
private decorateStorageEntry<ApiType> (creator: StorageEntry, decorateMethod: Decorate<ApiType>['decorateMethod']): QueryableStorageEntry<ApiType> {
|
||||
private decorateStorageEntry<ApiType> (creator: StorageEntry, decorateMethod: DecorateMethod<ApiType>): QueryableStorageEntry<ApiType> {
|
||||
// get the storage arguments, with DoubleMap as an array entry, otherwise spread
|
||||
const getArgs = (...args: any[]): any[] => creator.meta.type.isDoubleMap
|
||||
? [creator, args]
|
||||
: [creator, ...args];
|
||||
|
||||
const decorated = creator.headKey
|
||||
// FIXME We probably want to be able to query the full list with non-subs as well
|
||||
const decorated = this.hasSubscriptions && creator.headKey
|
||||
? this.decorateStorageEntryLinked(creator, decorateMethod)
|
||||
: decorateMethod((...args: any[]): Observable<Codec> =>
|
||||
this._rpcCore.state
|
||||
// Unfortunately for one-shot calls we also use .subscribeStorage here
|
||||
.subscribeStorage<[Codec]>([getArgs(...args)])
|
||||
// state_storage returns an array of values, since we have just subscribed to
|
||||
// a single entry, we pull that from the array and return it as-is
|
||||
.pipe(map(([data]): Codec => data)), { methodName: creator.method });
|
||||
: decorateMethod((...args: any[]): Observable<Codec> => (
|
||||
this.hasSubscriptions
|
||||
? this._rpcCore.state
|
||||
// Unfortunately for one-shot calls we also use .subscribeStorage here
|
||||
.subscribeStorage<[Codec]>([getArgs(...args)])
|
||||
// state_storage returns an array of values, since we have just subscribed to
|
||||
// a single entry, we pull that from the array and return it as-is
|
||||
.pipe(map(([data]): Codec => data))
|
||||
: this._rpcCore.state.getStorage(getArgs(...args))
|
||||
), { methodName: creator.method });
|
||||
|
||||
decorated.creator = creator;
|
||||
|
||||
@@ -258,10 +275,12 @@ export default abstract class Decorate<ApiType> extends Events {
|
||||
decorated.key = (arg1?: Arg, arg2?: Arg): string =>
|
||||
u8aToHex(compactStripLength(creator(creator.meta.type.isDoubleMap ? [arg1, arg2] : arg1))[1]);
|
||||
|
||||
// When using double map storage function, user need to pass double map key as an array
|
||||
decorated.multi = decorateMethod((args: (Arg | Arg[])[]): Observable<Codec[]> =>
|
||||
this._rpcCore.state.subscribeStorage(
|
||||
args.map((arg: Arg[] | Arg): [StorageEntry, Arg | Arg[]] => [creator, arg])));
|
||||
if (this.hasSubscriptions) {
|
||||
// When using double map storage function, user need to pass double map key as an array
|
||||
decorated.multi = decorateMethod((args: (Arg | Arg[])[]): Observable<Codec[]> =>
|
||||
this._rpcCore.state.subscribeStorage(
|
||||
args.map((arg: Arg[] | Arg): [StorageEntry, Arg | Arg[]] => [creator, arg])));
|
||||
}
|
||||
|
||||
decorated.size = decorateMethod((arg1?: Arg, arg2?: Arg): Observable<u64> =>
|
||||
this._rpcCore.state.getStorageSize(getArgs(arg1, arg2)));
|
||||
@@ -269,7 +288,7 @@ export default abstract class Decorate<ApiType> extends Events {
|
||||
return this.decorateFunctionMeta(creator, decorated) as unknown as QueryableStorageEntry<ApiType>;
|
||||
}
|
||||
|
||||
private decorateStorageEntryLinked<ApiType> (creator: StorageEntry, decorateMethod: Decorate<ApiType>['decorateMethod']): ReturnType<Decorate<ApiType>['decorateMethod']> {
|
||||
private decorateStorageEntryLinked<ApiType> (creator: StorageEntry, decorateMethod: DecorateMethod<ApiType>): ReturnType<DecorateMethod<ApiType>> {
|
||||
const result: Map<Codec, [Codec, Linkage<Codec>]> = new Map();
|
||||
let subject: BehaviorSubject<LinkageResult>;
|
||||
let head: Codec | null = null;
|
||||
@@ -337,13 +356,11 @@ export default abstract class Decorate<ApiType> extends Events {
|
||||
);
|
||||
}
|
||||
|
||||
// FIXME Any better ideas? `any` doesn't work, needs a return but TS infers
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
||||
protected decorateDerive (apiRx: ApiInterfaceRx, decorateMethod: Decorate<ApiType>['decorateMethod']) {
|
||||
protected decorateDerive (apiRx: ApiInterfaceRx, decorateMethod: DecorateMethod<ApiType>): DeriveAllSections<ApiType, ExactDerive> {
|
||||
// Pull in derive from api-derive
|
||||
const derive = decorateDerive(apiRx, this._options.derives);
|
||||
|
||||
return decorateSections<ApiType, typeof derive>(derive, decorateMethod);
|
||||
return decorateSections<ApiType, ExactDerive>(derive, decorateMethod);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,14 +7,10 @@ import { ApiInterfaceEvents } from '../types';
|
||||
import EventEmitter from 'eventemitter3';
|
||||
|
||||
export default class Events {
|
||||
private _eventemitter: EventEmitter;
|
||||
private _eventemitter = new EventEmitter();
|
||||
|
||||
protected constructor () {
|
||||
this._eventemitter = new EventEmitter();
|
||||
}
|
||||
|
||||
protected emit (type: ApiInterfaceEvents, ...args: any[]): void {
|
||||
this._eventemitter.emit(type, ...args);
|
||||
protected emit (type: ApiInterfaceEvents, ...args: any[]): boolean {
|
||||
return this._eventemitter.emit(type, ...args);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
|
||||
import { SignedBlock } from '@polkadot/types/interfaces';
|
||||
import { RegistryTypes } from '@polkadot/types/types';
|
||||
import { ApiInterfaceRx, ApiOptions, ApiTypes, DecorateMethod } from '../types';
|
||||
import { ApiBase, ApiInterfaceRx, ApiOptions, ApiTypes, DecorateMethod } from '../types';
|
||||
|
||||
import constantsFromMeta from '@polkadot/api-metadata/consts/fromMetadata';
|
||||
import extrinsicsFromMeta from '@polkadot/api-metadata/extrinsics/fromMetadata';
|
||||
import storageFromMeta from '@polkadot/api-metadata/storage/fromMetadata';
|
||||
import { GenericCall, GenericEvent, Metadata, u32 as U32 } from '@polkadot/types';
|
||||
import { LATEST_VERSION as EXTRINSIC_LATEST_VERSION } from '@polkadot/types/primitive/Extrinsic/constants';
|
||||
import { assert, logger } from '@polkadot/util';
|
||||
import { LATEST_EXTRINSIC_VERSION } from '@polkadot/types/primitive/Extrinsic/Extrinsic';
|
||||
import { logger } from '@polkadot/util';
|
||||
import { cryptoWaitReady, setSS58Format } from '@polkadot/util-crypto';
|
||||
import addressDefaults from '@polkadot/util-crypto/address/defaults';
|
||||
|
||||
@@ -56,10 +56,12 @@ const l = logger('api/decorator');
|
||||
export default abstract class Init<ApiType> extends Decorate<ApiType> {
|
||||
private _healthTimer: NodeJS.Timeout | null = null;
|
||||
|
||||
public constructor (options: ApiOptions, type: ApiTypes, decorateMethod: DecorateMethod) {
|
||||
public constructor (options: ApiOptions, type: ApiTypes, decorateMethod: DecorateMethod<ApiType>) {
|
||||
super(options, type, decorateMethod);
|
||||
|
||||
assert(this._rpcCore.provider.hasSubscriptions, 'Api can only be used with a provider supporting subscriptions');
|
||||
if (!this.hasSubscriptions) {
|
||||
console.warn('Api will be available in a limited mode since the provider does not support subscriptions');
|
||||
}
|
||||
|
||||
// We only register the types (global) if this is not a cloned instance.
|
||||
// Do right up-front, so we get in the user types before we are actually
|
||||
@@ -89,15 +91,33 @@ export default abstract class Init<ApiType> extends Decorate<ApiType> {
|
||||
if (!this._options.source || !this._options.source._isReady) {
|
||||
this._runtimeMetadata = await this.metaFromChain(metadata);
|
||||
} else {
|
||||
this._extrinsicType = this._options.source.extrinsicVersion;
|
||||
this._runtimeMetadata = this._options.source.runtimeMetadata;
|
||||
this._runtimeVersion = this._options.source.runtimeVersion;
|
||||
this._genesisHash = this._options.source.genesisHash;
|
||||
this._runtimeMetadata = await this.metaFromSource(this._options.source);
|
||||
}
|
||||
|
||||
return this.initFromMeta(this._runtimeMetadata);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
private async metaFromSource (source: ApiBase<any>): Promise<Metadata> {
|
||||
this._extrinsicType = source.extrinsicVersion;
|
||||
this._runtimeVersion = source.runtimeVersion;
|
||||
this._genesisHash = source.genesisHash;
|
||||
|
||||
const methods: string[] = [];
|
||||
|
||||
// manually build a list of all available methods in this RPC, we are
|
||||
// going to filter on it to align the cloned RPC without making a call
|
||||
Object.keys(source.rpc).forEach((section): void => {
|
||||
Object.keys((source.rpc as any)[section]).forEach((method): void => {
|
||||
methods.push(`${section}_${method}`);
|
||||
});
|
||||
});
|
||||
|
||||
this.filterRpcMethods(methods);
|
||||
|
||||
return source.runtimeMetadata;
|
||||
}
|
||||
|
||||
private async metaFromChain (optMetadata: Record<string, string>): Promise<Metadata> {
|
||||
const { typesChain = {}, typesSpec = {} } = this._options;
|
||||
const [genesisHash, runtimeVersion, chain, chainProps] = await Promise.all([
|
||||
@@ -118,7 +138,7 @@ export default abstract class Init<ApiType> extends Decorate<ApiType> {
|
||||
});
|
||||
|
||||
// filter the RPC methods (this does an rpc-methods call)
|
||||
await this.filterRpcMethods();
|
||||
await this.filterRpc();
|
||||
|
||||
// retrieve metadata, either from chain or as pass-in via options
|
||||
const metadataKey = `${genesisHash}-${runtimeVersion.specVersion}`;
|
||||
@@ -154,13 +174,13 @@ export default abstract class Init<ApiType> extends Decorate<ApiType> {
|
||||
// only inject if we are not a clone (global init)
|
||||
if (!this._options.source) {
|
||||
GenericEvent.injectMetadata(metadata);
|
||||
GenericCall.injectMethods(extrinsics);
|
||||
GenericCall.injectMetadata(metadata);
|
||||
|
||||
// detect the extrinsic version in-use based on the last block
|
||||
const { block: { extrinsics: [firstTx] } }: SignedBlock = await this._rpcCore.chain.getBlock().toPromise();
|
||||
|
||||
// If we haven't sync-ed to 1 yes, this won't have any values
|
||||
this._extrinsicType = firstTx ? firstTx.type : EXTRINSIC_LATEST_VERSION;
|
||||
this._extrinsicType = firstTx ? firstTx.type : LATEST_EXTRINSIC_VERSION;
|
||||
}
|
||||
|
||||
this._extrinsics = this.decorateExtrinsics(extrinsics, this.decorateMethod);
|
||||
|
||||
@@ -4,11 +4,12 @@
|
||||
|
||||
import { RpcInterface } from '@polkadot/rpc-core/jsonrpc.types';
|
||||
import { Hash, RuntimeVersion } from '@polkadot/types/interfaces';
|
||||
import { CallFunction, RegistryTypes, SignerPayloadRawBase } from '@polkadot/types/types';
|
||||
import { InterfaceRegistry } from '@polkadot/types/interfaceRegistry';
|
||||
import { CallFunction, InterfaceTypes, RegistryTypes, SignerPayloadRawBase } from '@polkadot/types/types';
|
||||
import { ApiOptions, ApiTypes, DecoratedRpc, DecorateMethod, QueryableStorage, QueryableStorageMulti, SubmittableExtrinsics, Signer } from '../types';
|
||||
|
||||
import { Constants } from '@polkadot/api-metadata/consts/types';
|
||||
import { GenericCall, Metadata, getTypeRegistry } from '@polkadot/types';
|
||||
import { GenericCall, Metadata, createType, getTypeRegistry } from '@polkadot/types';
|
||||
import { assert, isString, isUndefined, u8aToHex, u8aToU8a } from '@polkadot/util';
|
||||
|
||||
import Init from './Init';
|
||||
@@ -26,8 +27,8 @@ try {
|
||||
pkgJson = { name: '@polkadot/api', version: '-' };
|
||||
}
|
||||
|
||||
function assertResult <T> (value: T | undefined): T {
|
||||
assert(!isUndefined(value), 'Api needs to be initialised before using, listen on \'ready\'');
|
||||
function assertResult<T> (value: T | undefined): T {
|
||||
assert(!isUndefined(value), 'Api needs to be initialized before using, listen on \'ready\'');
|
||||
|
||||
return value as T;
|
||||
}
|
||||
@@ -51,7 +52,7 @@ export default abstract class ApiBase<ApiType> extends Init<ApiType> {
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
public constructor (options: ApiOptions = {}, type: ApiTypes, decorateMethod: DecorateMethod) {
|
||||
public constructor (options: ApiOptions = {}, type: ApiTypes, decorateMethod: DecorateMethod<ApiType>) {
|
||||
super(options, type, decorateMethod);
|
||||
}
|
||||
|
||||
@@ -162,7 +163,7 @@ export default abstract class ApiBase<ApiType> extends Init<ApiType> {
|
||||
/**
|
||||
* @description Contains all the raw rpc sections and their subsequent methods in the API as defined by the jsonrpc interface definitions. Unlike the dynamic `api.query` and `api.tx` sections, these methods are fixed (although extensible with node upgrades) and not determined by the runtime.
|
||||
*
|
||||
* RPC endpoints available here allow for the query of chain, node and system information, in addition to providing interfaces for the raw queries of state (usine known keys) and the submission of transactions.
|
||||
* RPC endpoints available here allow for the query of chain, node and system information, in addition to providing interfaces for the raw queries of state (using known keys) and the submission of transactions.
|
||||
*
|
||||
* @example
|
||||
* <BR>
|
||||
@@ -217,7 +218,14 @@ export default abstract class ApiBase<ApiType> extends Init<ApiType> {
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Disconnect from the underlying provider, halting all comms
|
||||
* @description Creates an instance of a type as registered
|
||||
*/
|
||||
public createType<K extends InterfaceTypes> (type: K, ...params: any[]): InterfaceRegistry[K] {
|
||||
return createType(type, ...params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Disconnect from the underlying provider, halting all network traffic
|
||||
*/
|
||||
public disconnect (): void {
|
||||
this._rpcCore.disconnect();
|
||||
|
||||
@@ -28,9 +28,8 @@ async function derive (api: ApiPromise): Promise<void> {
|
||||
console.log('current author:', header.author);
|
||||
});
|
||||
|
||||
await api.query.staking.intentions((intentions): void => {
|
||||
console.log('intentions:', intentions);
|
||||
});
|
||||
const fees = await api.derive.balances.fees();
|
||||
console.log('fees', fees);
|
||||
}
|
||||
|
||||
async function query (api: ApiPromise, keyring: TestKeyringMap): Promise<void> {
|
||||
|
||||
@@ -72,7 +72,7 @@ export default class Submittable<ApiType> extends _Extrinsic implements Submitta
|
||||
// signAndSend implementation for all 3 cases above
|
||||
public signAndSend (account: IKeyringPair | string | AccountId | Address, optionsOrStatus?: Partial<SignerOptions> | Callback<SubmittableResultImpl>, optionalStatusCb?: Callback<SubmittableResultImpl>): SubmitableResultResult<ApiType> | SubmitableResultSubscription<ApiType> {
|
||||
const [options, statusCb] = this._makeSignAndSendOptions(optionsOrStatus, optionalStatusCb);
|
||||
const isSubscription = this._ignoreStatusCb || !!statusCb;
|
||||
const isSubscription = this._api.hasSubscriptions && (this._ignoreStatusCb || !!statusCb);
|
||||
const address = isKeyringPair(account) ? account.address : account.toString();
|
||||
let updateId: number | undefined;
|
||||
|
||||
@@ -106,7 +106,7 @@ export default class Submittable<ApiType> extends _Extrinsic implements Submitta
|
||||
|
||||
// send implementation for both immediate Hash and statusCb variants
|
||||
public send (statusCb?: Callback<SubmittableResultImpl>): SubmitableResultResult<ApiType> | SubmitableResultSubscription<ApiType> {
|
||||
const isSubscription = this._ignoreStatusCb || !!statusCb;
|
||||
const isSubscription = this._api.hasSubscriptions && (this._ignoreStatusCb || !!statusCb);
|
||||
|
||||
return this._decorateMethod(
|
||||
isSubscription
|
||||
@@ -193,9 +193,12 @@ export default class Submittable<ApiType> extends _Extrinsic implements Submitta
|
||||
return combineLatest([
|
||||
// if we have a nonce already, don't retrieve the latest, use what is there
|
||||
isUndefined(options.nonce)
|
||||
? this._api.rpc.account.nextIndex
|
||||
? this._api.rpc.account.nextIndex(address)
|
||||
: this._api.query.system.accountNonce(address)
|
||||
// FIXME This apparently is having issues on latest Kusama for nonce retrieval,
|
||||
// hence we are using the accountNonce only
|
||||
// ? this._api.rpc.account.nextIndex
|
||||
// ? this._api.rpc.account.nextIndex(address)
|
||||
// : this._api.query.system.accountNonce(address)
|
||||
? this._api.query.system.accountNonce(address)
|
||||
: of(createType('Index', options.nonce)),
|
||||
// if we have an era provided already or eraLength is <= 0 (immortal)
|
||||
// don't get the latest block, just pass null, handle in mergeMap
|
||||
|
||||
@@ -2,6 +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 { UserRpc } from '@polkadot/rpc-core/types';
|
||||
import { Hash, RuntimeVersion } from '@polkadot/types/interfaces';
|
||||
import { AnyFunction, Callback, CallFunction, Codec, CodecArg, RegistryTypes, SignatureOptions, SignerPayloadJSON, SignerPayloadRaw } from '@polkadot/types/types';
|
||||
import { SubmittableResultImpl, SubmittableExtrinsic } from './submittable/types';
|
||||
@@ -50,7 +51,7 @@ export interface DecorateMethodOptions {
|
||||
methodName?: string;
|
||||
}
|
||||
|
||||
export type DecorateMethod = (method: (...args: any[]) => Observable<any>, options?: DecorateMethodOptions) => any;
|
||||
export type DecorateMethod<ApiType> = <Method extends (...args: any[]) => Observable<any>>(method: Method, options?: DecorateMethodOptions) => any;
|
||||
|
||||
// Here are the return types of these parts of the api:
|
||||
// - api.query.*.*: no exact typings
|
||||
@@ -185,6 +186,10 @@ export interface ApiOptions {
|
||||
* connecting to a WsProvider connecting localhost with the default port, i.e. `ws://127.0.0.1:9944`
|
||||
*/
|
||||
provider?: ProviderInterface;
|
||||
/**
|
||||
* @description User-defined RPC methods
|
||||
*/
|
||||
rpc?: UserRpc;
|
||||
/**
|
||||
* @description An external signer which will be used to sign extrinsic when account passed in is not KeyringPair
|
||||
*/
|
||||
@@ -260,3 +265,5 @@ export interface Signer {
|
||||
*/
|
||||
update?: (id: number, status: Hash | SubmittableResultImpl) => void;
|
||||
}
|
||||
|
||||
export { ApiBase };
|
||||
|
||||
@@ -3,7 +3,14 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { AnyFunction } from '@polkadot/types/types';
|
||||
import { MethodResult } from '../types';
|
||||
import { DecorateMethod, MethodResult } from '../types';
|
||||
|
||||
// Most generic typings for `api.derive.*.*`
|
||||
type AnyDerive = Record<string, Record<string, AnyFunction>>;
|
||||
// Exact typings for a particular section `api.derive.section.*`
|
||||
type DeriveSection<ApiType, Section extends Record<string, AnyFunction>> = { [MethodName in keyof Section]: MethodResult<ApiType, Section[MethodName]> };
|
||||
// Exact typings for all sections `api.derive.*.*`
|
||||
export type DeriveAllSections<ApiType, AllSections extends AnyDerive> = { [SectionName in keyof AllSections]: DeriveSection<ApiType, AllSections[SectionName]> };
|
||||
|
||||
// A technically unsafe version of Object.keys(obj) that assumes that
|
||||
// obj only has known properties of T
|
||||
@@ -11,45 +18,44 @@ function keys<T extends object> (obj: T): (keyof T)[] {
|
||||
return Object.keys(obj) as (keyof T)[];
|
||||
}
|
||||
|
||||
// FIXME the return value typings here is horrible and not DRY
|
||||
function decorateMethods<ApiType, Section extends Record<keyof Section, (...args: any[]) => any>> (
|
||||
/**
|
||||
* This is a methods decorator which keeps all type information.
|
||||
*/
|
||||
function decorateMethods<ApiType, Section extends Record<string, AnyFunction>> (
|
||||
section: Section,
|
||||
decorateMethod: <Method extends AnyFunction>(method: Method) => MethodResult<ApiType, Method>
|
||||
): { [MethodName in keyof Section]: MethodResult<ApiType, Section[MethodName]> } {
|
||||
decorateMethod: DecorateMethod<ApiType>
|
||||
): DeriveSection<ApiType, Section> {
|
||||
return keys(section).reduce(
|
||||
<MethodName extends keyof Section>(
|
||||
acc: { [MethodName in keyof Section]: MethodResult<ApiType, Section[MethodName]> },
|
||||
acc: DeriveSection<ApiType, Section>,
|
||||
methodName: MethodName
|
||||
): { [MethodName in keyof Section]: MethodResult<ApiType, Section[MethodName]> } => {
|
||||
): DeriveSection<ApiType, Section> => {
|
||||
const method = section[methodName];
|
||||
|
||||
acc[methodName] = decorateMethod(method) as any;
|
||||
acc[methodName] = decorateMethod(method);
|
||||
|
||||
return acc;
|
||||
},
|
||||
{} as unknown as { [MethodName in keyof Section]: MethodResult<ApiType, Section[MethodName]> }
|
||||
{} as DeriveSection<ApiType, Section>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a section decorator which keeps all type information.
|
||||
*/
|
||||
// FIXME the return value typings here is horrible and not DRY
|
||||
export function decorateSections<ApiType, AllSections extends {
|
||||
[SectionName in keyof AllSections]: Record<keyof AllSections[SectionName], (...args: any[]) => any>
|
||||
}> (
|
||||
export function decorateSections<ApiType, AllSections extends AnyDerive> (
|
||||
allSections: AllSections,
|
||||
decorateMethod: <Method extends AnyFunction>(method: Method) => MethodResult<ApiType, Method>
|
||||
): { [SectionName in keyof AllSections]: { [MethodName in keyof AllSections[SectionName]]: MethodResult<ApiType, AllSections[SectionName][MethodName]> } } {
|
||||
decorateMethod: DecorateMethod<ApiType>
|
||||
): DeriveAllSections<ApiType, AllSections> {
|
||||
return keys(allSections).reduce(
|
||||
<MethodName extends keyof AllSections>(
|
||||
acc: { [SectionName in keyof AllSections]: { [MethodName in keyof AllSections[SectionName]]: MethodResult<ApiType, AllSections[SectionName][MethodName]> } },
|
||||
acc: DeriveAllSections<ApiType, AllSections>,
|
||||
sectionName: MethodName
|
||||
): { [SectionName in keyof AllSections]: { [MethodName in keyof AllSections[SectionName]]: MethodResult<ApiType, AllSections[SectionName][MethodName]> } } => {
|
||||
): DeriveAllSections<ApiType, AllSections> => {
|
||||
acc[sectionName] = decorateMethods(allSections[sectionName], decorateMethod);
|
||||
|
||||
return acc;
|
||||
},
|
||||
{} as unknown as { [SectionName in keyof AllSections]: { [MethodName in keyof AllSections[SectionName]]: MethodResult<ApiType, AllSections[SectionName][MethodName]> } }
|
||||
{} as DeriveAllSections<ApiType, AllSections>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ describeE2E({
|
||||
|
||||
return (
|
||||
api.tx.contracts
|
||||
.create(CREATION_FEE, MAX_GAS, codeHash, abi.deploy(randomStart))
|
||||
.create(CREATION_FEE, MAX_GAS, codeHash, abi.constructors[0](randomStart))
|
||||
.signAndSend(keyring.dave, (result: SubmittableResult): void => {
|
||||
// console.error('create', JSON.stringify(result));
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright 2017-2019 @polkadot/api 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 WsProvider from '@polkadot/rpc-provider/ws';
|
||||
import ApiPromise from '../../../src/promise';
|
||||
import { describeE2E } from '../../util';
|
||||
|
||||
describeE2E({
|
||||
only: ['remote-polkadot-kusama']
|
||||
})('Promise e2e kusama queries', (wsUrl: string): void => {
|
||||
let api: ApiPromise;
|
||||
|
||||
beforeEach(async (done): Promise<void> => {
|
||||
api = await ApiPromise.create({ provider: new WsProvider(wsUrl) });
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
it('retrieves the list of validators', async (): Promise<void> => {
|
||||
const intentions = await api.query.staking.validators();
|
||||
|
||||
console.error(JSON.parse(JSON.stringify(intentions)));
|
||||
});
|
||||
});
|
||||
@@ -84,7 +84,7 @@ describeE2E({
|
||||
|
||||
return (
|
||||
api.tx.contracts
|
||||
.create(CREATION_FEE, MAX_GAS, codeHash, abi.deploy(randomStart))
|
||||
.create(CREATION_FEE, MAX_GAS, codeHash, abi.constructors[0](randomStart))
|
||||
.signAndSend(keyring.dave, (result: SubmittableResult): void => {
|
||||
if (result.status.isFinalized) {
|
||||
const record = result.findRecord('contracts', 'Instantiated');
|
||||
|
||||
@@ -10,6 +10,7 @@ const WS_ENDPOINTS = {
|
||||
'docker-polkadot-master': 'ws://127.0.0.1:9948/',
|
||||
'docker-polkadot-alexander': 'ws://127.0.0.1:9949/',
|
||||
'remote-polkadot-alexander': 'wss://poc3-rpc.polkadot.io/',
|
||||
'remote-polkadot-kusama': 'wss://kusama-rpc.polkadot.io/',
|
||||
'remote-substrate-1.0': 'wss://substrate-rpc.parity.io/'
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@polkadot/rpc-core",
|
||||
"version": "0.93.1",
|
||||
"version": "0.95.2",
|
||||
"description": "A JavaScript wrapper for the Polkadot JsonRPC interface",
|
||||
"main": "index.js",
|
||||
"keywords": [
|
||||
@@ -26,11 +26,11 @@
|
||||
},
|
||||
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/rpc-core#readme",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.6.2",
|
||||
"@polkadot/jsonrpc": "^0.93.1",
|
||||
"@polkadot/rpc-provider": "^0.93.1",
|
||||
"@polkadot/types": "^0.93.1",
|
||||
"@polkadot/util": "^1.5.1",
|
||||
"@babel/runtime": "^7.6.3",
|
||||
"@polkadot/jsonrpc": "^0.95.2",
|
||||
"@polkadot/rpc-provider": "^0.95.2",
|
||||
"@polkadot/types": "^0.95.2",
|
||||
"@polkadot/util": "^1.6.1",
|
||||
"rxjs": "^6.5.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import rpcMetadataV4 from '@polkadot/types/Metadata/v4/static';
|
||||
import rpcMetadataV5 from '@polkadot/types/Metadata/v5/static';
|
||||
import rpcMetadataV6 from '@polkadot/types/Metadata/v6/static';
|
||||
import rpcMetadataV7 from '@polkadot/types/Metadata/v7/static';
|
||||
import rpcMetadataV8 from '@polkadot/types/Metadata/v8/static';
|
||||
|
||||
import Api from '.';
|
||||
|
||||
@@ -212,3 +213,9 @@ formattingTests('v7', fromMetadata(new Metadata(rpcMetadataV7)), [
|
||||
'0x1dbb0224910f42a14e7f1406b24c6fe8157296691b02a78756e01946038fffab',
|
||||
'0xc7879f4faa637a90d782070a3cb6be99a9fb0316e19a0454ce93c4f0a34712f1'
|
||||
]);
|
||||
|
||||
formattingTests('v8', fromMetadata(new Metadata(rpcMetadataV8)), [
|
||||
'0xec8f96437274a883afcac82d01a9defeb68209cd4f2c084632813692aa5e65ad',
|
||||
'0x1dbb0224910f42a14e7f1406b24c6fe8157296691b02a78756e01946038fffab',
|
||||
'0xc7879f4faa637a90d782070a3cb6be99a9fb0316e19a0454ce93c4f0a34712f1'
|
||||
]);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import MockProvider from '@polkadot/rpc-provider/mock';
|
||||
import { isFunction } from '@polkadot/util';
|
||||
|
||||
import Rpc from '.';
|
||||
|
||||
@@ -19,8 +20,40 @@ describe('Api', (): void => {
|
||||
expect(
|
||||
Object.keys(rpc).filter((key): boolean => !key.startsWith('_'))
|
||||
).toEqual([
|
||||
'provider',
|
||||
'provider', 'mapping', 'sections',
|
||||
'account', 'author', 'chain', 'contracts', 'rpc', 'state', 'system'
|
||||
]);
|
||||
});
|
||||
|
||||
it('allows for the definition of user RPCs', (): void => {
|
||||
const rpc = new Rpc(new MockProvider(), {
|
||||
testing: [
|
||||
{
|
||||
name: 'foo',
|
||||
params: [{ name: 'bar', type: 'u32' }],
|
||||
type: 'Balance'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
expect(isFunction((rpc as any).testing.foo)).toBe(true);
|
||||
expect(rpc.sections.includes('testing')).toBe(true);
|
||||
expect(rpc.mapping.get('testing_foo')).toEqual({
|
||||
description: 'User defined',
|
||||
isDeprecated: false,
|
||||
isHidden: false,
|
||||
isOptional: false,
|
||||
isSigned: false,
|
||||
isSubscription: false,
|
||||
method: 'foo',
|
||||
params: [{
|
||||
isOptional: false,
|
||||
name: 'bar',
|
||||
type: 'u32'
|
||||
}],
|
||||
pubsub: ['', '', ''],
|
||||
section: 'testing',
|
||||
type: 'Balance'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+118
-63
@@ -3,19 +3,22 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { ProviderInterface } from '@polkadot/rpc-provider/types';
|
||||
import { RpcMethod } from '@polkadot/jsonrpc/types';
|
||||
import { StorageChangeSet } from '@polkadot/types/interfaces';
|
||||
import { RpcMethod, RpcSection, RpcParam } from '@polkadot/jsonrpc/types';
|
||||
import { AnyJson, Codec } from '@polkadot/types/types';
|
||||
import { RpcInterface } from './jsonrpc.types';
|
||||
import { RpcInterfaceMethod } from './types';
|
||||
import { RpcInterfaceMethod, UserRpc } from './types';
|
||||
|
||||
import memoizee from 'memoizee';
|
||||
import { combineLatest, from, Observable, Observer, of, throwError } from 'rxjs';
|
||||
import { catchError, map, publishReplay, refCount, switchMap } from 'rxjs/operators';
|
||||
import interfaces from '@polkadot/jsonrpc';
|
||||
import { ClassOf, Option, StorageData, StorageKey, Vec, createClass } from '@polkadot/types';
|
||||
import { catchError, distinctUntilChanged, map, publishReplay, refCount, switchMap } from 'rxjs/operators';
|
||||
import jsonrpc from '@polkadot/jsonrpc';
|
||||
import jsonrpcMethod from '@polkadot/jsonrpc/create/method';
|
||||
import jsonrpcParam from '@polkadot/jsonrpc/create/param';
|
||||
import { Option, StorageKey, Vec, createClass } from '@polkadot/types';
|
||||
import { createTypeUnsafe } from '@polkadot/types/codec';
|
||||
import { assert, isFunction, isNull, isNumber, logger } from '@polkadot/util';
|
||||
import { assert, isFunction, isNull, isNumber, logger, u8aToU8a } from '@polkadot/util';
|
||||
|
||||
type UserRpcConverted = Record<string, Record<string, RpcMethod>>;
|
||||
|
||||
const l = logger('rpc-core');
|
||||
|
||||
@@ -52,42 +55,44 @@ const EMPTY_META = {
|
||||
* ```
|
||||
*/
|
||||
export default class Rpc implements RpcInterface {
|
||||
private _storageCache = new Map<string, Option<StorageData>>();
|
||||
private _storageCache = new Map<string, string | null>();
|
||||
|
||||
public readonly provider: ProviderInterface;
|
||||
|
||||
public readonly account: RpcInterface['account'];
|
||||
public readonly mapping: Map<string, RpcMethod> = new Map();
|
||||
|
||||
public readonly author: RpcInterface['author'];
|
||||
public readonly sections: string[] = [];
|
||||
|
||||
public readonly chain: RpcInterface['chain'];
|
||||
// Ok, this is quite horrible - we really should not be using the ! here, but we are actually assigning
|
||||
// these via the createInterfaces inside the constructor. However... this is not quite visible. The reason
|
||||
// why we don't do for individual assignments is to allow user-defined RPCs to also be defined
|
||||
|
||||
public readonly contracts: RpcInterface['contracts'];
|
||||
public readonly account!: RpcInterface['account'];
|
||||
|
||||
public readonly rpc: RpcInterface['rpc'];
|
||||
public readonly author!: RpcInterface['author'];
|
||||
|
||||
public readonly state: RpcInterface['state'];
|
||||
public readonly chain!: RpcInterface['chain'];
|
||||
|
||||
public readonly system: RpcInterface['system'];
|
||||
public readonly contracts!: RpcInterface['contracts'];
|
||||
|
||||
public readonly rpc!: RpcInterface['rpc'];
|
||||
|
||||
public readonly state!: RpcInterface['state'];
|
||||
|
||||
public readonly system!: RpcInterface['system'];
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* Default constructor for the Api Object
|
||||
* @param {ProviderInterface} provider An API provider using HTTP or WebSocket
|
||||
*/
|
||||
public constructor (provider: ProviderInterface) {
|
||||
public constructor (provider: ProviderInterface, userRpc: UserRpc = {}) {
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
assert(provider && isFunction(provider.send), 'Expected Provider to API create');
|
||||
|
||||
this.provider = provider;
|
||||
|
||||
this.account = this.createInterface('account');
|
||||
this.author = this.createInterface('author');
|
||||
this.contracts = this.createInterface('contracts');
|
||||
this.chain = this.createInterface('chain');
|
||||
this.rpc = this.createInterface('rpc');
|
||||
this.state = this.createInterface('state');
|
||||
this.system = this.createInterface('system');
|
||||
this.createInterfaces(jsonrpc, userRpc);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -106,9 +111,7 @@ export default class Rpc implements RpcInterface {
|
||||
* ```
|
||||
*/
|
||||
public static signature ({ method, params, type }: RpcMethod): string {
|
||||
const inputs = params.map(({ name, type }): string =>
|
||||
`${name}: ${type}`
|
||||
).join(', ');
|
||||
const inputs = params.map(({ name, type }): string => `${name}: ${type}`).join(', ');
|
||||
|
||||
return `${method} (${inputs}): ${type}`;
|
||||
}
|
||||
@@ -124,13 +127,47 @@ export default class Rpc implements RpcInterface {
|
||||
return `${Rpc.signature(method)}:: ${error.message}`;
|
||||
}
|
||||
|
||||
private createInterface<Section extends keyof RpcInterface> (section: Section): RpcInterface[Section] {
|
||||
const { methods } = interfaces[section];
|
||||
private createInterfaces<Section extends keyof RpcInterface> (interfaces: Record<string, RpcSection>, userBare: UserRpc): void {
|
||||
// these are the base keys (i.e. part of jsonrpc)
|
||||
this.sections.push(...Object.keys(interfaces));
|
||||
|
||||
// add any extra user-defined sections
|
||||
this.sections.push(...Object.keys(userBare).filter((key): boolean => !this.sections.includes(key)));
|
||||
|
||||
// convert the user inputs into the same format as used in jsonrpc
|
||||
const user = Object.entries(userBare).reduce((user: UserRpcConverted, [sectionName, methods]): UserRpcConverted => {
|
||||
user[sectionName] = methods.reduce((section: Record<string, RpcMethod>, def): Record<string, RpcMethod> => {
|
||||
const { description = 'User defined', name, params, type } = def;
|
||||
|
||||
section[name] = jsonrpcMethod(sectionName, name, {
|
||||
description,
|
||||
params: params.map(({ isOptional, name, type }): RpcParam =>
|
||||
jsonrpcParam(name, type as any, { isOptional })),
|
||||
type: type as any
|
||||
});
|
||||
|
||||
return section;
|
||||
}, {});
|
||||
|
||||
return user;
|
||||
}, {});
|
||||
|
||||
// decorate the sections with base and user methods
|
||||
this.sections.forEach((sectionName): void => {
|
||||
(this as any)[sectionName as Section] = {
|
||||
...this.createInterface(sectionName, interfaces[sectionName] ? interfaces[sectionName].methods : {}),
|
||||
...this.createInterface(sectionName, user[sectionName] || {})
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private createInterface<Section extends keyof RpcInterface> (section: string, methods: Record<string, RpcMethod>): RpcInterface[Section] {
|
||||
return Object
|
||||
.keys(methods)
|
||||
.reduce((exposed, methodName): RpcInterface[Section] => {
|
||||
const def = methods[methodName];
|
||||
.reduce((exposed, method): RpcInterface[Section] => {
|
||||
const def = methods[method];
|
||||
|
||||
this.mapping.set(`${section}_${method}`, def);
|
||||
|
||||
// FIXME Remove any here
|
||||
// To do so, remove `RpcInterfaceMethod` from './types.ts', and refactor
|
||||
@@ -138,7 +175,7 @@ export default class Rpc implements RpcInterface {
|
||||
// `<S extends keyof RpcInterface, M extends keyof RpcInterface[S]>`
|
||||
// Not doing so, because it makes this class a little bit less readable,
|
||||
// and leaving it as-is doesn't harm much
|
||||
(exposed as any)[methodName] = def.isSubscription
|
||||
(exposed as any)[method] = def.isSubscription
|
||||
? this.createMethodSubscribe(def)
|
||||
: this.createMethodSend(def);
|
||||
|
||||
@@ -171,14 +208,12 @@ export default class Rpc implements RpcInterface {
|
||||
const message = this.createErrorMessage(method, error);
|
||||
|
||||
// don't scare with old nodes, this is handled transparently
|
||||
if (rpcName !== 'rpc_methods') {
|
||||
l.error(message);
|
||||
}
|
||||
rpcName !== 'rpc_methods' && l.error(message);
|
||||
|
||||
return throwError(new Error(message));
|
||||
}),
|
||||
publishReplay(1), // create a Replay(1)
|
||||
refCount() // Unsubcribe WS when there are no more subscribers
|
||||
refCount() // Unsubscribe WS when there are no more subscribers
|
||||
);
|
||||
};
|
||||
|
||||
@@ -251,6 +286,10 @@ export default class Rpc implements RpcInterface {
|
||||
);
|
||||
};
|
||||
}).pipe(
|
||||
// Duplicated in api-derive/util/drr
|
||||
distinctUntilChanged((a: any, b: any): boolean =>
|
||||
JSON.stringify({ value: a }) === JSON.stringify({ value: b })
|
||||
),
|
||||
publishReplay(1),
|
||||
refCount()
|
||||
);
|
||||
@@ -282,31 +321,36 @@ export default class Rpc implements RpcInterface {
|
||||
);
|
||||
}
|
||||
|
||||
private formatOutput (method: RpcMethod, params: Codec[], result?: any): Codec | (Codec | null | undefined)[] {
|
||||
const base = createTypeUnsafe(method.type, [result]);
|
||||
private treatAsHex (key: StorageKey): boolean {
|
||||
// :code is problematic - it does not have the length attached, which is
|
||||
// unlike all other storage entries where it is indeed properly encoded
|
||||
return ['0x3a636f6465'].includes(key.toHex());
|
||||
}
|
||||
|
||||
private formatOutput (method: RpcMethod, params: Codec[], result?: any): Codec | Codec[] {
|
||||
if (method.type === 'StorageData') {
|
||||
const key = params[0] as StorageKey;
|
||||
|
||||
try {
|
||||
return this.formatStorageData(key, base, isNull(result));
|
||||
return this.formatStorageData(key, result);
|
||||
} catch (error) {
|
||||
console.error(`Unable to decode storage ${key.section}.${key.method}:`, error.message);
|
||||
|
||||
throw error;
|
||||
}
|
||||
} else if ((method.type as string) === 'StorageChangeSet') {
|
||||
} else if (method.type === 'StorageChangeSet') {
|
||||
// For StorageChangeSet, the changes has the [key, value] mappings
|
||||
const changes: [string, string | null][] = result.changes;
|
||||
const keys = params[0] as Vec<StorageKey>;
|
||||
const withCache = keys.length !== 1;
|
||||
|
||||
// multiple return values (via state.storage subscription), decode the values
|
||||
// one at a time, all based on the query types. Three values can be returned -
|
||||
// - Base - There is a valid value, non-empty
|
||||
// - null - The storage key is empty (but in the resultset)
|
||||
// - undefined - The storage value is not in the resultset
|
||||
return keys.reduce((results, key: StorageKey): (Codec | undefined)[] => {
|
||||
// - Codec - There is a valid value, non-empty
|
||||
// - null - The storage key is empty
|
||||
return keys.reduce((results, key: StorageKey): Codec[] => {
|
||||
try {
|
||||
results.push(this.formatStorageSet(key, base as StorageChangeSet, withCache));
|
||||
results.push(this.formatStorageSet(key, changes, withCache));
|
||||
} catch (error) {
|
||||
console.error(`Unable to decode storage ${key.section}.${key.method}:`, error.message);
|
||||
|
||||
@@ -314,66 +358,77 @@ export default class Rpc implements RpcInterface {
|
||||
}
|
||||
|
||||
return results;
|
||||
}, [] as (Codec | undefined)[]);
|
||||
}, [] as Codec[]);
|
||||
}
|
||||
|
||||
return base;
|
||||
return createTypeUnsafe(method.type, [result]);
|
||||
}
|
||||
|
||||
private formatStorageData (key: StorageKey, base: Codec, isNull: boolean): Codec {
|
||||
private formatStorageData (key: StorageKey, value: string | null): Codec {
|
||||
// single return value (via state.getStorage), decode the value based on the
|
||||
// outputType that we have specified. Fallback to Data on nothing
|
||||
const type = key.outputType || 'Data';
|
||||
const meta = key.meta || EMPTY_META;
|
||||
const isEmpty = isNull(value);
|
||||
|
||||
// we convert to Uint8Array since it maps to the raw encoding, all
|
||||
// data will be correctly encoded (incl. numbers, excl. :code)
|
||||
const input = isEmpty
|
||||
? null
|
||||
: this.treatAsHex(key)
|
||||
? value
|
||||
: u8aToU8a(value);
|
||||
|
||||
if (meta.modifier.isOptional) {
|
||||
return new Option(
|
||||
createClass(type),
|
||||
isNull
|
||||
isEmpty
|
||||
? null
|
||||
: createTypeUnsafe(type, [base], true)
|
||||
: createTypeUnsafe(type, [input], true)
|
||||
);
|
||||
}
|
||||
|
||||
return createTypeUnsafe(type, [isNull ? meta.fallback : base], true);
|
||||
return createTypeUnsafe(type, [isEmpty ? meta.fallback : input], true);
|
||||
}
|
||||
|
||||
private formatStorageSet (key: StorageKey, base: StorageChangeSet, witCache: boolean): Codec {
|
||||
private formatStorageSet (key: StorageKey, changes: [string, string | null][], witCache: boolean): Codec {
|
||||
// Fallback to Data (i.e. just the encoding) if we don't have a specific type
|
||||
const type = key.outputType || 'Data';
|
||||
const hexKey = key.toHex();
|
||||
const meta = key.meta || EMPTY_META;
|
||||
|
||||
// if we don't find the value, this is out fallback
|
||||
// if we don't find the value, this is our fallback
|
||||
// - in the case of an array of values, fill the hole from the cache
|
||||
// - if a single result value, don't fill - it is not an update hole
|
||||
// - fallback to an empty option in all cases
|
||||
const emptyVal = (
|
||||
witCache
|
||||
? this._storageCache.get(hexKey)
|
||||
: null
|
||||
) || new Option<StorageData>(ClassOf('StorageData'), null);
|
||||
const emptyVal = (witCache && this._storageCache.get(hexKey)) || null;
|
||||
|
||||
// see if we have a result value for this specific key, fallback to the cache value
|
||||
// when the value in the set is not available, or is null/empty.
|
||||
const [, value] = base.changes.find(([key, value]): boolean =>
|
||||
value.isSome && key.toHex() === hexKey
|
||||
const [, value] = changes.find(([key, value]): boolean =>
|
||||
!isNull(value) && key === hexKey
|
||||
) || [null, emptyVal];
|
||||
const isEmpty = isNull(value);
|
||||
const input = isEmpty
|
||||
? null
|
||||
: this.treatAsHex(key)
|
||||
? value
|
||||
: u8aToU8a(value);
|
||||
|
||||
// store the retrieved result - the only issue with this cache is that there is no
|
||||
// clearning of it, so very long running processes (not just a couple of hours, longer)
|
||||
// clearing of it, so very long running processes (not just a couple of hours, longer)
|
||||
// will increase memory beyond what is allowed.
|
||||
this._storageCache.set(hexKey, value);
|
||||
|
||||
if (meta.modifier.isOptional) {
|
||||
return new Option(
|
||||
createClass(type),
|
||||
value.isNone
|
||||
isEmpty
|
||||
? null
|
||||
: createTypeUnsafe(type, [value.unwrap()], true)
|
||||
: createTypeUnsafe(type, [input], true)
|
||||
);
|
||||
}
|
||||
|
||||
return createTypeUnsafe(type, [value.unwrapOr(meta.fallback)], true);
|
||||
return createTypeUnsafe(type, [isEmpty ? meta.fallback : input], true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,3 +7,12 @@ import { Observable } from 'rxjs';
|
||||
export interface RpcInterfaceMethod {
|
||||
(...params: any[]): Observable<any>;
|
||||
}
|
||||
|
||||
export interface UserRpcMethod {
|
||||
description?: string;
|
||||
name: string;
|
||||
params: { isOptional?: boolean; name: string; type: string }[];
|
||||
type: string;
|
||||
}
|
||||
|
||||
export type UserRpc = Record<string, UserRpcMethod[]>;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@polkadot/rpc-provider",
|
||||
"version": "0.93.1",
|
||||
"version": "0.95.2",
|
||||
"description": "Transport providers for the API",
|
||||
"main": "index.js",
|
||||
"keywords": [
|
||||
@@ -26,18 +26,18 @@
|
||||
},
|
||||
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/rpc-provider#readme",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.6.2",
|
||||
"@polkadot/api-metadata": "^0.93.1",
|
||||
"@polkadot/util": "^1.5.1",
|
||||
"@polkadot/util-crypto": "^1.5.1",
|
||||
"@babel/runtime": "^7.6.3",
|
||||
"@polkadot/api-metadata": "^0.95.2",
|
||||
"@polkadot/util": "^1.6.1",
|
||||
"@polkadot/util-crypto": "^1.6.1",
|
||||
"@types/nock": "^11.1.0",
|
||||
"eventemitter3": "^4.0.0",
|
||||
"isomorphic-fetch": "^2.2.1",
|
||||
"websocket": "^1.0.30"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@polkadot/keyring": "^1.5.1",
|
||||
"mock-socket": "^9.0.0",
|
||||
"nock": "^11.3.5"
|
||||
"@polkadot/keyring": "^1.6.1",
|
||||
"mock-socket": "^9.0.2",
|
||||
"nock": "^11.4.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
import { JsonRpcRequest, JsonRpcResponse, JsonRpcResponseBaseError } from '../types';
|
||||
|
||||
import { assert, isUndefined, isNumber } from '@polkadot/util';
|
||||
import { assert, isUndefined, isNumber, isString } from '@polkadot/util';
|
||||
|
||||
export default class RpcCoder {
|
||||
private id = 0;
|
||||
@@ -54,7 +54,7 @@ export default class RpcCoder {
|
||||
const { code, data, message } = error;
|
||||
const _data = isUndefined(data)
|
||||
? ''
|
||||
: ' (' + `${data}`.substr(0, 10) + ')';
|
||||
: `: ${isString(data) ? data : JSON.stringify(data)}`.substr(0, 22);
|
||||
|
||||
throw new Error(`${code}: ${message}${_data}`);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@polkadot/jsonrpc",
|
||||
"version": "0.93.1",
|
||||
"version": "0.95.2",
|
||||
"description": "Method definitions for the Polkadot RPC layer",
|
||||
"main": "index.js",
|
||||
"publishConfig": {
|
||||
@@ -26,6 +26,6 @@
|
||||
},
|
||||
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/type-jsonrpc#readme",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.6.2"
|
||||
"@babel/runtime": "^7.6.3"
|
||||
}
|
||||
}
|
||||
|
||||
+14
-151
@@ -10,15 +10,12 @@ These are the base types of the codec. They are typically not used directly, but
|
||||
|
||||
| **Types** | |
|
||||
| --- | --- |
|
||||
| [[AbstractArray]] | Manages codec arrays. It is an extension to Array |
|
||||
| [[Base]] | A type extends the Base class, when it holds a value |
|
||||
| [[Compact]] | A compact length-encoding codec wrapper. Mostly used by other types to add length-prefixed encoding |
|
||||
| [[Enum]] | A codec wrapper for an enum. Enums are encoded as a single byte, where the byte is a zero-indexed value |
|
||||
| [[Int]] | A generic signed integer codec |
|
||||
| [[Option]] | An Option is an optional field. The first byte indicates that there is is value to follow |
|
||||
| [[Set]] | An Set is an array of string values, represented an an encoded type by a bitwise representation of the values |
|
||||
| [[Struct]] | A Struct defines an Object with key-value pairs - where the values are Codec values. |
|
||||
| [[StructAny]] | Wraps the a JSON structure retrieve via RPC. It extends the standard JS Map |
|
||||
| [[Tuple]] | A Tuple defines an anonymous fixed-length array, where each element has its own type |
|
||||
| [[U8a]] | A basic wrapper around Uint8Array. It will consume the full Uint8Array as passed to it |
|
||||
| [[U8aFixed]] | A U8a that manages a a sequence of bytes up to the specified bitLength |
|
||||
@@ -35,9 +32,8 @@ These primitive types are available:
|
||||
| --- | --- |
|
||||
| [[AccountId]] | A wrapper around an AccountId/PublicKey representation |
|
||||
| [[AccountIndex]] | A wrapper around an AccountIndex, which is a shortened, variable-length encoding for an Account |
|
||||
| [[AccountInfo]] | An Account information structure for contracts |
|
||||
| [[Address]] | A wrapper around an AccountId and/or AccountIndex that is encoded with a prefix |
|
||||
| [[Bool]] | Representation for a boolean value in the system |
|
||||
| [[bool]] | Representation for a boolean value in the system |
|
||||
| [[Bytes]] | A Bytes wrapper for `Vec<u8>` |
|
||||
| [[Call]] | Extrinsic function descriptor, as defined in [the extrinsic format for a node](https://github.com/paritytech/wiki/blob/master/Extrinsic.md#the-extrinsic-format-for-node) |
|
||||
| [[Data]] | A raw data structure. It is an encoding of a U8a without any length encoding |
|
||||
@@ -45,160 +41,27 @@ These primitive types are available:
|
||||
| [[EventRecord]] | A record for an [[Event]] (as specified by [[Metadata]]) with the specific [[Phase]] of application |
|
||||
| [[Extrinsic]] | Representation of an Extrinsic in the system |
|
||||
| [[ExtrinsicEra]] | The era for an extrinsic, indicating either a mortal or immortal extrinsic |
|
||||
| [[ExtrinsicSignature]] | A container for the [[Signature]] associated with a specific [[Extrinsic]] |
|
||||
| [[ExtrinsicPayload]] | A signing payload for an [[Extrinsic]]. For the final encoding, it is variable length based on the contents included |
|
||||
| [[H160]] | Hash containing 160 bits (20 bytes), typically used in blocks, extrinsics and as a sane default |
|
||||
| [[H256]] | Hash containing 256 bits (32 bytes), typically used in blocks, extrinsics and as a sane default |
|
||||
| [[H512]] | Hash containing 512 bits (64 bytes), typically used for signatures |
|
||||
| [[Hash]] | The default hash that is used accross the system. It is just a thin wrapper around [[H256]]
|
||||
| [[I8]] | An 8-bit signed integer |
|
||||
| [[I16]] | A 16-bit signed integer |
|
||||
| [[I32]] | A 32-bit signed integer |
|
||||
| [[I64]] | A 64-bit signed integer |
|
||||
| [[I128]] | A 128-bit signed integer |
|
||||
| [[I256]] | A 256-bit signed integer |
|
||||
| [[i8]] | An 8-bit signed integer |
|
||||
| [[i16]] | A 16-bit signed integer |
|
||||
| [[i32]] | A 32-bit signed integer |
|
||||
| [[i64]] | A 64-bit signed integer |
|
||||
| [[i128]] | A 128-bit signed integer |
|
||||
| [[i256]] | A 256-bit signed integer |
|
||||
| [[Moment]] | A wrapper around seconds/timestamps. Internally the representation only has second precicion (aligning with Rust) |
|
||||
| [[Null]] | Implements a type that does not contain anything (apart from `null`) |
|
||||
| [[Origin]] | Where Origin occurs, it should be ignored as an internal-only value |
|
||||
| [[Signature]] | The default signature that is used accross the system |
|
||||
| [[ExtrinsicPayload]] | A signing payload for an [[Extrinsic]]. For the final encoding, it is variable length based on the contents included |
|
||||
| [[StorageData]] | Data retrieved via Storage queries and data for key-value pairs |
|
||||
| [[StorageKey]] | A representation of a storage key (typically hashed) in the system |
|
||||
| [[Text]] | This is a string wrapper, along with the length. |
|
||||
| [[Type]] | This is a extended version of String, specifically to handle types |
|
||||
| [[U8]] | An 8-bit unsigned integer |
|
||||
| [[U16]] | A 16-bit unsigned integer |
|
||||
| [[U32]] | A 32-bit unsigned integer |
|
||||
| [[U64]] | A 64-bit unsigned integer |
|
||||
| [[U128]] | A 128-bit unsigned integer |
|
||||
| [[U256]] | A 256-bit unsigned integer |
|
||||
| [[USize]] | A System default unsigned number, typically used in RPC to report non-consensus data |
|
||||
| [[Weight]] | Numeric range of a transaction weight. |
|
||||
| [[WeightMultiplier]] | Representation of a weight multiplier. This represents how a fee value can be computed from a weighted transaction. |
|
||||
|
||||
|
||||
## Substrate types
|
||||
|
||||
These custom types implement specific types that are found as part of the Substrate core. They're all extensions of one of the codec types:
|
||||
|
||||
| **Types** | |
|
||||
| --- | --- |
|
||||
| [[Amount]] | The Substrate Amount representation as a [[Balance]] |
|
||||
| [[ApprovalFlag]] | Approval flag, implemented as a [[U32]] |
|
||||
| [[AssetOf]] | The Substrate AssetOf representation as a [[Balance]] |
|
||||
| [[AuthorityId]] | Wrapper for a AuthorityId. Same as an normal AccountId |
|
||||
| [[AuthoritiesChange]] | Log for Authories changed |
|
||||
| [[AuthorityWeight]] | The weight of an authority |
|
||||
| [[Balance]] | The Substrate Balance representation as a [[U128]] |
|
||||
| [[BalanceLock]] | The Substrate BalanceLock for staking |
|
||||
| [[BalanceOf]] | The Substrate BalanceOf representation as a [[Balance]] |
|
||||
| [[BlockNumber]] | A representation of a Substrate BlockNumber, implemented as a [[U64]] |
|
||||
| [[CodeHash]] | The default contract code hash that is used accross the system |
|
||||
| [[Conviction]] | A value denoting the strength of conviction of a vote. |
|
||||
| [[Consensus]] | Log item indicating consensus |
|
||||
| [[ContractInfo]] | The contract information for a given contract |
|
||||
| [[ContractStorageKey]] | A representation of a storage key for contracts |
|
||||
| [[EraIndex]] | A representation for the era count |
|
||||
| [[Exposure]] | A snapshot of the stake backing a single validator in the system |
|
||||
| [[Gas]] | A gas number type for Substrate, extending [[U64]] |
|
||||
| [[Heartbeat]] | Heartbeat which is send/received. |
|
||||
| [[IndividualExposure]] | The Substrate IndividualExposure for staking |
|
||||
| [[InherentOfflineReport]] | Describes the offline-reporting extrinsic |
|
||||
| [[Justification]] | A generic justification as a stream of [[Bytes]], this is specific per consensus implementation |
|
||||
| [[Key]] | The Substrate Key representation as a [[Bytes]] (`vec<u8>`) |
|
||||
| [[Keys]] | The session keys for both Grandpa (ed25519) and Babe (sr25519) |
|
||||
| [[KeyValue]] | KeyValue structure. Since most of the keys and resultant values in Subtrate are hashed and/or encoded, keys and values are reprsented as [[Bytes]] |
|
||||
| [[KeyValueOption]] | A key/value change. Similar to the [[KeyValue]] structure, but the value can be optional |
|
||||
| [[LockIdentifier]] | The Substrate LockIdentifier for staking |
|
||||
| [[LockPeriods]] | A number of lock periods |
|
||||
| [[MemberCount]] | A number of council members |
|
||||
| [[MisbehaviorKind]] | An [[EnumType]] containing a Bft misbehaviour |
|
||||
| [[MisbehaviorReport]] | A Misbehaviour report of [[MisbehavioirKind]] against a specific [[AuthorityId]] |
|
||||
| [[NewAccountOutcome]] | Enum to track the outcome for creation of an [[AccountId]] |
|
||||
| [[NextAuthority]] | The next authority available as [[SessionKey]] |
|
||||
| [[Nonce]] | The Nonce or number of transactions sent by a specific account |
|
||||
| [[NonceCompact]] | The Compact<Nonce> or number of transactions sent by a specific account |
|
||||
| [[OpaqueKey]] | A key represented as a [[Bytes]] |
|
||||
| [[Perbill]] | Parts per billion (see also [[Permill]]) |
|
||||
| [[Permill]] | Parts per million (See also [[Perbill]]) |
|
||||
| [[PrefabWasmModule]] | Struct to encode the vesting schedule of an individual account |
|
||||
| [[PropIndex]] | An increasing number that represents a specific council proposal index in the system |
|
||||
| [[Proposal]] | A proposal in the system. It just extends [[Call]] (Proposal = Call in Rust) |
|
||||
| [[ProposalIndex]] | An increasing number that represents a specific council proposal index in the system |
|
||||
| [[ReferendumIndex]] | An increasing number that represents a specific referendum in the system |
|
||||
| [[ReferendumInfo]] | Info regarding an ongoing referendum |
|
||||
| [[RewardDestination]] | A destination account for payment |
|
||||
| [[Schedule]] | Definition of the cost schedule and other parameterizations for wasm vm |
|
||||
| [[Seal]] | Log item indicating a sealing event |
|
||||
| [[SeedOf]] | The Substrate SeedOf representation as a [[Hash]] |
|
||||
| [[SessionIndex]] | Simple index type with which we can count sessions as [[U32]] |
|
||||
| [[SessionKey]] | Wrapper for a SessionKey. Same as an normal [[AuthorityId]], i.e. a wrapper around publicKey |
|
||||
| [[SetIndex]] | Set index, implemented as a [[U32]] |
|
||||
| [[StakingLedger]] | The ledger of a (bonded) stash |
|
||||
| [[StoredPendingChange]] | Stored pending change for a Grandpa events |
|
||||
| [[StoredState]] | Current state of the GRANDPA authority set. State transitions must happen in the same order of states defined below, e.g. `Paused` implies a prior `PendingPause` |
|
||||
| [[TreasuryProposal]] | A Proposal made for Treasury |
|
||||
| [[UncleEntryItem]] | Information about an uncle to include |
|
||||
| [[UnlockChunk]] | Just a Balance/BlockNumber tuple to encode when a chunk of funds will be unlocked |
|
||||
| [[ValidatorId]] | Validator in the system, maps to an AccountId |
|
||||
| [[ValidatorPrefs]] | Validator preferences |
|
||||
| [[VestingSchedule]] | Struct to encode the vesting schedule of an individual account |
|
||||
| [[Vote]] | A number of lock periods, plus a vote, one way or the other |
|
||||
| [[Votes]] | Info for keeping track of a council motion being voted on. |
|
||||
| [[VoteIndex]] | Voting index, implemented as a [[U32]] |
|
||||
| [[VoterInfo]] | The activity status of a voter. |
|
||||
| [[VoteThreshold]] | Voting threshold, used inside proposals to set change the voting tally |
|
||||
| [[WithdrawReasons]] | The Substrate WithdrawReasons for staking |
|
||||
|
||||
|
||||
## Polkadot types
|
||||
|
||||
These types are only available in Polkadot chains -
|
||||
|
||||
| **Types** | |
|
||||
| --- | --- |
|
||||
| [[AuctionIndex]] | A parachain auction index as a [[U32]] |
|
||||
| [[AttestedCandidate]] | An attested candidate |
|
||||
| [[Bidder]] | The desired target of a bidder in an auction. |
|
||||
| [[LeasePeriod]] | The length of the lease for a parachain |
|
||||
| [[LeasePeriodOf]] | The length of the lease for a parachain |
|
||||
| [[IncomingParachain]] | Information regarding a parachain that will be deployed. |
|
||||
| [[NewBidder]] | A bidder identifier, which is just the combination of an account ID and a sub-bidder ID. This is called `NewBidder` in order to distinguish between bidders that would deploy a *new* parachain and pre-existing parachains bidding to renew themselves. |
|
||||
| [[ParachainDispatchOrigin]] | Which origin a parachain's message to the relay chain should be dispatched from. |
|
||||
| [[ParaId]] | Identifier for a deployed parachain implemented as a [[U32]] |
|
||||
| [[ParaIdOf]] | Identifier for a deployed parachain implemented as a [[U32]] |
|
||||
| [[SlotRange]] | A compactly represented sub-range from the series (0, 1, 2, 3) |
|
||||
| [[SubId]] | A sub-bidder identifier. Used to distinguish between different logical bidders coming from the same account ID. |
|
||||
| [[UpwardMessage]] | A message from a parachain to its Relay Chain |
|
||||
| [[WinningData]] | Winning data type. This encodes the top bidders of each range together with their bid. |
|
||||
| [[WinningDataEntry]] | And entry in the [[WinningData]] fixed vector |
|
||||
|
||||
|
||||
## RPC types
|
||||
|
||||
These types are not used in the runtime, but are rather used in RPC results:
|
||||
|
||||
| **Types** | |
|
||||
| --- | --- |
|
||||
| [[Block]] | A block encoded with header and extrinsics |
|
||||
| [[ChainProperties]] | Wraps the properties retrieved from the chain via the `system.properties` RPC call |
|
||||
| [[Digest]] | A [[Header]] Digest |
|
||||
| [[DigestOf]] | A [[Header]] Digest |
|
||||
| [[DigestItem]] | A [[EnumType]] the specifies the specific item in the logs of a [[Digest]] |
|
||||
| [[ExtrinsicStatus]] | An EnumType that indicates the status of the Extrinsic as been submitted |
|
||||
| [[Header]] | A [[Block]] header |
|
||||
| [[Health]] | A system health indicator, reported back over RPC |
|
||||
| [[NetworkState]] | Wraps the properties retrieved from the chain via the `system.network_state` RPC call |
|
||||
| [[Metadata]] | The versioned runtime metadata as a decoded structure |
|
||||
| [[PeerInfo]] | A system peer info indicator, reported back over RPC |
|
||||
| [[RuntimeVersion]] | A [[Tuple]] that conatins the [[ApiId]] and [[U32]] version |
|
||||
| [[SignedBlock]] | A [[Block]] that has been signed and contains a [[Justification]] |
|
||||
| [[StorageChangeSet]] | A set of storage changes. It contains the [[Block]] hash and a list of the actual changes |
|
||||
|
||||
|
||||
## Derive types
|
||||
|
||||
These types are are specific for the Polkadot-JS derive API, so you won't find a representation of them in the SCALE codec or the Substrate core. They are used in the [api-derive](https://www.npmjs.com/package/@polkadot/api-derive) methods.
|
||||
|
||||
| **Types** | |
|
||||
| --- | --- |
|
||||
| [[HeaderExtended]] | A [[Header]] header with an additional `author` field that indicates the block author] |
|
||||
| [[u8]] | An 8-bit unsigned integer |
|
||||
| [[u16]] | A 16-bit unsigned integer |
|
||||
| [[u32]] | A 32-bit unsigned integer |
|
||||
| [[u64]] | A 64-bit unsigned integer |
|
||||
| [[u128]] | A 128-bit unsigned integer |
|
||||
| [[u256]] | A 256-bit unsigned integer |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@polkadot/types",
|
||||
"version": "0.93.1",
|
||||
"version": "0.95.2",
|
||||
"description": "Implementation of the Parity codec",
|
||||
"main": "index.js",
|
||||
"keywords": [
|
||||
@@ -26,13 +26,13 @@
|
||||
},
|
||||
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/types#readme",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.6.2",
|
||||
"@polkadot/util": "^1.5.1",
|
||||
"@polkadot/util-crypto": "^1.5.1",
|
||||
"@babel/runtime": "^7.6.3",
|
||||
"@polkadot/util": "^1.6.1",
|
||||
"@polkadot/util-crypto": "^1.6.1",
|
||||
"@types/memoizee": "^0.4.3",
|
||||
"memoizee": "^0.4.14"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@polkadot/keyring": "^1.5.1"
|
||||
"@polkadot/keyring": "^1.6.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import MetadataV4 from './v4';
|
||||
import MetadataV5 from './v5';
|
||||
import MetadataV6 from './v6';
|
||||
import MetadataV7 from './v7';
|
||||
import MetadataV8 from './v8';
|
||||
import v0ToV1 from './v0/toV1';
|
||||
import v1ToV2 from './v1/toV2';
|
||||
import v2ToV3 from './v2/toV3';
|
||||
@@ -22,11 +23,12 @@ import v3ToV4 from './v3/toV4';
|
||||
import v4ToV5 from './v4/toV5';
|
||||
import v5ToV6 from './v5/toV6';
|
||||
import v6ToV7 from './v6/toV7';
|
||||
import v7ToV8 from './v7/toV8';
|
||||
import { getUniqTypes, toCallsOnly } from './util';
|
||||
|
||||
type MetaMapped = MetadataV0 | MetadataV1 | MetadataV2 | MetadataV3 | MetadataV4 | MetadataV5 | MetadataV6 | MetadataV7;
|
||||
type MetaVersions = 1 | 2 | 3 | 4 | 5 | 6 | 7;
|
||||
type MetaAsX = 'asV0' | 'asV1' | 'asV2' | 'asV3' | 'asV4' | 'asV5' | 'asV6';
|
||||
type MetaVersions = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
|
||||
type MetaAsX = 'asV0' | 'asV1' | 'asV2' | 'asV3' | 'asV4' | 'asV5' | 'asV6' | 'asV7';
|
||||
|
||||
class MetadataEnum extends Enum {
|
||||
public constructor (value?: any, index?: number) {
|
||||
@@ -38,7 +40,8 @@ class MetadataEnum extends Enum {
|
||||
V4: MetadataV4, // once rolled-out, can replace this with MetadataDeprecated
|
||||
V5: MetadataV5, // once rolled-out, can replace this with MetadataDeprecated
|
||||
V6: MetadataV6, // once rolled-out, can replace this with MetadataDeprecated
|
||||
V7: MetadataV7
|
||||
V7: MetadataV7, // once rolled-out, can replace this with MetadataDeprecated
|
||||
V8: MetadataV8
|
||||
}, value, index);
|
||||
}
|
||||
|
||||
@@ -114,6 +117,15 @@ class MetadataEnum extends Enum {
|
||||
return this.value as MetadataV7;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Returns the wrapped values as a V8 object
|
||||
*/
|
||||
public get asV8 (): MetadataV8 {
|
||||
assert(this.isV8, `Cannot convert '${this.type}' via asV8`);
|
||||
|
||||
return this.value as MetadataV8;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description `true` if Deprecated
|
||||
*/
|
||||
@@ -176,6 +188,13 @@ class MetadataEnum extends Enum {
|
||||
public get isV7 (): boolean {
|
||||
return this.type === 'V7';
|
||||
}
|
||||
|
||||
/**
|
||||
* @description `true` if V8
|
||||
*/
|
||||
public get isV8 (): boolean {
|
||||
return this.type === 'V8';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -215,24 +234,13 @@ export default class MetadataVersioned extends Struct {
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
* @description Returns the wrapped metadata as a limited calls-only (latest) version
|
||||
*/
|
||||
public get magicNumber (): MagicNumber {
|
||||
return this.get('magicNumber') as MagicNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description the metadata wrapped
|
||||
*/
|
||||
private get metadata (): MetadataEnum {
|
||||
return this.get('metadata') as MetadataEnum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description the metadata version this structure represents
|
||||
*/
|
||||
public get version (): number {
|
||||
return this.metadata.index;
|
||||
public get asCallsOnly (): MetadataVersioned {
|
||||
return new MetadataVersioned({
|
||||
magicNumber: this.magicNumber,
|
||||
metadata: new MetadataEnum(toCallsOnly(this.asLatest), this.version)
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -294,20 +302,38 @@ export default class MetadataVersioned extends Struct {
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Returns the wrapped metadata as a limited calls-only (latest) version
|
||||
* @description Returns the wrapped values as a V8 object
|
||||
*/
|
||||
public get asCallsOnly (): MetadataVersioned {
|
||||
return new MetadataVersioned({
|
||||
magicNumber: this.magicNumber,
|
||||
metadata: new MetadataEnum(toCallsOnly(this.asLatest), this.version)
|
||||
});
|
||||
public get asV8 (): MetadataV8 {
|
||||
return this.getVersion(8, v7ToV8);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Returns the wrapped values as a latest version object
|
||||
*/
|
||||
public get asLatest (): MetadataV7 {
|
||||
return this.asV7;
|
||||
public get asLatest (): MetadataV8 {
|
||||
return this.asV8;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
*/
|
||||
public get magicNumber (): MagicNumber {
|
||||
return this.get('magicNumber') as MagicNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description the metadata wrapped
|
||||
*/
|
||||
private get metadata (): MetadataEnum {
|
||||
return this.get('metadata') as MetadataEnum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description the metadata version this structure represents
|
||||
*/
|
||||
public get version (): number {
|
||||
return this.metadata.index;
|
||||
}
|
||||
|
||||
public getUniqTypes (throwError: boolean): string[] {
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import metadata from './v7/static';
|
||||
import metadata from './v8/static';
|
||||
|
||||
export default metadata;
|
||||
|
||||
@@ -32,7 +32,7 @@ type Item = {
|
||||
type Storage = Option<Vec<Item> | {
|
||||
// v0
|
||||
functions?: Vec<Item>;
|
||||
// V7
|
||||
// V7+
|
||||
items?: Vec<Item>;
|
||||
} & Codec>;
|
||||
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
|
||||
import '../../injector';
|
||||
|
||||
import extrinsicsFromMeta from '@polkadot/api-metadata/extrinsics/fromMetadata';
|
||||
|
||||
import { createTypeUnsafe } from '../../codec/create';
|
||||
import Metadata from '../Metadata';
|
||||
import Call from '../../primitive/Generic/Call';
|
||||
@@ -34,18 +32,18 @@ export function decodeLatestSubstrate<Modules extends Codec> (
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a `version`, MetadataV7 and MetadataV{version} should output the same
|
||||
* Given a `version`, MetadataLatest and MetadataV{version} should output the same
|
||||
* unique types.
|
||||
*/
|
||||
export function toV7<Modules extends Codec> (version: number, rpcData: string): void {
|
||||
it(`converts v${version} to v7`, (): void => {
|
||||
export function toLatest<Modules extends Codec> (version: number, rpcData: string): void {
|
||||
it(`converts v${version} to v8`, (): void => {
|
||||
const metadata = new Metadata(rpcData)[`asV${version}` as keyof Metadata];
|
||||
const metadataV7 = new Metadata(rpcData).asV7;
|
||||
const metadataV8 = new Metadata(rpcData).asLatest;
|
||||
|
||||
expect(
|
||||
getUniqTypes(metadata as unknown as MetadataInterface<Modules>, true)
|
||||
).toEqual(
|
||||
getUniqTypes(metadataV7, true)
|
||||
getUniqTypes(metadataV8, true)
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -57,7 +55,7 @@ export function defaultValues (rpcData: string): void {
|
||||
describe('storage with default values', (): void => {
|
||||
const metadata = new Metadata(rpcData);
|
||||
|
||||
Call.injectMethods(extrinsicsFromMeta(metadata));
|
||||
Call.injectMetadata(metadata);
|
||||
|
||||
metadata.asLatest.modules
|
||||
.filter(({ storage }): boolean => storage.isSome)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user